diff options
-rw-r--r-- | 2d23d.html | 4 | ||||
-rw-r--r-- | 2d23dcustom.html | 4 | ||||
-rw-r--r-- | 2pi.html | 4 | ||||
-rw-r--r-- | 404.html | 5 | ||||
-rw-r--r-- | AutoAudio.html | 2 | ||||
-rw-r--r-- | AutoHarmonograph.html | 4 | ||||
-rw-r--r-- | AutoImages.html | 2 | ||||
-rw-r--r-- | AutoVideos.html | 4 | ||||
-rw-r--r-- | Harmonograph.html | 4 | ||||
-rw-r--r-- | NameGenerator.html | 2 | ||||
-rw-r--r-- | all.html | 2 | ||||
-rw-r--r-- | ant.html | 4 | ||||
-rw-r--r-- | apps.html | 2 | ||||
-rw-r--r-- | ballbounce.html | 4 | ||||
-rw-r--r-- | clock.html | 6 | ||||
-rw-r--r-- | css/bootstrap.min.css | 6 | ||||
-rw-r--r-- | explanation.html | 2 | ||||
-rw-r--r-- | games.html | 2 | ||||
-rw-r--r-- | index.html | 2 | ||||
-rw-r--r-- | js/p5.js | 29765 | ||||
-rw-r--r-- | js/processing.js | 21748 | ||||
-rw-r--r-- | magnets.html | 4 | ||||
-rw-r--r-- | magnets_old_version.html | 4 | ||||
-rw-r--r-- | mandelbrot.html | 2 | ||||
-rw-r--r-- | mandelbrot_explanation.html | 2 | ||||
-rw-r--r-- | mathematical.html | 2 | ||||
-rw-r--r-- | modularcircles.html | 4 | ||||
-rw-r--r-- | modularpascal.html | 4 | ||||
-rw-r--r-- | shaperoller.html | 4 | ||||
-rw-r--r-- | tree.html | 4 | ||||
-rw-r--r-- | treegenerator.html | 4 |
31 files changed, 49 insertions, 51563 deletions
@@ -1,7 +1,7 @@ <html> <head> <title>2D becomes 3D</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -9,7 +9,7 @@ <div id="header_links_div"></div> <script src="js/header_links.js"></script> <hr> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/2d23d.js"></script> </body> </html>
\ No newline at end of file diff --git a/2d23dcustom.html b/2d23dcustom.html index 341f472..38c78c2 100644 --- a/2d23dcustom.html +++ b/2d23dcustom.html @@ -1,7 +1,7 @@ <html> <head> <title>2D becomes 3D</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -12,7 +12,7 @@ <p>Draw a pattern by dragging your mouse around. Press enter when you're done.<br> To draw a straight line, click the starting location, press the shift key, and click the ending location.</p> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/2d23dcustom.js"></script> </body> </html>
\ No newline at end of file @@ -4,9 +4,9 @@ <meta charset="utf-8"> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> </head> <body> diff --git a/404.html b/404.html new file mode 100644 index 0000000..cd45151 --- /dev/null +++ b/404.html @@ -0,0 +1,5 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; url=https://pommicket.github.io/"> +</head> +</html> diff --git a/AutoAudio.html b/AutoAudio.html index bffb2da..2f0a1f0 100644 --- a/AutoAudio.html +++ b/AutoAudio.html @@ -3,7 +3,7 @@ <head>
<script src="js/latexit.js"></script>
-<link rel="stylesheet" href="css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<link rel="shortcut icon" type="image/png" href="favicon.png">
<title>AutoAudio</title>
diff --git a/AutoHarmonograph.html b/AutoHarmonograph.html index bebf100..cdd3fa6 100644 --- a/AutoHarmonograph.html +++ b/AutoHarmonograph.html @@ -1,7 +1,7 @@ <html> <head> <title>AutoHarmonograph</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -14,7 +14,7 @@ Number of pendulums: <input type="number" id="npendulums"><br> Maximum damping: <input type="number" id="DMAX"><br> <button onclick="start();">Start</button><br> <button onclick="saveCanvas();">Save image</button><br> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/AutoHarmonograph.js"></script> </body> </html>
\ No newline at end of file diff --git a/AutoImages.html b/AutoImages.html index dfc6325..266eb04 100644 --- a/AutoImages.html +++ b/AutoImages.html @@ -2,7 +2,7 @@ <head>
<script src="js/latexit.js"></script>
-<link rel="stylesheet" href="css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<link rel="shortcut icon" type="image/png" href="favicon.png">
<title>AutoImages</title>
diff --git a/AutoVideos.html b/AutoVideos.html index 0e23d65..dffe44f 100644 --- a/AutoVideos.html +++ b/AutoVideos.html @@ -2,7 +2,7 @@ <head>
-<link rel="stylesheet" href="css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="js/latexit.js"></script>
<link rel="shortcut icon" type="image/png" href="favicon.png">
@@ -60,7 +60,7 @@ Function length: <input type='number' value='60'><br> <div id='Function' lang='latex'></div>
-<script src="http://antimatter15.com/whammy/whammy.js"></script>
+<script src="https://antimatter15.com/whammy/whammy.js"></script>
<script src="js/AutoVideos.js"></script>
<noscript>
diff --git a/Harmonograph.html b/Harmonograph.html index ef3d398..ec9c6c4 100644 --- a/Harmonograph.html +++ b/Harmonograph.html @@ -1,7 +1,7 @@ <html> <head> <title>Harmonograph</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -15,7 +15,7 @@ <button onclick="saveCanvas();">Save image</button><br> <button onclick="addPendulum();">Add pendulum</button> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/Harmonograph.js"></script> </body> diff --git a/NameGenerator.html b/NameGenerator.html index 019a6f4..6b15438 100644 --- a/NameGenerator.html +++ b/NameGenerator.html @@ -1,7 +1,7 @@ <html> <head> <title>NameGenerator</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <style> #loading @@ -2,7 +2,7 @@ <head> <title>All</title> <meta charset="utf-8"> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" type="image/png" href="favicon.png"> </head> @@ -1,9 +1,9 @@ <html> <head> <title>Langton's Ant</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> </head> <body> <h2>Langton's Ant</h2> @@ -2,7 +2,7 @@ <head> <title>Android Apps</title> <meta charset="utf-8"> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" type="image/png" href="favicon.png"> </head> diff --git a/ballbounce.html b/ballbounce.html index 0bbdf01..5042d15 100644 --- a/ballbounce.html +++ b/ballbounce.html @@ -1,7 +1,7 @@ <html> <head> <title>Bounce the ball</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> @@ -12,7 +12,7 @@ <hr> <p>You can get the android app for Ball Bounce <a href="https://play.google.com/store/apps/details?id=org.neocities.autoart.ballbounce">here</a>.</p> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/ballbounce.js"></script> </body> </html>
\ No newline at end of file @@ -1,7 +1,7 @@ <html> <head> <title>Clock</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" type="image/png" href="clock.png"> </head> @@ -10,7 +10,7 @@ <div id="header_links_div"></div> <script src="js/header_links.js"></script> <hr> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/clock.js"></script> </body> -</html>
\ No newline at end of file +</html> diff --git a/css/bootstrap.min.css b/css/bootstrap.min.css deleted file mode 100644 index 4cf729e..0000000 --- a/css/bootstrap.min.css +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */
\ No newline at end of file diff --git a/explanation.html b/explanation.html index 805192f..c7d778e 100644 --- a/explanation.html +++ b/explanation.html @@ -1,7 +1,7 @@ <html>
<head>
<script src="js/latexit.js"></script>
-<link rel="stylesheet" href="css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<title>AutoArt Explanation</title>
@@ -2,7 +2,7 @@ <head> <title>Games</title> <meta charset="utf-8"> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" type="image/png" href="favicon.png"> <style> @@ -2,7 +2,7 @@ <head> <title>AutoArt</title> - <link rel="stylesheet" href="css/bootstrap.min.css"> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" type="image/png" href="favicon.png"> diff --git a/js/p5.js b/js/p5.js deleted file mode 100644 index 43d7136..0000000 --- a/js/p5.js +++ /dev/null @@ -1,29765 +0,0 @@ -/*! p5.js v0.4.23 March 04, 2016 */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.p5 = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ - -},{}],2:[function(_dereq_,module,exports){ -// Run-time checking of preconditions. - -'use strict'; - -// Precondition function that checks if the given predicate is true. -// If not, it will throw an error. -exports.argument = function(predicate, message) { - if (!predicate) { - throw new Error(message); - } -}; - -// Precondition function that checks if the given assertion is true. -// If not, it will throw an error. -exports.assert = exports.argument; - -},{}],3:[function(_dereq_,module,exports){ -// Drawing utility functions. - -'use strict'; - -// Draw a line on the given context from point `x1,y1` to point `x2,y2`. -function line(ctx, x1, y1, x2, y2) { - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.stroke(); -} - -exports.line = line; - -},{}],4:[function(_dereq_,module,exports){ -// Glyph encoding - -'use strict'; - -var cffStandardStrings = [ - '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', - 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', - 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', - 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', - 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', - 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', - 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', - 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', - 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', - 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', - 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', - 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', - 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', - 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', - 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', - 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', - 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', - 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', - 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', - 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff', 'onedotenleader', - 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', - 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', - 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', - 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', - 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', - 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', - 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', - 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', - 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', - 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', - 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', - 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', - 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', - 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', - 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', - 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', - 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', - 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', - 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', - '001.001', '001.002', '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold']; - -var cffStandardEncoding = [ - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', - 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', - 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', - 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', - 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', - 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', - 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', - 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', - 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '', - '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', - 'lslash', 'oslash', 'oe', 'germandbls']; - -var cffExpertEncoding = [ - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', - 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', - 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', - 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', - 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', - 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', - 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', - 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', - 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', - 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', - 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', - 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior', - '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', - 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', - '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', - 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', - 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', - 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', - 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', - 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', - 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', - 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', - 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall']; - -var standardNames = [ - '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', - 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', - 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', - 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', - 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', - 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', - 'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', - 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', - 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', - 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal', - 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', - 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown', - 'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', - 'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', - 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', - 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', - 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', - 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', - 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', - 'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth', - 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior', - 'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla', - 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat']; - -// This is the encoding used for fonts created from scratch. -// It loops through all glyphs and finds the appropriate unicode value. -// Since it's linear time, other encodings will be faster. -function DefaultEncoding(font) { - this.font = font; -} - -DefaultEncoding.prototype.charToGlyphIndex = function(c) { - var code = c.charCodeAt(0); - var glyphs = this.font.glyphs; - if (glyphs) { - for (var i = 0; i < glyphs.length; i += 1) { - var glyph = glyphs.get(i); - for (var j = 0; j < glyph.unicodes.length; j += 1) { - if (glyph.unicodes[j] === code) { - return i; - } - } - } - } else { - return null; - } -}; - -function CmapEncoding(cmap) { - this.cmap = cmap; -} - -CmapEncoding.prototype.charToGlyphIndex = function(c) { - return this.cmap.glyphIndexMap[c.charCodeAt(0)] || 0; -}; - -function CffEncoding(encoding, charset) { - this.encoding = encoding; - this.charset = charset; -} - -CffEncoding.prototype.charToGlyphIndex = function(s) { - var code = s.charCodeAt(0); - var charName = this.encoding[code]; - return this.charset.indexOf(charName); -}; - -function GlyphNames(post) { - var i; - switch (post.version) { - case 1: - this.names = exports.standardNames.slice(); - break; - case 2: - this.names = new Array(post.numberOfGlyphs); - for (i = 0; i < post.numberOfGlyphs; i++) { - if (post.glyphNameIndex[i] < exports.standardNames.length) { - this.names[i] = exports.standardNames[post.glyphNameIndex[i]]; - } else { - this.names[i] = post.names[post.glyphNameIndex[i] - exports.standardNames.length]; - } - } - - break; - case 2.5: - this.names = new Array(post.numberOfGlyphs); - for (i = 0; i < post.numberOfGlyphs; i++) { - this.names[i] = exports.standardNames[i + post.glyphNameIndex[i]]; - } - - break; - case 3: - this.names = []; - break; - } -} - -GlyphNames.prototype.nameToGlyphIndex = function(name) { - return this.names.indexOf(name); -}; - -GlyphNames.prototype.glyphIndexToName = function(gid) { - return this.names[gid]; -}; - -function addGlyphNames(font) { - var glyph; - var glyphIndexMap = font.tables.cmap.glyphIndexMap; - var charCodes = Object.keys(glyphIndexMap); - - for (var i = 0; i < charCodes.length; i += 1) { - var c = charCodes[i]; - var glyphIndex = glyphIndexMap[c]; - glyph = font.glyphs.get(glyphIndex); - glyph.addUnicode(parseInt(c)); - } - - for (i = 0; i < font.glyphs.length; i += 1) { - glyph = font.glyphs.get(i); - if (font.cffEncoding) { - glyph.name = font.cffEncoding.charset[i]; - } else { - glyph.name = font.glyphNames.glyphIndexToName(i); - } - } -} - -exports.cffStandardStrings = cffStandardStrings; -exports.cffStandardEncoding = cffStandardEncoding; -exports.cffExpertEncoding = cffExpertEncoding; -exports.standardNames = standardNames; -exports.DefaultEncoding = DefaultEncoding; -exports.CmapEncoding = CmapEncoding; -exports.CffEncoding = CffEncoding; -exports.GlyphNames = GlyphNames; -exports.addGlyphNames = addGlyphNames; - -},{}],5:[function(_dereq_,module,exports){ -// The Font object - -'use strict'; - -var path = _dereq_('./path'); -var sfnt = _dereq_('./tables/sfnt'); -var encoding = _dereq_('./encoding'); -var glyphset = _dereq_('./glyphset'); - -// A Font represents a loaded OpenType font file. -// It contains a set of glyphs and methods to draw text on a drawing context, -// or to get a path representing the text. -function Font(options) { - options = options || {}; - - // OS X will complain if the names are empty, so we put a single space everywhere by default. - this.familyName = options.familyName || ' '; - this.styleName = options.styleName || ' '; - this.designer = options.designer || ' '; - this.designerURL = options.designerURL || ' '; - this.manufacturer = options.manufacturer || ' '; - this.manufacturerURL = options.manufacturerURL || ' '; - this.license = options.license || ' '; - this.licenseURL = options.licenseURL || ' '; - this.version = options.version || 'Version 0.1'; - this.description = options.description || ' '; - this.copyright = options.copyright || ' '; - this.trademark = options.trademark || ' '; - this.unitsPerEm = options.unitsPerEm || 1000; - this.ascender = options.ascender; - this.descender = options.descender; - this.supported = true; - this.glyphs = new glyphset.GlyphSet(this, options.glyphs || []); - this.encoding = new encoding.DefaultEncoding(this); - this.tables = {}; -} - -// Check if the font has a glyph for the given character. -Font.prototype.hasChar = function(c) { - return this.encoding.charToGlyphIndex(c) !== null; -}; - -// Convert the given character to a single glyph index. -// Note that this function assumes that there is a one-to-one mapping between -// the given character and a glyph; for complex scripts this might not be the case. -Font.prototype.charToGlyphIndex = function(s) { - return this.encoding.charToGlyphIndex(s); -}; - -// Convert the given character to a single Glyph object. -// Note that this function assumes that there is a one-to-one mapping between -// the given character and a glyph; for complex scripts this might not be the case. -Font.prototype.charToGlyph = function(c) { - var glyphIndex = this.charToGlyphIndex(c); - var glyph = this.glyphs.get(glyphIndex); - if (!glyph) { - // .notdef - glyph = this.glyphs.get(0); - } - - return glyph; -}; - -// Convert the given text to a list of Glyph objects. -// Note that there is no strict one-to-one mapping between characters and -// glyphs, so the list of returned glyphs can be larger or smaller than the -// length of the given string. -Font.prototype.stringToGlyphs = function(s) { - var glyphs = []; - for (var i = 0; i < s.length; i += 1) { - var c = s[i]; - glyphs.push(this.charToGlyph(c)); - } - - return glyphs; -}; - -Font.prototype.nameToGlyphIndex = function(name) { - return this.glyphNames.nameToGlyphIndex(name); -}; - -Font.prototype.nameToGlyph = function(name) { - var glyphIndex = this.nametoGlyphIndex(name); - var glyph = this.glyphs.get(glyphIndex); - if (!glyph) { - // .notdef - glyph = this.glyphs.get(0); - } - - return glyph; -}; - -Font.prototype.glyphIndexToName = function(gid) { - if (!this.glyphNames.glyphIndexToName) { - return ''; - } - - return this.glyphNames.glyphIndexToName(gid); -}; - -// Retrieve the value of the kerning pair between the left glyph (or its index) -// and the right glyph (or its index). If no kerning pair is found, return 0. -// The kerning value gets added to the advance width when calculating the spacing -// between glyphs. -Font.prototype.getKerningValue = function(leftGlyph, rightGlyph) { - leftGlyph = leftGlyph.index || leftGlyph; - rightGlyph = rightGlyph.index || rightGlyph; - var gposKerning = this.getGposKerningValue; - return gposKerning ? gposKerning(leftGlyph, rightGlyph) : - (this.kerningPairs[leftGlyph + ',' + rightGlyph] || 0); -}; - -// Helper function that invokes the given callback for each glyph in the given text. -// The callback gets `(glyph, x, y, fontSize, options)`. -Font.prototype.forEachGlyph = function(text, x, y, fontSize, options, callback) { - if (!this.supported) { - return; - } - - x = x !== undefined ? x : 0; - y = y !== undefined ? y : 0; - fontSize = fontSize !== undefined ? fontSize : 72; - options = options || {}; - var kerning = options.kerning === undefined ? true : options.kerning; - var fontScale = 1 / this.unitsPerEm * fontSize; - var glyphs = this.stringToGlyphs(text); - for (var i = 0; i < glyphs.length; i += 1) { - var glyph = glyphs[i]; - callback(glyph, x, y, fontSize, options); - if (glyph.advanceWidth) { - x += glyph.advanceWidth * fontScale; - } - - if (kerning && i < glyphs.length - 1) { - var kerningValue = this.getKerningValue(glyph, glyphs[i + 1]); - x += kerningValue * fontScale; - } - } -}; - -// Create a Path object that represents the given text. -// -// text - The text to create. -// x - Horizontal position of the beginning of the text. (default: 0) -// y - Vertical position of the *baseline* of the text. (default: 0) -// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) -// Options is an optional object that contains: -// - kerning - Whether to take kerning information into account. (default: true) -// -// Returns a Path object. -Font.prototype.getPath = function(text, x, y, fontSize, options) { - var fullPath = new path.Path(); - this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) { - var glyphPath = glyph.getPath(gX, gY, gFontSize); - fullPath.extend(glyphPath); - }); - - return fullPath; -}; - -// Draw the text on the given drawing context. -// -// ctx - A 2D drawing context, like Canvas. -// text - The text to create. -// x - Horizontal position of the beginning of the text. (default: 0) -// y - Vertical position of the *baseline* of the text. (default: 0) -// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) -// Options is an optional object that contains: -// - kerning - Whether to take kerning information into account. (default: true) -Font.prototype.draw = function(ctx, text, x, y, fontSize, options) { - this.getPath(text, x, y, fontSize, options).draw(ctx); -}; - -// Draw the points of all glyphs in the text. -// On-curve points will be drawn in blue, off-curve points will be drawn in red. -// -// ctx - A 2D drawing context, like Canvas. -// text - The text to create. -// x - Horizontal position of the beginning of the text. (default: 0) -// y - Vertical position of the *baseline* of the text. (default: 0) -// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) -// Options is an optional object that contains: -// - kerning - Whether to take kerning information into account. (default: true) -Font.prototype.drawPoints = function(ctx, text, x, y, fontSize, options) { - this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) { - glyph.drawPoints(ctx, gX, gY, gFontSize); - }); -}; - -// Draw lines indicating important font measurements for all glyphs in the text. -// Black lines indicate the origin of the coordinate system (point 0,0). -// Blue lines indicate the glyph bounding box. -// Green line indicates the advance width of the glyph. -// -// ctx - A 2D drawing context, like Canvas. -// text - The text to create. -// x - Horizontal position of the beginning of the text. (default: 0) -// y - Vertical position of the *baseline* of the text. (default: 0) -// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) -// Options is an optional object that contains: -// - kerning - Whether to take kerning information into account. (default: true) -Font.prototype.drawMetrics = function(ctx, text, x, y, fontSize, options) { - this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) { - glyph.drawMetrics(ctx, gX, gY, gFontSize); - }); -}; - -// Validate -Font.prototype.validate = function() { - var warnings = []; - var _this = this; - - function assert(predicate, message) { - if (!predicate) { - warnings.push(message); - } - } - - function assertStringAttribute(attrName) { - assert(_this[attrName] && _this[attrName].trim().length > 0, 'No ' + attrName + ' specified.'); - } - - // Identification information - assertStringAttribute('familyName'); - assertStringAttribute('weightName'); - assertStringAttribute('manufacturer'); - assertStringAttribute('copyright'); - assertStringAttribute('version'); - - // Dimension information - assert(this.unitsPerEm > 0, 'No unitsPerEm specified.'); -}; - -// Convert the font object to a SFNT data structure. -// This structure contains all the necessary tables and metadata to create a binary OTF file. -Font.prototype.toTables = function() { - return sfnt.fontToTable(this); -}; - -Font.prototype.toBuffer = function() { - var sfntTable = this.toTables(); - var bytes = sfntTable.encode(); - var buffer = new ArrayBuffer(bytes.length); - var intArray = new Uint8Array(buffer); - for (var i = 0; i < bytes.length; i++) { - intArray[i] = bytes[i]; - } - - return buffer; -}; - -// Initiate a download of the OpenType font. -Font.prototype.download = function() { - var fileName = this.familyName.replace(/\s/g, '') + '-' + this.styleName + '.otf'; - var buffer = this.toBuffer(); - - window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; - window.requestFileSystem(window.TEMPORARY, buffer.byteLength, function(fs) { - fs.root.getFile(fileName, {create: true}, function(fileEntry) { - fileEntry.createWriter(function(writer) { - var dataView = new DataView(buffer); - var blob = new Blob([dataView], {type: 'font/opentype'}); - writer.write(blob); - - writer.addEventListener('writeend', function() { - // Navigating to the file will download it. - location.href = fileEntry.toURL(); - }, false); - }); - }); - }, - - function(err) { - throw err; - }); -}; - -exports.Font = Font; - -},{"./encoding":4,"./glyphset":7,"./path":10,"./tables/sfnt":25}],6:[function(_dereq_,module,exports){ -// The Glyph object - -'use strict'; - -var check = _dereq_('./check'); -var draw = _dereq_('./draw'); -var path = _dereq_('./path'); - -function getPathDefinition(glyph, path) { - var _path = path || { commands: [] }; - return { - configurable: true, - - get: function() { - if (typeof _path === 'function') { - _path = _path(); - } - - return _path; - }, - - set: function(p) { - _path = p; - } - }; -} - -// A Glyph is an individual mark that often corresponds to a character. -// Some glyphs, such as ligatures, are a combination of many characters. -// Glyphs are the basic building blocks of a font. -// -// The `Glyph` class contains utility methods for drawing the path and its points. -function Glyph(options) { - // By putting all the code on a prototype function (which is only declared once) - // we reduce the memory requirements for larger fonts by some 2% - this.bindConstructorValues(options); -} - -Glyph.prototype.bindConstructorValues = function(options) { - this.index = options.index || 0; - - // These three values cannnot be deferred for memory optimization: - this.name = options.name || null; - this.unicode = options.unicode || undefined; - this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : []; - - // But by binding these values only when necessary, we reduce can - // the memory requirements by almost 3% for larger fonts. - if (options.xMin) { - this.xMin = options.xMin; - } - - if (options.yMin) { - this.yMin = options.yMin; - } - - if (options.xMax) { - this.xMax = options.xMax; - } - - if (options.yMax) { - this.yMax = options.yMax; - } - - if (options.advanceWidth) { - this.advanceWidth = options.advanceWidth; - } - - // The path for a glyph is the most memory intensive, and is bound as a value - // with a getter/setter to ensure we actually do path parsing only once the - // path is actually needed by anything. - Object.defineProperty(this, 'path', getPathDefinition(this, options.path)); -}; - -Glyph.prototype.addUnicode = function(unicode) { - if (this.unicodes.length === 0) { - this.unicode = unicode; - } - - this.unicodes.push(unicode); -}; - -// Convert the glyph to a Path we can draw on a drawing context. -// -// x - Horizontal position of the glyph. (default: 0) -// y - Vertical position of the *baseline* of the glyph. (default: 0) -// fontSize - Font size, in pixels (default: 72). -Glyph.prototype.getPath = function(x, y, fontSize) { - x = x !== undefined ? x : 0; - y = y !== undefined ? y : 0; - fontSize = fontSize !== undefined ? fontSize : 72; - var scale = 1 / this.path.unitsPerEm * fontSize; - var p = new path.Path(); - var commands = this.path.commands; - for (var i = 0; i < commands.length; i += 1) { - var cmd = commands[i]; - if (cmd.type === 'M') { - p.moveTo(x + (cmd.x * scale), y + (-cmd.y * scale)); - } else if (cmd.type === 'L') { - p.lineTo(x + (cmd.x * scale), y + (-cmd.y * scale)); - } else if (cmd.type === 'Q') { - p.quadraticCurveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale), - x + (cmd.x * scale), y + (-cmd.y * scale)); - } else if (cmd.type === 'C') { - p.curveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale), - x + (cmd.x2 * scale), y + (-cmd.y2 * scale), - x + (cmd.x * scale), y + (-cmd.y * scale)); - } else if (cmd.type === 'Z') { - p.closePath(); - } - } - - return p; -}; - -// Split the glyph into contours. -// This function is here for backwards compatibility, and to -// provide raw access to the TrueType glyph outlines. -Glyph.prototype.getContours = function() { - if (this.points === undefined) { - return []; - } - - var contours = []; - var currentContour = []; - for (var i = 0; i < this.points.length; i += 1) { - var pt = this.points[i]; - currentContour.push(pt); - if (pt.lastPointOfContour) { - contours.push(currentContour); - currentContour = []; - } - } - - check.argument(currentContour.length === 0, 'There are still points left in the current contour.'); - return contours; -}; - -// Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph. -Glyph.prototype.getMetrics = function() { - var commands = this.path.commands; - var xCoords = []; - var yCoords = []; - for (var i = 0; i < commands.length; i += 1) { - var cmd = commands[i]; - if (cmd.type !== 'Z') { - xCoords.push(cmd.x); - yCoords.push(cmd.y); - } - - if (cmd.type === 'Q' || cmd.type === 'C') { - xCoords.push(cmd.x1); - yCoords.push(cmd.y1); - } - - if (cmd.type === 'C') { - xCoords.push(cmd.x2); - yCoords.push(cmd.y2); - } - } - - var metrics = { - xMin: Math.min.apply(null, xCoords), - yMin: Math.min.apply(null, yCoords), - xMax: Math.max.apply(null, xCoords), - yMax: Math.max.apply(null, yCoords), - leftSideBearing: 0 - }; - metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin); - return metrics; -}; - -// Draw the glyph on the given context. -// -// ctx - The drawing context. -// x - Horizontal position of the glyph. (default: 0) -// y - Vertical position of the *baseline* of the glyph. (default: 0) -// fontSize - Font size, in pixels (default: 72). -Glyph.prototype.draw = function(ctx, x, y, fontSize) { - this.getPath(x, y, fontSize).draw(ctx); -}; - -// Draw the points of the glyph. -// On-curve points will be drawn in blue, off-curve points will be drawn in red. -// -// ctx - The drawing context. -// x - Horizontal position of the glyph. (default: 0) -// y - Vertical position of the *baseline* of the glyph. (default: 0) -// fontSize - Font size, in pixels (default: 72). -Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) { - - function drawCircles(l, x, y, scale) { - var PI_SQ = Math.PI * 2; - ctx.beginPath(); - for (var j = 0; j < l.length; j += 1) { - ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale)); - ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, PI_SQ, false); - } - - ctx.closePath(); - ctx.fill(); - } - - x = x !== undefined ? x : 0; - y = y !== undefined ? y : 0; - fontSize = fontSize !== undefined ? fontSize : 24; - var scale = 1 / this.path.unitsPerEm * fontSize; - - var blueCircles = []; - var redCircles = []; - var path = this.path; - for (var i = 0; i < path.commands.length; i += 1) { - var cmd = path.commands[i]; - if (cmd.x !== undefined) { - blueCircles.push({x: cmd.x, y: -cmd.y}); - } - - if (cmd.x1 !== undefined) { - redCircles.push({x: cmd.x1, y: -cmd.y1}); - } - - if (cmd.x2 !== undefined) { - redCircles.push({x: cmd.x2, y: -cmd.y2}); - } - } - - ctx.fillStyle = 'blue'; - drawCircles(blueCircles, x, y, scale); - ctx.fillStyle = 'red'; - drawCircles(redCircles, x, y, scale); -}; - -// Draw lines indicating important font measurements. -// Black lines indicate the origin of the coordinate system (point 0,0). -// Blue lines indicate the glyph bounding box. -// Green line indicates the advance width of the glyph. -// -// ctx - The drawing context. -// x - Horizontal position of the glyph. (default: 0) -// y - Vertical position of the *baseline* of the glyph. (default: 0) -// fontSize - Font size, in pixels (default: 72). -Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) { - var scale; - x = x !== undefined ? x : 0; - y = y !== undefined ? y : 0; - fontSize = fontSize !== undefined ? fontSize : 24; - scale = 1 / this.path.unitsPerEm * fontSize; - ctx.lineWidth = 1; - - // Draw the origin - ctx.strokeStyle = 'black'; - draw.line(ctx, x, -10000, x, 10000); - draw.line(ctx, -10000, y, 10000, y); - - // This code is here due to memory optimization: by not using - // defaults in the constructor, we save a notable amount of memory. - var xMin = this.xMin || 0; - var yMin = this.yMin || 0; - var xMax = this.xMax || 0; - var yMax = this.yMax || 0; - var advanceWidth = this.advanceWidth || 0; - - // Draw the glyph box - ctx.strokeStyle = 'blue'; - draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000); - draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000); - draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale)); - draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale)); - - // Draw the advance width - ctx.strokeStyle = 'green'; - draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000); -}; - -exports.Glyph = Glyph; - -},{"./check":2,"./draw":3,"./path":10}],7:[function(_dereq_,module,exports){ -// The GlyphSet object - -'use strict'; - -var _glyph = _dereq_('./glyph'); - -// A GlyphSet represents all glyphs available in the font, but modelled using -// a deferred glyph loader, for retrieving glyphs only once they are absolutely -// necessary, to keep the memory footprint down. -function GlyphSet(font, glyphs) { - this.font = font; - this.glyphs = {}; - if (Array.isArray(glyphs)) { - for (var i = 0; i < glyphs.length; i++) { - this.glyphs[i] = glyphs[i]; - } - } - - this.length = (glyphs && glyphs.length) || 0; -} - -GlyphSet.prototype.get = function(index) { - if (typeof this.glyphs[index] === 'function') { - this.glyphs[index] = this.glyphs[index](); - } - - return this.glyphs[index]; -}; - -GlyphSet.prototype.push = function(index, loader) { - this.glyphs[index] = loader; - this.length++; -}; - -function glyphLoader(font, index) { - return new _glyph.Glyph({index: index, font: font}); -} - -/** - * Generate a stub glyph that can be filled with all metadata *except* - * the "points" and "path" properties, which must be loaded only once - * the glyph's path is actually requested for text shaping. - */ - -function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPath) { - return function() { - var glyph = new _glyph.Glyph({index: index, font: font}); - - glyph.path = function() { - parseGlyph(glyph, data, position); - var path = buildPath(font.glyphs, glyph); - path.unitsPerEm = font.unitsPerEm; - return path; - }; - - return glyph; - }; -} - -function cffGlyphLoader(font, index, parseCFFCharstring, charstring) { - return function() { - var glyph = new _glyph.Glyph({index: index, font: font}); - - glyph.path = function() { - var path = parseCFFCharstring(font, glyph, charstring); - path.unitsPerEm = font.unitsPerEm; - return path; - }; - - return glyph; - }; -} - -exports.GlyphSet = GlyphSet; -exports.glyphLoader = glyphLoader; -exports.ttfGlyphLoader = ttfGlyphLoader; -exports.cffGlyphLoader = cffGlyphLoader; - -},{"./glyph":6}],8:[function(_dereq_,module,exports){ -// opentype.js -// https://github.com/nodebox/opentype.js -// (c) 2015 Frederik De Bleser -// opentype.js may be freely distributed under the MIT license. - -/* global ArrayBuffer, DataView, Uint8Array, XMLHttpRequest */ - -'use strict'; - -var encoding = _dereq_('./encoding'); -var _font = _dereq_('./font'); -var glyph = _dereq_('./glyph'); -var parse = _dereq_('./parse'); -var path = _dereq_('./path'); - -var cmap = _dereq_('./tables/cmap'); -var cff = _dereq_('./tables/cff'); -var glyf = _dereq_('./tables/glyf'); -var gpos = _dereq_('./tables/gpos'); -var head = _dereq_('./tables/head'); -var hhea = _dereq_('./tables/hhea'); -var hmtx = _dereq_('./tables/hmtx'); -var kern = _dereq_('./tables/kern'); -var loca = _dereq_('./tables/loca'); -var maxp = _dereq_('./tables/maxp'); -var _name = _dereq_('./tables/name'); -var os2 = _dereq_('./tables/os2'); -var post = _dereq_('./tables/post'); - -// File loaders ///////////////////////////////////////////////////////// - -// Convert a Node.js Buffer to an ArrayBuffer -function toArrayBuffer(buffer) { - var arrayBuffer = new ArrayBuffer(buffer.length); - var data = new Uint8Array(arrayBuffer); - for (var i = 0; i < buffer.length; i += 1) { - data[i] = buffer[i]; - } - - return arrayBuffer; -} - -function loadFromFile(path, callback) { - var fs = _dereq_('fs'); - fs.readFile(path, function(err, buffer) { - if (err) { - return callback(err.message); - } - - callback(null, toArrayBuffer(buffer)); - }); -} - -function loadFromUrl(url, callback) { - var request = new XMLHttpRequest(); - request.open('get', url, true); - request.responseType = 'arraybuffer'; - request.onload = function() { - if (request.status !== 200) { - return callback('Font could not be loaded: ' + request.statusText); - } - - return callback(null, request.response); - }; - - request.send(); -} - -// Public API /////////////////////////////////////////////////////////// - -// Parse the OpenType file data (as an ArrayBuffer) and return a Font object. -// If the file could not be parsed (most likely because it contains Postscript outlines) -// we return an empty Font object with the `supported` flag set to `false`. -function parseBuffer(buffer) { - var indexToLocFormat; - var hmtxOffset; - var glyfOffset; - var locaOffset; - var cffOffset; - var kernOffset; - var gposOffset; - - // OpenType fonts use big endian byte ordering. - // We can't rely on typed array view types, because they operate with the endianness of the host computer. - // Instead we use DataViews where we can specify endianness. - - var font = new _font.Font(); - var data = new DataView(buffer, 0); - - var version = parse.getFixed(data, 0); - if (version === 1.0) { - font.outlinesFormat = 'truetype'; - } else { - version = parse.getTag(data, 0); - if (version === 'OTTO') { - font.outlinesFormat = 'cff'; - } else { - throw new Error('Unsupported OpenType version ' + version); - } - } - - var numTables = parse.getUShort(data, 4); - - // Offset into the table records. - var p = 12; - for (var i = 0; i < numTables; i += 1) { - var tag = parse.getTag(data, p); - var offset = parse.getULong(data, p + 8); - switch (tag) { - case 'cmap': - font.tables.cmap = cmap.parse(data, offset); - font.encoding = new encoding.CmapEncoding(font.tables.cmap); - if (!font.encoding) { - font.supported = false; - } - - break; - case 'head': - font.tables.head = head.parse(data, offset); - font.unitsPerEm = font.tables.head.unitsPerEm; - indexToLocFormat = font.tables.head.indexToLocFormat; - break; - case 'hhea': - font.tables.hhea = hhea.parse(data, offset); - font.ascender = font.tables.hhea.ascender; - font.descender = font.tables.hhea.descender; - font.numberOfHMetrics = font.tables.hhea.numberOfHMetrics; - break; - case 'hmtx': - hmtxOffset = offset; - break; - case 'maxp': - font.tables.maxp = maxp.parse(data, offset); - font.numGlyphs = font.tables.maxp.numGlyphs; - break; - case 'name': - font.tables.name = _name.parse(data, offset); - font.familyName = font.tables.name.fontFamily; - font.styleName = font.tables.name.fontSubfamily; - break; - case 'OS/2': - font.tables.os2 = os2.parse(data, offset); - break; - case 'post': - font.tables.post = post.parse(data, offset); - font.glyphNames = new encoding.GlyphNames(font.tables.post); - break; - case 'glyf': - glyfOffset = offset; - break; - case 'loca': - locaOffset = offset; - break; - case 'CFF ': - cffOffset = offset; - break; - case 'kern': - kernOffset = offset; - break; - case 'GPOS': - gposOffset = offset; - break; - } - p += 16; - } - - if (glyfOffset && locaOffset) { - var shortVersion = indexToLocFormat === 0; - var locaTable = loca.parse(data, locaOffset, font.numGlyphs, shortVersion); - font.glyphs = glyf.parse(data, glyfOffset, locaTable, font); - hmtx.parse(data, hmtxOffset, font.numberOfHMetrics, font.numGlyphs, font.glyphs); - encoding.addGlyphNames(font); - } else if (cffOffset) { - cff.parse(data, cffOffset, font); - encoding.addGlyphNames(font); - } else { - font.supported = false; - } - - if (font.supported) { - if (kernOffset) { - font.kerningPairs = kern.parse(data, kernOffset); - } else { - font.kerningPairs = {}; - } - - if (gposOffset) { - gpos.parse(data, gposOffset, font); - } - } - - return font; -} - -// Asynchronously load the font from a URL or a filesystem. When done, call the callback -// with two arguments `(err, font)`. The `err` will be null on success, -// the `font` is a Font object. -// -// We use the node.js callback convention so that -// opentype.js can integrate with frameworks like async.js. -function load(url, callback) { - var isNode = typeof window === 'undefined'; - var loadFn = isNode ? loadFromFile : loadFromUrl; - loadFn(url, function(err, arrayBuffer) { - if (err) { - return callback(err); - } - - var font = parseBuffer(arrayBuffer); - if (!font.supported) { - return callback('Font is not supported (is this a Postscript font?)'); - } - - return callback(null, font); - }); -} - -exports._parse = parse; -exports.Font = _font.Font; -exports.Glyph = glyph.Glyph; -exports.Path = path.Path; -exports.parse = parseBuffer; -exports.load = load; - -},{"./encoding":4,"./font":5,"./glyph":6,"./parse":9,"./path":10,"./tables/cff":12,"./tables/cmap":13,"./tables/glyf":14,"./tables/gpos":15,"./tables/head":16,"./tables/hhea":17,"./tables/hmtx":18,"./tables/kern":19,"./tables/loca":20,"./tables/maxp":21,"./tables/name":22,"./tables/os2":23,"./tables/post":24,"fs":1}],9:[function(_dereq_,module,exports){ -// Parsing utility functions - -'use strict'; - -// Retrieve an unsigned byte from the DataView. -exports.getByte = function getByte(dataView, offset) { - return dataView.getUint8(offset); -}; - -exports.getCard8 = exports.getByte; - -// Retrieve an unsigned 16-bit short from the DataView. -// The value is stored in big endian. -exports.getUShort = function(dataView, offset) { - return dataView.getUint16(offset, false); -}; - -exports.getCard16 = exports.getUShort; - -// Retrieve a signed 16-bit short from the DataView. -// The value is stored in big endian. -exports.getShort = function(dataView, offset) { - return dataView.getInt16(offset, false); -}; - -// Retrieve an unsigned 32-bit long from the DataView. -// The value is stored in big endian. -exports.getULong = function(dataView, offset) { - return dataView.getUint32(offset, false); -}; - -// Retrieve a 32-bit signed fixed-point number (16.16) from the DataView. -// The value is stored in big endian. -exports.getFixed = function(dataView, offset) { - var decimal = dataView.getInt16(offset, false); - var fraction = dataView.getUint16(offset + 2, false); - return decimal + fraction / 65535; -}; - -// Retrieve a 4-character tag from the DataView. -// Tags are used to identify tables. -exports.getTag = function(dataView, offset) { - var tag = ''; - for (var i = offset; i < offset + 4; i += 1) { - tag += String.fromCharCode(dataView.getInt8(i)); - } - - return tag; -}; - -// Retrieve an offset from the DataView. -// Offsets are 1 to 4 bytes in length, depending on the offSize argument. -exports.getOffset = function(dataView, offset, offSize) { - var v = 0; - for (var i = 0; i < offSize; i += 1) { - v <<= 8; - v += dataView.getUint8(offset + i); - } - - return v; -}; - -// Retrieve a number of bytes from start offset to the end offset from the DataView. -exports.getBytes = function(dataView, startOffset, endOffset) { - var bytes = []; - for (var i = startOffset; i < endOffset; i += 1) { - bytes.push(dataView.getUint8(i)); - } - - return bytes; -}; - -// Convert the list of bytes to a string. -exports.bytesToString = function(bytes) { - var s = ''; - for (var i = 0; i < bytes.length; i += 1) { - s += String.fromCharCode(bytes[i]); - } - - return s; -}; - -var typeOffsets = { - byte: 1, - uShort: 2, - short: 2, - uLong: 4, - fixed: 4, - longDateTime: 8, - tag: 4 -}; - -// A stateful parser that changes the offset whenever a value is retrieved. -// The data is a DataView. -function Parser(data, offset) { - this.data = data; - this.offset = offset; - this.relativeOffset = 0; -} - -Parser.prototype.parseByte = function() { - var v = this.data.getUint8(this.offset + this.relativeOffset); - this.relativeOffset += 1; - return v; -}; - -Parser.prototype.parseChar = function() { - var v = this.data.getInt8(this.offset + this.relativeOffset); - this.relativeOffset += 1; - return v; -}; - -Parser.prototype.parseCard8 = Parser.prototype.parseByte; - -Parser.prototype.parseUShort = function() { - var v = this.data.getUint16(this.offset + this.relativeOffset); - this.relativeOffset += 2; - return v; -}; - -Parser.prototype.parseCard16 = Parser.prototype.parseUShort; -Parser.prototype.parseSID = Parser.prototype.parseUShort; -Parser.prototype.parseOffset16 = Parser.prototype.parseUShort; - -Parser.prototype.parseShort = function() { - var v = this.data.getInt16(this.offset + this.relativeOffset); - this.relativeOffset += 2; - return v; -}; - -Parser.prototype.parseF2Dot14 = function() { - var v = this.data.getInt16(this.offset + this.relativeOffset) / 16384; - this.relativeOffset += 2; - return v; -}; - -Parser.prototype.parseULong = function() { - var v = exports.getULong(this.data, this.offset + this.relativeOffset); - this.relativeOffset += 4; - return v; -}; - -Parser.prototype.parseFixed = function() { - var v = exports.getFixed(this.data, this.offset + this.relativeOffset); - this.relativeOffset += 4; - return v; -}; - -Parser.prototype.parseOffset16List = -Parser.prototype.parseUShortList = function(count) { - var offsets = new Array(count); - var dataView = this.data; - var offset = this.offset + this.relativeOffset; - for (var i = 0; i < count; i++) { - offsets[i] = exports.getUShort(dataView, offset); - offset += 2; - } - - this.relativeOffset += count * 2; - return offsets; -}; - -Parser.prototype.parseString = function(length) { - var dataView = this.data; - var offset = this.offset + this.relativeOffset; - var string = ''; - this.relativeOffset += length; - for (var i = 0; i < length; i++) { - string += String.fromCharCode(dataView.getUint8(offset + i)); - } - - return string; -}; - -Parser.prototype.parseTag = function() { - return this.parseString(4); -}; - -// LONGDATETIME is a 64-bit integer. -// JavaScript and unix timestamps traditionally use 32 bits, so we -// only take the last 32 bits. -Parser.prototype.parseLongDateTime = function() { - var v = exports.getULong(this.data, this.offset + this.relativeOffset + 4); - this.relativeOffset += 8; - return v; -}; - -Parser.prototype.parseFixed = function() { - var v = exports.getULong(this.data, this.offset + this.relativeOffset); - this.relativeOffset += 4; - return v / 65536; -}; - -Parser.prototype.parseVersion = function() { - var major = exports.getUShort(this.data, this.offset + this.relativeOffset); - - // How to interpret the minor version is very vague in the spec. 0x5000 is 5, 0x1000 is 1 - // This returns the correct number if minor = 0xN000 where N is 0-9 - var minor = exports.getUShort(this.data, this.offset + this.relativeOffset + 2); - this.relativeOffset += 4; - return major + minor / 0x1000 / 10; -}; - -Parser.prototype.skip = function(type, amount) { - if (amount === undefined) { - amount = 1; - } - - this.relativeOffset += typeOffsets[type] * amount; -}; - -exports.Parser = Parser; - -},{}],10:[function(_dereq_,module,exports){ -// Geometric objects - -'use strict'; - -// A bézier path containing a set of path commands similar to a SVG path. -// Paths can be drawn on a context using `draw`. -function Path() { - this.commands = []; - this.fill = 'black'; - this.stroke = null; - this.strokeWidth = 1; -} - -Path.prototype.moveTo = function(x, y) { - this.commands.push({ - type: 'M', - x: x, - y: y - }); -}; - -Path.prototype.lineTo = function(x, y) { - this.commands.push({ - type: 'L', - x: x, - y: y - }); -}; - -Path.prototype.curveTo = Path.prototype.bezierCurveTo = function(x1, y1, x2, y2, x, y) { - this.commands.push({ - type: 'C', - x1: x1, - y1: y1, - x2: x2, - y2: y2, - x: x, - y: y - }); -}; - -Path.prototype.quadTo = Path.prototype.quadraticCurveTo = function(x1, y1, x, y) { - this.commands.push({ - type: 'Q', - x1: x1, - y1: y1, - x: x, - y: y - }); -}; - -Path.prototype.close = Path.prototype.closePath = function() { - this.commands.push({ - type: 'Z' - }); -}; - -// Add the given path or list of commands to the commands of this path. -Path.prototype.extend = function(pathOrCommands) { - if (pathOrCommands.commands) { - pathOrCommands = pathOrCommands.commands; - } - - Array.prototype.push.apply(this.commands, pathOrCommands); -}; - -// Draw the path to a 2D context. -Path.prototype.draw = function(ctx) { - ctx.beginPath(); - for (var i = 0; i < this.commands.length; i += 1) { - var cmd = this.commands[i]; - if (cmd.type === 'M') { - ctx.moveTo(cmd.x, cmd.y); - } else if (cmd.type === 'L') { - ctx.lineTo(cmd.x, cmd.y); - } else if (cmd.type === 'C') { - ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); - } else if (cmd.type === 'Q') { - ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y); - } else if (cmd.type === 'Z') { - ctx.closePath(); - } - } - - if (this.fill) { - ctx.fillStyle = this.fill; - ctx.fill(); - } - - if (this.stroke) { - ctx.strokeStyle = this.stroke; - ctx.lineWidth = this.strokeWidth; - ctx.stroke(); - } -}; - -// Convert the Path to a string of path data instructions -// See http://www.w3.org/TR/SVG/paths.html#PathData -// Parameters: -// - decimalPlaces: The amount of decimal places for floating-point values (default: 2) -Path.prototype.toPathData = function(decimalPlaces) { - decimalPlaces = decimalPlaces !== undefined ? decimalPlaces : 2; - - function floatToString(v) { - if (Math.round(v) === v) { - return '' + Math.round(v); - } else { - return v.toFixed(decimalPlaces); - } - } - - function packValues() { - var s = ''; - for (var i = 0; i < arguments.length; i += 1) { - var v = arguments[i]; - if (v >= 0 && i > 0) { - s += ' '; - } - - s += floatToString(v); - } - - return s; - } - - var d = ''; - for (var i = 0; i < this.commands.length; i += 1) { - var cmd = this.commands[i]; - if (cmd.type === 'M') { - d += 'M' + packValues(cmd.x, cmd.y); - } else if (cmd.type === 'L') { - d += 'L' + packValues(cmd.x, cmd.y); - } else if (cmd.type === 'C') { - d += 'C' + packValues(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); - } else if (cmd.type === 'Q') { - d += 'Q' + packValues(cmd.x1, cmd.y1, cmd.x, cmd.y); - } else if (cmd.type === 'Z') { - d += 'Z'; - } - } - - return d; -}; - -// Convert the path to a SVG <path> element, as a string. -// Parameters: -// - decimalPlaces: The amount of decimal places for floating-point values (default: 2) -Path.prototype.toSVG = function(decimalPlaces) { - var svg = '<path d="'; - svg += this.toPathData(decimalPlaces); - svg += '"'; - if (this.fill & this.fill !== 'black') { - if (this.fill === null) { - svg += ' fill="none"'; - } else { - svg += ' fill="' + this.fill + '"'; - } - } - - if (this.stroke) { - svg += ' stroke="' + this.stroke + '" stroke-width="' + this.strokeWidth + '"'; - } - - svg += '/>'; - return svg; -}; - -exports.Path = Path; - -},{}],11:[function(_dereq_,module,exports){ -// Table metadata - -'use strict'; - -var check = _dereq_('./check'); -var encode = _dereq_('./types').encode; -var sizeOf = _dereq_('./types').sizeOf; - -function Table(tableName, fields, options) { - var i; - for (i = 0; i < fields.length; i += 1) { - var field = fields[i]; - this[field.name] = field.value; - } - - this.tableName = tableName; - this.fields = fields; - if (options) { - var optionKeys = Object.keys(options); - for (i = 0; i < optionKeys.length; i += 1) { - var k = optionKeys[i]; - var v = options[k]; - if (this[k] !== undefined) { - this[k] = v; - } - } - } -} - -Table.prototype.sizeOf = function() { - var v = 0; - for (var i = 0; i < this.fields.length; i += 1) { - var field = this.fields[i]; - var value = this[field.name]; - if (value === undefined) { - value = field.value; - } - - if (typeof value.sizeOf === 'function') { - v += value.sizeOf(); - } else { - var sizeOfFunction = sizeOf[field.type]; - check.assert(typeof sizeOfFunction === 'function', 'Could not find sizeOf function for field' + field.name); - v += sizeOfFunction(value); - } - } - - return v; -}; - -Table.prototype.encode = function() { - return encode.TABLE(this); -}; - -exports.Table = Table; - -},{"./check":2,"./types":26}],12:[function(_dereq_,module,exports){ -// The `CFF` table contains the glyph outlines in PostScript format. -// https://www.microsoft.com/typography/OTSPEC/cff.htm -// http://download.microsoft.com/download/8/0/1/801a191c-029d-4af3-9642-555f6fe514ee/cff.pdf -// http://download.microsoft.com/download/8/0/1/801a191c-029d-4af3-9642-555f6fe514ee/type2.pdf - -'use strict'; - -var encoding = _dereq_('../encoding'); -var glyphset = _dereq_('../glyphset'); -var parse = _dereq_('../parse'); -var path = _dereq_('../path'); -var table = _dereq_('../table'); - -// Custom equals function that can also check lists. -function equals(a, b) { - if (a === b) { - return true; - } else if (Array.isArray(a) && Array.isArray(b)) { - if (a.length !== b.length) { - return false; - } - - for (var i = 0; i < a.length; i += 1) { - if (!equals(a[i], b[i])) { - return false; - } - } - - return true; - } else { - return false; - } -} - -// Parse a `CFF` INDEX array. -// An index array consists of a list of offsets, then a list of objects at those offsets. -function parseCFFIndex(data, start, conversionFn) { - //var i, objectOffset, endOffset; - var offsets = []; - var objects = []; - var count = parse.getCard16(data, start); - var i; - var objectOffset; - var endOffset; - if (count !== 0) { - var offsetSize = parse.getByte(data, start + 2); - objectOffset = start + ((count + 1) * offsetSize) + 2; - var pos = start + 3; - for (i = 0; i < count + 1; i += 1) { - offsets.push(parse.getOffset(data, pos, offsetSize)); - pos += offsetSize; - } - - // The total size of the index array is 4 header bytes + the value of the last offset. - endOffset = objectOffset + offsets[count]; - } else { - endOffset = start + 2; - } - - for (i = 0; i < offsets.length - 1; i += 1) { - var value = parse.getBytes(data, objectOffset + offsets[i], objectOffset + offsets[i + 1]); - if (conversionFn) { - value = conversionFn(value); - } - - objects.push(value); - } - - return {objects: objects, startOffset: start, endOffset: endOffset}; -} - -// Parse a `CFF` DICT real value. -function parseFloatOperand(parser) { - var s = ''; - var eof = 15; - var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-']; - while (true) { - var b = parser.parseByte(); - var n1 = b >> 4; - var n2 = b & 15; - - if (n1 === eof) { - break; - } - - s += lookup[n1]; - - if (n2 === eof) { - break; - } - - s += lookup[n2]; - } - - return parseFloat(s); -} - -// Parse a `CFF` DICT operand. -function parseOperand(parser, b0) { - var b1; - var b2; - var b3; - var b4; - if (b0 === 28) { - b1 = parser.parseByte(); - b2 = parser.parseByte(); - return b1 << 8 | b2; - } - - if (b0 === 29) { - b1 = parser.parseByte(); - b2 = parser.parseByte(); - b3 = parser.parseByte(); - b4 = parser.parseByte(); - return b1 << 24 | b2 << 16 | b3 << 8 | b4; - } - - if (b0 === 30) { - return parseFloatOperand(parser); - } - - if (b0 >= 32 && b0 <= 246) { - return b0 - 139; - } - - if (b0 >= 247 && b0 <= 250) { - b1 = parser.parseByte(); - return (b0 - 247) * 256 + b1 + 108; - } - - if (b0 >= 251 && b0 <= 254) { - b1 = parser.parseByte(); - return -(b0 - 251) * 256 - b1 - 108; - } - - throw new Error('Invalid b0 ' + b0); -} - -// Convert the entries returned by `parseDict` to a proper dictionary. -// If a value is a list of one, it is unpacked. -function entriesToObject(entries) { - var o = {}; - for (var i = 0; i < entries.length; i += 1) { - var key = entries[i][0]; - var values = entries[i][1]; - var value; - if (values.length === 1) { - value = values[0]; - } else { - value = values; - } - - if (o.hasOwnProperty(key)) { - throw new Error('Object ' + o + ' already has key ' + key); - } - - o[key] = value; - } - - return o; -} - -// Parse a `CFF` DICT object. -// A dictionary contains key-value pairs in a compact tokenized format. -function parseCFFDict(data, start, size) { - start = start !== undefined ? start : 0; - var parser = new parse.Parser(data, start); - var entries = []; - var operands = []; - size = size !== undefined ? size : data.length; - - while (parser.relativeOffset < size) { - var op = parser.parseByte(); - - // The first byte for each dict item distinguishes between operator (key) and operand (value). - // Values <= 21 are operators. - if (op <= 21) { - // Two-byte operators have an initial escape byte of 12. - if (op === 12) { - op = 1200 + parser.parseByte(); - } - - entries.push([op, operands]); - operands = []; - } else { - // Since the operands (values) come before the operators (keys), we store all operands in a list - // until we encounter an operator. - operands.push(parseOperand(parser, op)); - } - } - - return entriesToObject(entries); -} - -// Given a String Index (SID), return the value of the string. -// Strings below index 392 are standard CFF strings and are not encoded in the font. -function getCFFString(strings, index) { - if (index <= 390) { - index = encoding.cffStandardStrings[index]; - } else { - index = strings[index - 391]; - } - - return index; -} - -// Interpret a dictionary and return a new dictionary with readable keys and values for missing entries. -// This function takes `meta` which is a list of objects containing `operand`, `name` and `default`. -function interpretDict(dict, meta, strings) { - var newDict = {}; - - // Because we also want to include missing values, we start out from the meta list - // and lookup values in the dict. - for (var i = 0; i < meta.length; i += 1) { - var m = meta[i]; - var value = dict[m.op]; - if (value === undefined) { - value = m.value !== undefined ? m.value : null; - } - - if (m.type === 'SID') { - value = getCFFString(strings, value); - } - - newDict[m.name] = value; - } - - return newDict; -} - -// Parse the CFF header. -function parseCFFHeader(data, start) { - var header = {}; - header.formatMajor = parse.getCard8(data, start); - header.formatMinor = parse.getCard8(data, start + 1); - header.size = parse.getCard8(data, start + 2); - header.offsetSize = parse.getCard8(data, start + 3); - header.startOffset = start; - header.endOffset = start + 4; - return header; -} - -var TOP_DICT_META = [ - {name: 'version', op: 0, type: 'SID'}, - {name: 'notice', op: 1, type: 'SID'}, - {name: 'copyright', op: 1200, type: 'SID'}, - {name: 'fullName', op: 2, type: 'SID'}, - {name: 'familyName', op: 3, type: 'SID'}, - {name: 'weight', op: 4, type: 'SID'}, - {name: 'isFixedPitch', op: 1201, type: 'number', value: 0}, - {name: 'italicAngle', op: 1202, type: 'number', value: 0}, - {name: 'underlinePosition', op: 1203, type: 'number', value: -100}, - {name: 'underlineThickness', op: 1204, type: 'number', value: 50}, - {name: 'paintType', op: 1205, type: 'number', value: 0}, - {name: 'charstringType', op: 1206, type: 'number', value: 2}, - {name: 'fontMatrix', op: 1207, type: ['real', 'real', 'real', 'real', 'real', 'real'], value: [0.001, 0, 0, 0.001, 0, 0]}, - {name: 'uniqueId', op: 13, type: 'number'}, - {name: 'fontBBox', op: 5, type: ['number', 'number', 'number', 'number'], value: [0, 0, 0, 0]}, - {name: 'strokeWidth', op: 1208, type: 'number', value: 0}, - {name: 'xuid', op: 14, type: [], value: null}, - {name: 'charset', op: 15, type: 'offset', value: 0}, - {name: 'encoding', op: 16, type: 'offset', value: 0}, - {name: 'charStrings', op: 17, type: 'offset', value: 0}, - {name: 'private', op: 18, type: ['number', 'offset'], value: [0, 0]} -]; - -var PRIVATE_DICT_META = [ - {name: 'subrs', op: 19, type: 'offset', value: 0}, - {name: 'defaultWidthX', op: 20, type: 'number', value: 0}, - {name: 'nominalWidthX', op: 21, type: 'number', value: 0} -]; - -// Parse the CFF top dictionary. A CFF table can contain multiple fonts, each with their own top dictionary. -// The top dictionary contains the essential metadata for the font, together with the private dictionary. -function parseCFFTopDict(data, strings) { - var dict = parseCFFDict(data, 0, data.byteLength); - return interpretDict(dict, TOP_DICT_META, strings); -} - -// Parse the CFF private dictionary. We don't fully parse out all the values, only the ones we need. -function parseCFFPrivateDict(data, start, size, strings) { - var dict = parseCFFDict(data, start, size); - return interpretDict(dict, PRIVATE_DICT_META, strings); -} - -// Parse the CFF charset table, which contains internal names for all the glyphs. -// This function will return a list of glyph names. -// See Adobe TN #5176 chapter 13, "Charsets". -function parseCFFCharset(data, start, nGlyphs, strings) { - var i; - var sid; - var count; - var parser = new parse.Parser(data, start); - - // The .notdef glyph is not included, so subtract 1. - nGlyphs -= 1; - var charset = ['.notdef']; - - var format = parser.parseCard8(); - if (format === 0) { - for (i = 0; i < nGlyphs; i += 1) { - sid = parser.parseSID(); - charset.push(getCFFString(strings, sid)); - } - } else if (format === 1) { - while (charset.length <= nGlyphs) { - sid = parser.parseSID(); - count = parser.parseCard8(); - for (i = 0; i <= count; i += 1) { - charset.push(getCFFString(strings, sid)); - sid += 1; - } - } - } else if (format === 2) { - while (charset.length <= nGlyphs) { - sid = parser.parseSID(); - count = parser.parseCard16(); - for (i = 0; i <= count; i += 1) { - charset.push(getCFFString(strings, sid)); - sid += 1; - } - } - } else { - throw new Error('Unknown charset format ' + format); - } - - return charset; -} - -// Parse the CFF encoding data. Only one encoding can be specified per font. -// See Adobe TN #5176 chapter 12, "Encodings". -function parseCFFEncoding(data, start, charset) { - var i; - var code; - var enc = {}; - var parser = new parse.Parser(data, start); - var format = parser.parseCard8(); - if (format === 0) { - var nCodes = parser.parseCard8(); - for (i = 0; i < nCodes; i += 1) { - code = parser.parseCard8(); - enc[code] = i; - } - } else if (format === 1) { - var nRanges = parser.parseCard8(); - code = 1; - for (i = 0; i < nRanges; i += 1) { - var first = parser.parseCard8(); - var nLeft = parser.parseCard8(); - for (var j = first; j <= first + nLeft; j += 1) { - enc[j] = code; - code += 1; - } - } - } else { - throw new Error('Unknown encoding format ' + format); - } - - return new encoding.CffEncoding(enc, charset); -} - -// Take in charstring code and return a Glyph object. -// The encoding is described in the Type 2 Charstring Format -// https://www.microsoft.com/typography/OTSPEC/charstr2.htm -function parseCFFCharstring(font, glyph, code) { - var c1x; - var c1y; - var c2x; - var c2y; - var p = new path.Path(); - var stack = []; - var nStems = 0; - var haveWidth = false; - var width = font.defaultWidthX; - var open = false; - var x = 0; - var y = 0; - - function newContour(x, y) { - if (open) { - p.closePath(); - } - - p.moveTo(x, y); - open = true; - } - - function parseStems() { - var hasWidthArg; - - // The number of stem operators on the stack is always even. - // If the value is uneven, that means a width is specified. - hasWidthArg = stack.length % 2 !== 0; - if (hasWidthArg && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - } - - nStems += stack.length >> 1; - stack.length = 0; - haveWidth = true; - } - - function parse(code) { - var b1; - var b2; - var b3; - var b4; - var codeIndex; - var subrCode; - var jpx; - var jpy; - var c3x; - var c3y; - var c4x; - var c4y; - - var i = 0; - while (i < code.length) { - var v = code[i]; - i += 1; - switch (v) { - case 1: // hstem - parseStems(); - break; - case 3: // vstem - parseStems(); - break; - case 4: // vmoveto - if (stack.length > 1 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - y += stack.pop(); - newContour(x, y); - break; - case 5: // rlineto - while (stack.length > 0) { - x += stack.shift(); - y += stack.shift(); - p.lineTo(x, y); - } - - break; - case 6: // hlineto - while (stack.length > 0) { - x += stack.shift(); - p.lineTo(x, y); - if (stack.length === 0) { - break; - } - - y += stack.shift(); - p.lineTo(x, y); - } - - break; - case 7: // vlineto - while (stack.length > 0) { - y += stack.shift(); - p.lineTo(x, y); - if (stack.length === 0) { - break; - } - - x += stack.shift(); - p.lineTo(x, y); - } - - break; - case 8: // rrcurveto - while (stack.length > 0) { - c1x = x + stack.shift(); - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + stack.shift(); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 10: // callsubr - codeIndex = stack.pop() + font.subrsBias; - subrCode = font.subrs[codeIndex]; - if (subrCode) { - parse(subrCode); - } - - break; - case 11: // return - return; - case 12: // flex operators - v = code[i]; - i += 1; - switch (v) { - case 35: // flex - // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |- - c1x = x + stack.shift(); // dx1 - c1y = y + stack.shift(); // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y + stack.shift(); // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = jpy + stack.shift(); // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = c3y + stack.shift(); // dy5 - x = c4x + stack.shift(); // dx6 - y = c4y + stack.shift(); // dy6 - stack.shift(); // flex depth - p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - p.curveTo(c3x, c3y, c4x, c4y, x, y); - break; - case 34: // hflex - // |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |- - c1x = x + stack.shift(); // dx1 - c1y = y; // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y; // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = c2y; // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = y; // dy5 - x = c4x + stack.shift(); // dx6 - p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - p.curveTo(c3x, c3y, c4x, c4y, x, y); - break; - case 36: // hflex1 - // |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |- - c1x = x + stack.shift(); // dx1 - c1y = y + stack.shift(); // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y; // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = c2y; // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = c3y + stack.shift(); // dy5 - x = c4x + stack.shift(); // dx6 - p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - p.curveTo(c3x, c3y, c4x, c4y, x, y); - break; - case 37: // flex1 - // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |- - c1x = x + stack.shift(); // dx1 - c1y = y + stack.shift(); // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y + stack.shift(); // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = jpy + stack.shift(); // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = c3y + stack.shift(); // dy5 - if (Math.abs(c4x - x) > Math.abs(c4y - y)) { - x = c4x + stack.shift(); - } else { - y = c4y + stack.shift(); - } - - p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - p.curveTo(c3x, c3y, c4x, c4y, x, y); - break; - default: - console.log('Glyph ' + glyph.index + ': unknown operator ' + 1200 + v); - stack.length = 0; - } - break; - case 14: // endchar - if (stack.length > 0 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - if (open) { - p.closePath(); - open = false; - } - - break; - case 18: // hstemhm - parseStems(); - break; - case 19: // hintmask - case 20: // cntrmask - parseStems(); - i += (nStems + 7) >> 3; - break; - case 21: // rmoveto - if (stack.length > 2 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - y += stack.pop(); - x += stack.pop(); - newContour(x, y); - break; - case 22: // hmoveto - if (stack.length > 1 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - x += stack.pop(); - newContour(x, y); - break; - case 23: // vstemhm - parseStems(); - break; - case 24: // rcurveline - while (stack.length > 2) { - c1x = x + stack.shift(); - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + stack.shift(); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - } - - x += stack.shift(); - y += stack.shift(); - p.lineTo(x, y); - break; - case 25: // rlinecurve - while (stack.length > 6) { - x += stack.shift(); - y += stack.shift(); - p.lineTo(x, y); - } - - c1x = x + stack.shift(); - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + stack.shift(); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - break; - case 26: // vvcurveto - if (stack.length % 2) { - x += stack.shift(); - } - - while (stack.length > 0) { - c1x = x; - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x; - y = c2y + stack.shift(); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 27: // hhcurveto - if (stack.length % 2) { - y += stack.shift(); - } - - while (stack.length > 0) { - c1x = x + stack.shift(); - c1y = y; - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y; - p.curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 28: // shortint - b1 = code[i]; - b2 = code[i + 1]; - stack.push(((b1 << 24) | (b2 << 16)) >> 16); - i += 2; - break; - case 29: // callgsubr - codeIndex = stack.pop() + font.gsubrsBias; - subrCode = font.gsubrs[codeIndex]; - if (subrCode) { - parse(subrCode); - } - - break; - case 30: // vhcurveto - while (stack.length > 0) { - c1x = x; - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + (stack.length === 1 ? stack.shift() : 0); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - if (stack.length === 0) { - break; - } - - c1x = x + stack.shift(); - c1y = y; - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - y = c2y + stack.shift(); - x = c2x + (stack.length === 1 ? stack.shift() : 0); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 31: // hvcurveto - while (stack.length > 0) { - c1x = x + stack.shift(); - c1y = y; - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - y = c2y + stack.shift(); - x = c2x + (stack.length === 1 ? stack.shift() : 0); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - if (stack.length === 0) { - break; - } - - c1x = x; - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + (stack.length === 1 ? stack.shift() : 0); - p.curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - default: - if (v < 32) { - console.log('Glyph ' + glyph.index + ': unknown operator ' + v); - } else if (v < 247) { - stack.push(v - 139); - } else if (v < 251) { - b1 = code[i]; - i += 1; - stack.push((v - 247) * 256 + b1 + 108); - } else if (v < 255) { - b1 = code[i]; - i += 1; - stack.push(-(v - 251) * 256 - b1 - 108); - } else { - b1 = code[i]; - b2 = code[i + 1]; - b3 = code[i + 2]; - b4 = code[i + 3]; - i += 4; - stack.push(((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65536); - } - } - } - } - - parse(code); - - glyph.advanceWidth = width; - return p; -} - -// Subroutines are encoded using the negative half of the number space. -// See type 2 chapter 4.7 "Subroutine operators". -function calcCFFSubroutineBias(subrs) { - var bias; - if (subrs.length < 1240) { - bias = 107; - } else if (subrs.length < 33900) { - bias = 1131; - } else { - bias = 32768; - } - - return bias; -} - -// Parse the `CFF` table, which contains the glyph outlines in PostScript format. -function parseCFFTable(data, start, font) { - font.tables.cff = {}; - var header = parseCFFHeader(data, start); - var nameIndex = parseCFFIndex(data, header.endOffset, parse.bytesToString); - var topDictIndex = parseCFFIndex(data, nameIndex.endOffset); - var stringIndex = parseCFFIndex(data, topDictIndex.endOffset, parse.bytesToString); - var globalSubrIndex = parseCFFIndex(data, stringIndex.endOffset); - font.gsubrs = globalSubrIndex.objects; - font.gsubrsBias = calcCFFSubroutineBias(font.gsubrs); - - var topDictData = new DataView(new Uint8Array(topDictIndex.objects[0]).buffer); - var topDict = parseCFFTopDict(topDictData, stringIndex.objects); - font.tables.cff.topDict = topDict; - - var privateDictOffset = start + topDict['private'][1]; - var privateDict = parseCFFPrivateDict(data, privateDictOffset, topDict['private'][0], stringIndex.objects); - font.defaultWidthX = privateDict.defaultWidthX; - font.nominalWidthX = privateDict.nominalWidthX; - - if (privateDict.subrs !== 0) { - var subrOffset = privateDictOffset + privateDict.subrs; - var subrIndex = parseCFFIndex(data, subrOffset); - font.subrs = subrIndex.objects; - font.subrsBias = calcCFFSubroutineBias(font.subrs); - } else { - font.subrs = []; - font.subrsBias = 0; - } - - // Offsets in the top dict are relative to the beginning of the CFF data, so add the CFF start offset. - var charStringsIndex = parseCFFIndex(data, start + topDict.charStrings); - font.nGlyphs = charStringsIndex.objects.length; - - var charset = parseCFFCharset(data, start + topDict.charset, font.nGlyphs, stringIndex.objects); - if (topDict.encoding === 0) { // Standard encoding - font.cffEncoding = new encoding.CffEncoding(encoding.cffStandardEncoding, charset); - } else if (topDict.encoding === 1) { // Expert encoding - font.cffEncoding = new encoding.CffEncoding(encoding.cffExpertEncoding, charset); - } else { - font.cffEncoding = parseCFFEncoding(data, start + topDict.encoding, charset); - } - - // Prefer the CMAP encoding to the CFF encoding. - font.encoding = font.encoding || font.cffEncoding; - - font.glyphs = new glyphset.GlyphSet(font); - for (var i = 0; i < font.nGlyphs; i += 1) { - var charString = charStringsIndex.objects[i]; - font.glyphs.push(i, glyphset.cffGlyphLoader(font, i, parseCFFCharstring, charString)); - } -} - -// Convert a string to a String ID (SID). -// The list of strings is modified in place. -function encodeString(s, strings) { - var sid; - - // Is the string in the CFF standard strings? - var i = encoding.cffStandardStrings.indexOf(s); - if (i >= 0) { - sid = i; - } - - // Is the string already in the string index? - i = strings.indexOf(s); - if (i >= 0) { - sid = i + encoding.cffStandardStrings.length; - } else { - sid = encoding.cffStandardStrings.length + strings.length; - strings.push(s); - } - - return sid; -} - -function makeHeader() { - return new table.Table('Header', [ - {name: 'major', type: 'Card8', value: 1}, - {name: 'minor', type: 'Card8', value: 0}, - {name: 'hdrSize', type: 'Card8', value: 4}, - {name: 'major', type: 'Card8', value: 1} - ]); -} - -function makeNameIndex(fontNames) { - var t = new table.Table('Name INDEX', [ - {name: 'names', type: 'INDEX', value: []} - ]); - t.names = []; - for (var i = 0; i < fontNames.length; i += 1) { - t.names.push({name: 'name_' + i, type: 'NAME', value: fontNames[i]}); - } - - return t; -} - -// Given a dictionary's metadata, create a DICT structure. -function makeDict(meta, attrs, strings) { - var m = {}; - for (var i = 0; i < meta.length; i += 1) { - var entry = meta[i]; - var value = attrs[entry.name]; - if (value !== undefined && !equals(value, entry.value)) { - if (entry.type === 'SID') { - value = encodeString(value, strings); - } - - m[entry.op] = {name: entry.name, type: entry.type, value: value}; - } - } - - return m; -} - -// The Top DICT houses the global font attributes. -function makeTopDict(attrs, strings) { - var t = new table.Table('Top DICT', [ - {name: 'dict', type: 'DICT', value: {}} - ]); - t.dict = makeDict(TOP_DICT_META, attrs, strings); - return t; -} - -function makeTopDictIndex(topDict) { - var t = new table.Table('Top DICT INDEX', [ - {name: 'topDicts', type: 'INDEX', value: []} - ]); - t.topDicts = [{name: 'topDict_0', type: 'TABLE', value: topDict}]; - return t; -} - -function makeStringIndex(strings) { - var t = new table.Table('String INDEX', [ - {name: 'strings', type: 'INDEX', value: []} - ]); - t.strings = []; - for (var i = 0; i < strings.length; i += 1) { - t.strings.push({name: 'string_' + i, type: 'STRING', value: strings[i]}); - } - - return t; -} - -function makeGlobalSubrIndex() { - // Currently we don't use subroutines. - return new table.Table('Global Subr INDEX', [ - {name: 'subrs', type: 'INDEX', value: []} - ]); -} - -function makeCharsets(glyphNames, strings) { - var t = new table.Table('Charsets', [ - {name: 'format', type: 'Card8', value: 0} - ]); - for (var i = 0; i < glyphNames.length; i += 1) { - var glyphName = glyphNames[i]; - var glyphSID = encodeString(glyphName, strings); - t.fields.push({name: 'glyph_' + i, type: 'SID', value: glyphSID}); - } - - return t; -} - -function glyphToOps(glyph) { - var ops = []; - var path = glyph.path; - ops.push({name: 'width', type: 'NUMBER', value: glyph.advanceWidth}); - var x = 0; - var y = 0; - for (var i = 0; i < path.commands.length; i += 1) { - var dx; - var dy; - var cmd = path.commands[i]; - if (cmd.type === 'Q') { - // CFF only supports bézier curves, so convert the quad to a bézier. - var _13 = 1 / 3; - var _23 = 2 / 3; - - // We're going to create a new command so we don't change the original path. - cmd = { - type: 'C', - x: cmd.x, - y: cmd.y, - x1: _13 * x + _23 * cmd.x1, - y1: _13 * y + _23 * cmd.y1, - x2: _13 * cmd.x + _23 * cmd.x1, - y2: _13 * cmd.y + _23 * cmd.y1 - }; - } - - if (cmd.type === 'M') { - dx = Math.round(cmd.x - x); - dy = Math.round(cmd.y - y); - ops.push({name: 'dx', type: 'NUMBER', value: dx}); - ops.push({name: 'dy', type: 'NUMBER', value: dy}); - ops.push({name: 'rmoveto', type: 'OP', value: 21}); - x = Math.round(cmd.x); - y = Math.round(cmd.y); - } else if (cmd.type === 'L') { - dx = Math.round(cmd.x - x); - dy = Math.round(cmd.y - y); - ops.push({name: 'dx', type: 'NUMBER', value: dx}); - ops.push({name: 'dy', type: 'NUMBER', value: dy}); - ops.push({name: 'rlineto', type: 'OP', value: 5}); - x = Math.round(cmd.x); - y = Math.round(cmd.y); - } else if (cmd.type === 'C') { - var dx1 = Math.round(cmd.x1 - x); - var dy1 = Math.round(cmd.y1 - y); - var dx2 = Math.round(cmd.x2 - cmd.x1); - var dy2 = Math.round(cmd.y2 - cmd.y1); - dx = Math.round(cmd.x - cmd.x2); - dy = Math.round(cmd.y - cmd.y2); - ops.push({name: 'dx1', type: 'NUMBER', value: dx1}); - ops.push({name: 'dy1', type: 'NUMBER', value: dy1}); - ops.push({name: 'dx2', type: 'NUMBER', value: dx2}); - ops.push({name: 'dy2', type: 'NUMBER', value: dy2}); - ops.push({name: 'dx', type: 'NUMBER', value: dx}); - ops.push({name: 'dy', type: 'NUMBER', value: dy}); - ops.push({name: 'rrcurveto', type: 'OP', value: 8}); - x = Math.round(cmd.x); - y = Math.round(cmd.y); - } - - // Contours are closed automatically. - - } - - ops.push({name: 'endchar', type: 'OP', value: 14}); - return ops; -} - -function makeCharStringsIndex(glyphs) { - var t = new table.Table('CharStrings INDEX', [ - {name: 'charStrings', type: 'INDEX', value: []} - ]); - - for (var i = 0; i < glyphs.length; i += 1) { - var glyph = glyphs.get(i); - var ops = glyphToOps(glyph); - t.charStrings.push({name: glyph.name, type: 'CHARSTRING', value: ops}); - } - - return t; -} - -function makePrivateDict(attrs, strings) { - var t = new table.Table('Private DICT', [ - {name: 'dict', type: 'DICT', value: {}} - ]); - t.dict = makeDict(PRIVATE_DICT_META, attrs, strings); - return t; -} - -function makePrivateDictIndex(privateDict) { - var t = new table.Table('Private DICT INDEX', [ - {name: 'privateDicts', type: 'INDEX', value: []} - ]); - t.privateDicts = [{name: 'privateDict_0', type: 'TABLE', value: privateDict}]; - return t; -} - -function makeCFFTable(glyphs, options) { - var t = new table.Table('CFF ', [ - {name: 'header', type: 'TABLE'}, - {name: 'nameIndex', type: 'TABLE'}, - {name: 'topDictIndex', type: 'TABLE'}, - {name: 'stringIndex', type: 'TABLE'}, - {name: 'globalSubrIndex', type: 'TABLE'}, - {name: 'charsets', type: 'TABLE'}, - {name: 'charStringsIndex', type: 'TABLE'}, - {name: 'privateDictIndex', type: 'TABLE'} - ]); - - var fontScale = 1 / options.unitsPerEm; - // We use non-zero values for the offsets so that the DICT encodes them. - // This is important because the size of the Top DICT plays a role in offset calculation, - // and the size shouldn't change after we've written correct offsets. - var attrs = { - version: options.version, - fullName: options.fullName, - familyName: options.familyName, - weight: options.weightName, - fontMatrix: [fontScale, 0, 0, fontScale, 0, 0], - charset: 999, - encoding: 0, - charStrings: 999, - private: [0, 999] - }; - - var privateAttrs = {}; - - var glyphNames = []; - var glyph; - - // Skip first glyph (.notdef) - for (var i = 1; i < glyphs.length; i += 1) { - glyph = glyphs.get(i); - glyphNames.push(glyph.name); - } - - var strings = []; - - t.header = makeHeader(); - t.nameIndex = makeNameIndex([options.postScriptName]); - var topDict = makeTopDict(attrs, strings); - t.topDictIndex = makeTopDictIndex(topDict); - t.globalSubrIndex = makeGlobalSubrIndex(); - t.charsets = makeCharsets(glyphNames, strings); - t.charStringsIndex = makeCharStringsIndex(glyphs); - var privateDict = makePrivateDict(privateAttrs, strings); - t.privateDictIndex = makePrivateDictIndex(privateDict); - - // Needs to come at the end, to encode all custom strings used in the font. - t.stringIndex = makeStringIndex(strings); - - var startOffset = t.header.sizeOf() + - t.nameIndex.sizeOf() + - t.topDictIndex.sizeOf() + - t.stringIndex.sizeOf() + - t.globalSubrIndex.sizeOf(); - attrs.charset = startOffset; - - // We use the CFF standard encoding; proper encoding will be handled in cmap. - attrs.encoding = 0; - attrs.charStrings = attrs.charset + t.charsets.sizeOf(); - attrs.private[1] = attrs.charStrings + t.charStringsIndex.sizeOf(); - - // Recreate the Top DICT INDEX with the correct offsets. - topDict = makeTopDict(attrs, strings); - t.topDictIndex = makeTopDictIndex(topDict); - - return t; -} - -exports.parse = parseCFFTable; -exports.make = makeCFFTable; - -},{"../encoding":4,"../glyphset":7,"../parse":9,"../path":10,"../table":11}],13:[function(_dereq_,module,exports){ -// The `cmap` table stores the mappings from characters to glyphs. -// https://www.microsoft.com/typography/OTSPEC/cmap.htm - -'use strict'; - -var check = _dereq_('../check'); -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// Parse the `cmap` table. This table stores the mappings from characters to glyphs. -// There are many available formats, but we only support the Windows format 4. -// This function returns a `CmapEncoding` object or null if no supported format could be found. -function parseCmapTable(data, start) { - var i; - var cmap = {}; - cmap.version = parse.getUShort(data, start); - check.argument(cmap.version === 0, 'cmap table version should be 0.'); - - // The cmap table can contain many sub-tables, each with their own format. - // We're only interested in a "platform 3" table. This is a Windows format. - cmap.numTables = parse.getUShort(data, start + 2); - var offset = -1; - for (i = 0; i < cmap.numTables; i += 1) { - var platformId = parse.getUShort(data, start + 4 + (i * 8)); - var encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2); - if (platformId === 3 && (encodingId === 1 || encodingId === 0)) { - offset = parse.getULong(data, start + 4 + (i * 8) + 4); - break; - } - } - - if (offset === -1) { - // There is no cmap table in the font that we support, so return null. - // This font will be marked as unsupported. - return null; - } - - var p = new parse.Parser(data, start + offset); - cmap.format = p.parseUShort(); - check.argument(cmap.format === 4, 'Only format 4 cmap tables are supported.'); - - // Length in bytes of the sub-tables. - cmap.length = p.parseUShort(); - cmap.language = p.parseUShort(); - - // segCount is stored x 2. - var segCount; - cmap.segCount = segCount = p.parseUShort() >> 1; - - // Skip searchRange, entrySelector, rangeShift. - p.skip('uShort', 3); - - // The "unrolled" mapping from character codes to glyph indices. - cmap.glyphIndexMap = {}; - - var endCountParser = new parse.Parser(data, start + offset + 14); - var startCountParser = new parse.Parser(data, start + offset + 16 + segCount * 2); - var idDeltaParser = new parse.Parser(data, start + offset + 16 + segCount * 4); - var idRangeOffsetParser = new parse.Parser(data, start + offset + 16 + segCount * 6); - var glyphIndexOffset = start + offset + 16 + segCount * 8; - for (i = 0; i < segCount - 1; i += 1) { - var glyphIndex; - var endCount = endCountParser.parseUShort(); - var startCount = startCountParser.parseUShort(); - var idDelta = idDeltaParser.parseShort(); - var idRangeOffset = idRangeOffsetParser.parseUShort(); - for (var c = startCount; c <= endCount; c += 1) { - if (idRangeOffset !== 0) { - // The idRangeOffset is relative to the current position in the idRangeOffset array. - // Take the current offset in the idRangeOffset array. - glyphIndexOffset = (idRangeOffsetParser.offset + idRangeOffsetParser.relativeOffset - 2); - - // Add the value of the idRangeOffset, which will move us into the glyphIndex array. - glyphIndexOffset += idRangeOffset; - - // Then add the character index of the current segment, multiplied by 2 for USHORTs. - glyphIndexOffset += (c - startCount) * 2; - glyphIndex = parse.getUShort(data, glyphIndexOffset); - if (glyphIndex !== 0) { - glyphIndex = (glyphIndex + idDelta) & 0xFFFF; - } - } else { - glyphIndex = (c + idDelta) & 0xFFFF; - } - - cmap.glyphIndexMap[c] = glyphIndex; - } - } - - return cmap; -} - -function addSegment(t, code, glyphIndex) { - t.segments.push({ - end: code, - start: code, - delta: -(code - glyphIndex), - offset: 0 - }); -} - -function addTerminatorSegment(t) { - t.segments.push({ - end: 0xFFFF, - start: 0xFFFF, - delta: 1, - offset: 0 - }); -} - -function makeCmapTable(glyphs) { - var i; - var t = new table.Table('cmap', [ - {name: 'version', type: 'USHORT', value: 0}, - {name: 'numTables', type: 'USHORT', value: 1}, - {name: 'platformID', type: 'USHORT', value: 3}, - {name: 'encodingID', type: 'USHORT', value: 1}, - {name: 'offset', type: 'ULONG', value: 12}, - {name: 'format', type: 'USHORT', value: 4}, - {name: 'length', type: 'USHORT', value: 0}, - {name: 'language', type: 'USHORT', value: 0}, - {name: 'segCountX2', type: 'USHORT', value: 0}, - {name: 'searchRange', type: 'USHORT', value: 0}, - {name: 'entrySelector', type: 'USHORT', value: 0}, - {name: 'rangeShift', type: 'USHORT', value: 0} - ]); - - t.segments = []; - for (i = 0; i < glyphs.length; i += 1) { - var glyph = glyphs.get(i); - for (var j = 0; j < glyph.unicodes.length; j += 1) { - addSegment(t, glyph.unicodes[j], i); - } - - t.segments = t.segments.sort(function(a, b) { - return a.start - b.start; - }); - } - - addTerminatorSegment(t); - - var segCount; - segCount = t.segments.length; - t.segCountX2 = segCount * 2; - t.searchRange = Math.pow(2, Math.floor(Math.log(segCount) / Math.log(2))) * 2; - t.entrySelector = Math.log(t.searchRange / 2) / Math.log(2); - t.rangeShift = t.segCountX2 - t.searchRange; - - // Set up parallel segment arrays. - var endCounts = []; - var startCounts = []; - var idDeltas = []; - var idRangeOffsets = []; - var glyphIds = []; - - for (i = 0; i < segCount; i += 1) { - var segment = t.segments[i]; - endCounts = endCounts.concat({name: 'end_' + i, type: 'USHORT', value: segment.end}); - startCounts = startCounts.concat({name: 'start_' + i, type: 'USHORT', value: segment.start}); - idDeltas = idDeltas.concat({name: 'idDelta_' + i, type: 'SHORT', value: segment.delta}); - idRangeOffsets = idRangeOffsets.concat({name: 'idRangeOffset_' + i, type: 'USHORT', value: segment.offset}); - if (segment.glyphId !== undefined) { - glyphIds = glyphIds.concat({name: 'glyph_' + i, type: 'USHORT', value: segment.glyphId}); - } - } - - t.fields = t.fields.concat(endCounts); - t.fields.push({name: 'reservedPad', type: 'USHORT', value: 0}); - t.fields = t.fields.concat(startCounts); - t.fields = t.fields.concat(idDeltas); - t.fields = t.fields.concat(idRangeOffsets); - t.fields = t.fields.concat(glyphIds); - - t.length = 14 + // Subtable header - endCounts.length * 2 + - 2 + // reservedPad - startCounts.length * 2 + - idDeltas.length * 2 + - idRangeOffsets.length * 2 + - glyphIds.length * 2; - - return t; -} - -exports.parse = parseCmapTable; -exports.make = makeCmapTable; - -},{"../check":2,"../parse":9,"../table":11}],14:[function(_dereq_,module,exports){ -// The `glyf` table describes the glyphs in TrueType outline format. -// http://www.microsoft.com/typography/otspec/glyf.htm - -'use strict'; - -var check = _dereq_('../check'); -var glyphset = _dereq_('../glyphset'); -var parse = _dereq_('../parse'); -var path = _dereq_('../path'); - -// Parse the coordinate data for a glyph. -function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask, sameBitMask) { - var v; - if ((flag & shortVectorBitMask) > 0) { - // The coordinate is 1 byte long. - v = p.parseByte(); - // The `same` bit is re-used for short values to signify the sign of the value. - if ((flag & sameBitMask) === 0) { - v = -v; - } - - v = previousValue + v; - } else { - // The coordinate is 2 bytes long. - // If the `same` bit is set, the coordinate is the same as the previous coordinate. - if ((flag & sameBitMask) > 0) { - v = previousValue; - } else { - // Parse the coordinate as a signed 16-bit delta value. - v = previousValue + p.parseShort(); - } - } - - return v; -} - -// Parse a TrueType glyph. -function parseGlyph(glyph, data, start) { - var p = new parse.Parser(data, start); - glyph.numberOfContours = p.parseShort(); - glyph.xMin = p.parseShort(); - glyph.yMin = p.parseShort(); - glyph.xMax = p.parseShort(); - glyph.yMax = p.parseShort(); - var flags; - var flag; - if (glyph.numberOfContours > 0) { - var i; - // This glyph is not a composite. - var endPointIndices = glyph.endPointIndices = []; - for (i = 0; i < glyph.numberOfContours; i += 1) { - endPointIndices.push(p.parseUShort()); - } - - glyph.instructionLength = p.parseUShort(); - glyph.instructions = []; - for (i = 0; i < glyph.instructionLength; i += 1) { - glyph.instructions.push(p.parseByte()); - } - - var numberOfCoordinates = endPointIndices[endPointIndices.length - 1] + 1; - flags = []; - for (i = 0; i < numberOfCoordinates; i += 1) { - flag = p.parseByte(); - flags.push(flag); - // If bit 3 is set, we repeat this flag n times, where n is the next byte. - if ((flag & 8) > 0) { - var repeatCount = p.parseByte(); - for (var j = 0; j < repeatCount; j += 1) { - flags.push(flag); - i += 1; - } - } - } - - check.argument(flags.length === numberOfCoordinates, 'Bad flags.'); - - if (endPointIndices.length > 0) { - var points = []; - var point; - // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0. - if (numberOfCoordinates > 0) { - for (i = 0; i < numberOfCoordinates; i += 1) { - flag = flags[i]; - point = {}; - point.onCurve = !!(flag & 1); - point.lastPointOfContour = endPointIndices.indexOf(i) >= 0; - points.push(point); - } - - var px = 0; - for (i = 0; i < numberOfCoordinates; i += 1) { - flag = flags[i]; - point = points[i]; - point.x = parseGlyphCoordinate(p, flag, px, 2, 16); - px = point.x; - } - - var py = 0; - for (i = 0; i < numberOfCoordinates; i += 1) { - flag = flags[i]; - point = points[i]; - point.y = parseGlyphCoordinate(p, flag, py, 4, 32); - py = point.y; - } - } - - glyph.points = points; - } else { - glyph.points = []; - } - } else if (glyph.numberOfContours === 0) { - glyph.points = []; - } else { - glyph.isComposite = true; - glyph.points = []; - glyph.components = []; - var moreComponents = true; - while (moreComponents) { - flags = p.parseUShort(); - var component = { - glyphIndex: p.parseUShort(), - xScale: 1, - scale01: 0, - scale10: 0, - yScale: 1, - dx: 0, - dy: 0 - }; - if ((flags & 1) > 0) { - // The arguments are words - component.dx = p.parseShort(); - component.dy = p.parseShort(); - } else { - // The arguments are bytes - component.dx = p.parseChar(); - component.dy = p.parseChar(); - } - - if ((flags & 8) > 0) { - // We have a scale - component.xScale = component.yScale = p.parseF2Dot14(); - } else if ((flags & 64) > 0) { - // We have an X / Y scale - component.xScale = p.parseF2Dot14(); - component.yScale = p.parseF2Dot14(); - } else if ((flags & 128) > 0) { - // We have a 2x2 transformation - component.xScale = p.parseF2Dot14(); - component.scale01 = p.parseF2Dot14(); - component.scale10 = p.parseF2Dot14(); - component.yScale = p.parseF2Dot14(); - } - - glyph.components.push(component); - moreComponents = !!(flags & 32); - } - } -} - -// Transform an array of points and return a new array. -function transformPoints(points, transform) { - var newPoints = []; - for (var i = 0; i < points.length; i += 1) { - var pt = points[i]; - var newPt = { - x: transform.xScale * pt.x + transform.scale01 * pt.y + transform.dx, - y: transform.scale10 * pt.x + transform.yScale * pt.y + transform.dy, - onCurve: pt.onCurve, - lastPointOfContour: pt.lastPointOfContour - }; - newPoints.push(newPt); - } - - return newPoints; -} - -function getContours(points) { - var contours = []; - var currentContour = []; - for (var i = 0; i < points.length; i += 1) { - var pt = points[i]; - currentContour.push(pt); - if (pt.lastPointOfContour) { - contours.push(currentContour); - currentContour = []; - } - } - - check.argument(currentContour.length === 0, 'There are still points left in the current contour.'); - return contours; -} - -// Convert the TrueType glyph outline to a Path. -function getPath(points) { - var p = new path.Path(); - if (!points) { - return p; - } - - var contours = getContours(points); - for (var i = 0; i < contours.length; i += 1) { - var contour = contours[i]; - var firstPt = contour[0]; - var lastPt = contour[contour.length - 1]; - var curvePt; - var realFirstPoint; - if (firstPt.onCurve) { - curvePt = null; - // The first point will be consumed by the moveTo command, - // so skip it in the loop. - realFirstPoint = true; - } else { - if (lastPt.onCurve) { - // If the first point is off-curve and the last point is on-curve, - // start at the last point. - firstPt = lastPt; - } else { - // If both first and last points are off-curve, start at their middle. - firstPt = { x: (firstPt.x + lastPt.x) / 2, y: (firstPt.y + lastPt.y) / 2 }; - } - - curvePt = firstPt; - // The first point is synthesized, so don't skip the real first point. - realFirstPoint = false; - } - - p.moveTo(firstPt.x, firstPt.y); - - for (var j = realFirstPoint ? 1 : 0; j < contour.length; j += 1) { - var pt = contour[j]; - var prevPt = j === 0 ? firstPt : contour[j - 1]; - if (prevPt.onCurve && pt.onCurve) { - // This is a straight line. - p.lineTo(pt.x, pt.y); - } else if (prevPt.onCurve && !pt.onCurve) { - curvePt = pt; - } else if (!prevPt.onCurve && !pt.onCurve) { - var midPt = { x: (prevPt.x + pt.x) / 2, y: (prevPt.y + pt.y) / 2 }; - p.quadraticCurveTo(prevPt.x, prevPt.y, midPt.x, midPt.y); - curvePt = pt; - } else if (!prevPt.onCurve && pt.onCurve) { - // Previous point off-curve, this point on-curve. - p.quadraticCurveTo(curvePt.x, curvePt.y, pt.x, pt.y); - curvePt = null; - } else { - throw new Error('Invalid state.'); - } - } - - if (firstPt !== lastPt) { - // Connect the last and first points - if (curvePt) { - p.quadraticCurveTo(curvePt.x, curvePt.y, firstPt.x, firstPt.y); - } else { - p.lineTo(firstPt.x, firstPt.y); - } - } - } - - p.closePath(); - return p; -} - -function buildPath(glyphs, glyph) { - if (glyph.isComposite) { - for (var j = 0; j < glyph.components.length; j += 1) { - var component = glyph.components[j]; - var componentGlyph = glyphs.get(component.glyphIndex); - if (componentGlyph.points) { - var transformedPoints = transformPoints(componentGlyph.points, component); - glyph.points = glyph.points.concat(transformedPoints); - } - } - } - - return getPath(glyph.points); -} - -// Parse all the glyphs according to the offsets from the `loca` table. -function parseGlyfTable(data, start, loca, font) { - var glyphs = new glyphset.GlyphSet(font); - var i; - - // The last element of the loca table is invalid. - for (i = 0; i < loca.length - 1; i += 1) { - var offset = loca[i]; - var nextOffset = loca[i + 1]; - if (offset !== nextOffset) { - glyphs.push(i, glyphset.ttfGlyphLoader(font, i, parseGlyph, data, start + offset, buildPath)); - } else { - glyphs.push(i, glyphset.glyphLoader(font, i)); - } - } - - return glyphs; -} - -exports.parse = parseGlyfTable; - -},{"../check":2,"../glyphset":7,"../parse":9,"../path":10}],15:[function(_dereq_,module,exports){ -// The `GPOS` table contains kerning pairs, among other things. -// https://www.microsoft.com/typography/OTSPEC/gpos.htm - -'use strict'; - -var check = _dereq_('../check'); -var parse = _dereq_('../parse'); - -// Parse ScriptList and FeatureList tables of GPOS, GSUB, GDEF, BASE, JSTF tables. -// These lists are unused by now, this function is just the basis for a real parsing. -function parseTaggedListTable(data, start) { - var p = new parse.Parser(data, start); - var n = p.parseUShort(); - var list = []; - for (var i = 0; i < n; i++) { - list[p.parseTag()] = { offset: p.parseUShort() }; - } - - return list; -} - -// Parse a coverage table in a GSUB, GPOS or GDEF table. -// Format 1 is a simple list of glyph ids, -// Format 2 is a list of ranges. It is expanded in a list of glyphs, maybe not the best idea. -function parseCoverageTable(data, start) { - var p = new parse.Parser(data, start); - var format = p.parseUShort(); - var count = p.parseUShort(); - if (format === 1) { - return p.parseUShortList(count); - } - else if (format === 2) { - var coverage = []; - for (; count--;) { - var begin = p.parseUShort(); - var end = p.parseUShort(); - var index = p.parseUShort(); - for (var i = begin; i <= end; i++) { - coverage[index++] = i; - } - } - - return coverage; - } -} - -// Parse a Class Definition Table in a GSUB, GPOS or GDEF table. -// Returns a function that gets a class value from a glyph ID. -function parseClassDefTable(data, start) { - var p = new parse.Parser(data, start); - var format = p.parseUShort(); - if (format === 1) { - // Format 1 specifies a range of consecutive glyph indices, one class per glyph ID. - var startGlyph = p.parseUShort(); - var glyphCount = p.parseUShort(); - var classes = p.parseUShortList(glyphCount); - return function(glyphID) { - return classes[glyphID - startGlyph] || 0; - }; - } - else if (format === 2) { - // Format 2 defines multiple groups of glyph indices that belong to the same class. - var rangeCount = p.parseUShort(); - var startGlyphs = []; - var endGlyphs = []; - var classValues = []; - for (var i = 0; i < rangeCount; i++) { - startGlyphs[i] = p.parseUShort(); - endGlyphs[i] = p.parseUShort(); - classValues[i] = p.parseUShort(); - } - - return function(glyphID) { - var l = 0; - var r = startGlyphs.length - 1; - while (l < r) { - var c = (l + r + 1) >> 1; - if (glyphID < startGlyphs[c]) { - r = c - 1; - } else { - l = c; - } - } - - if (startGlyphs[l] <= glyphID && glyphID <= endGlyphs[l]) { - return classValues[l] || 0; - } - - return 0; - }; - } -} - -// Parse a pair adjustment positioning subtable, format 1 or format 2 -// The subtable is returned in the form of a lookup function. -function parsePairPosSubTable(data, start) { - var p = new parse.Parser(data, start); - // This part is common to format 1 and format 2 subtables - var format = p.parseUShort(); - var coverageOffset = p.parseUShort(); - var coverage = parseCoverageTable(data, start + coverageOffset); - // valueFormat 4: XAdvance only, 1: XPlacement only, 0: no ValueRecord for second glyph - // Only valueFormat1=4 and valueFormat2=0 is supported. - var valueFormat1 = p.parseUShort(); - var valueFormat2 = p.parseUShort(); - var value1; - var value2; - if (valueFormat1 !== 4 || valueFormat2 !== 0) return; - var sharedPairSets = {}; - if (format === 1) { - // Pair Positioning Adjustment: Format 1 - var pairSetCount = p.parseUShort(); - var pairSet = []; - // Array of offsets to PairSet tables-from beginning of PairPos subtable-ordered by Coverage Index - var pairSetOffsets = p.parseOffset16List(pairSetCount); - for (var firstGlyph = 0; firstGlyph < pairSetCount; firstGlyph++) { - var pairSetOffset = pairSetOffsets[firstGlyph]; - var sharedPairSet = sharedPairSets[pairSetOffset]; - if (!sharedPairSet) { - // Parse a pairset table in a pair adjustment subtable format 1 - sharedPairSet = {}; - p.relativeOffset = pairSetOffset; - var pairValueCount = p.parseUShort(); - for (; pairValueCount--;) { - var secondGlyph = p.parseUShort(); - if (valueFormat1) value1 = p.parseShort(); - if (valueFormat2) value2 = p.parseShort(); - // We only support valueFormat1 = 4 and valueFormat2 = 0, - // so value1 is the XAdvance and value2 is empty. - sharedPairSet[secondGlyph] = value1; - } - } - - pairSet[coverage[firstGlyph]] = sharedPairSet; - } - - return function(leftGlyph, rightGlyph) { - var pairs = pairSet[leftGlyph]; - if (pairs) return pairs[rightGlyph]; - }; - } - else if (format === 2) { - // Pair Positioning Adjustment: Format 2 - var classDef1Offset = p.parseUShort(); - var classDef2Offset = p.parseUShort(); - var class1Count = p.parseUShort(); - var class2Count = p.parseUShort(); - var getClass1 = parseClassDefTable(data, start + classDef1Offset); - var getClass2 = parseClassDefTable(data, start + classDef2Offset); - - // Parse kerning values by class pair. - var kerningMatrix = []; - for (var i = 0; i < class1Count; i++) { - var kerningRow = kerningMatrix[i] = []; - for (var j = 0; j < class2Count; j++) { - if (valueFormat1) value1 = p.parseShort(); - if (valueFormat2) value2 = p.parseShort(); - // We only support valueFormat1 = 4 and valueFormat2 = 0, - // so value1 is the XAdvance and value2 is empty. - kerningRow[j] = value1; - } - } - - // Convert coverage list to a hash - var covered = {}; - for (i = 0; i < coverage.length; i++) covered[coverage[i]] = 1; - - // Get the kerning value for a specific glyph pair. - return function(leftGlyph, rightGlyph) { - if (!covered[leftGlyph]) return; - var class1 = getClass1(leftGlyph); - var class2 = getClass2(rightGlyph); - var kerningRow = kerningMatrix[class1]; - - if (kerningRow) { - return kerningRow[class2]; - } - }; - } -} - -// Parse a LookupTable (present in of GPOS, GSUB, GDEF, BASE, JSTF tables). -function parseLookupTable(data, start) { - var p = new parse.Parser(data, start); - var lookupType = p.parseUShort(); - var lookupFlag = p.parseUShort(); - var useMarkFilteringSet = lookupFlag & 0x10; - var subTableCount = p.parseUShort(); - var subTableOffsets = p.parseOffset16List(subTableCount); - var table = { - lookupType: lookupType, - lookupFlag: lookupFlag, - markFilteringSet: useMarkFilteringSet ? p.parseUShort() : -1 - }; - // LookupType 2, Pair adjustment - if (lookupType === 2) { - var subtables = []; - for (var i = 0; i < subTableCount; i++) { - subtables.push(parsePairPosSubTable(data, start + subTableOffsets[i])); - } - // Return a function which finds the kerning values in the subtables. - table.getKerningValue = function(leftGlyph, rightGlyph) { - for (var i = subtables.length; i--;) { - var value = subtables[i](leftGlyph, rightGlyph); - if (value !== undefined) return value; - } - - return 0; - }; - } - - return table; -} - -// Parse the `GPOS` table which contains, among other things, kerning pairs. -// https://www.microsoft.com/typography/OTSPEC/gpos.htm -function parseGposTable(data, start, font) { - var p = new parse.Parser(data, start); - var tableVersion = p.parseFixed(); - check.argument(tableVersion === 1, 'Unsupported GPOS table version.'); - - // ScriptList and FeatureList - ignored for now - parseTaggedListTable(data, start + p.parseUShort()); - // 'kern' is the feature we are looking for. - parseTaggedListTable(data, start + p.parseUShort()); - - // LookupList - var lookupListOffset = p.parseUShort(); - p.relativeOffset = lookupListOffset; - var lookupCount = p.parseUShort(); - var lookupTableOffsets = p.parseOffset16List(lookupCount); - var lookupListAbsoluteOffset = start + lookupListOffset; - for (var i = 0; i < lookupCount; i++) { - var table = parseLookupTable(data, lookupListAbsoluteOffset + lookupTableOffsets[i]); - if (table.lookupType === 2 && !font.getGposKerningValue) font.getGposKerningValue = table.getKerningValue; - } -} - -exports.parse = parseGposTable; - -},{"../check":2,"../parse":9}],16:[function(_dereq_,module,exports){ -// The `head` table contains global information about the font. -// https://www.microsoft.com/typography/OTSPEC/head.htm - -'use strict'; - -var check = _dereq_('../check'); -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// Parse the header `head` table -function parseHeadTable(data, start) { - var head = {}; - var p = new parse.Parser(data, start); - head.version = p.parseVersion(); - head.fontRevision = Math.round(p.parseFixed() * 1000) / 1000; - head.checkSumAdjustment = p.parseULong(); - head.magicNumber = p.parseULong(); - check.argument(head.magicNumber === 0x5F0F3CF5, 'Font header has wrong magic number.'); - head.flags = p.parseUShort(); - head.unitsPerEm = p.parseUShort(); - head.created = p.parseLongDateTime(); - head.modified = p.parseLongDateTime(); - head.xMin = p.parseShort(); - head.yMin = p.parseShort(); - head.xMax = p.parseShort(); - head.yMax = p.parseShort(); - head.macStyle = p.parseUShort(); - head.lowestRecPPEM = p.parseUShort(); - head.fontDirectionHint = p.parseShort(); - head.indexToLocFormat = p.parseShort(); // 50 - head.glyphDataFormat = p.parseShort(); - return head; -} - -function makeHeadTable(options) { - return new table.Table('head', [ - {name: 'version', type: 'FIXED', value: 0x00010000}, - {name: 'fontRevision', type: 'FIXED', value: 0x00010000}, - {name: 'checkSumAdjustment', type: 'ULONG', value: 0}, - {name: 'magicNumber', type: 'ULONG', value: 0x5F0F3CF5}, - {name: 'flags', type: 'USHORT', value: 0}, - {name: 'unitsPerEm', type: 'USHORT', value: 1000}, - {name: 'created', type: 'LONGDATETIME', value: 0}, - {name: 'modified', type: 'LONGDATETIME', value: 0}, - {name: 'xMin', type: 'SHORT', value: 0}, - {name: 'yMin', type: 'SHORT', value: 0}, - {name: 'xMax', type: 'SHORT', value: 0}, - {name: 'yMax', type: 'SHORT', value: 0}, - {name: 'macStyle', type: 'USHORT', value: 0}, - {name: 'lowestRecPPEM', type: 'USHORT', value: 0}, - {name: 'fontDirectionHint', type: 'SHORT', value: 2}, - {name: 'indexToLocFormat', type: 'SHORT', value: 0}, - {name: 'glyphDataFormat', type: 'SHORT', value: 0} - ], options); -} - -exports.parse = parseHeadTable; -exports.make = makeHeadTable; - -},{"../check":2,"../parse":9,"../table":11}],17:[function(_dereq_,module,exports){ -// The `hhea` table contains information for horizontal layout. -// https://www.microsoft.com/typography/OTSPEC/hhea.htm - -'use strict'; - -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// Parse the horizontal header `hhea` table -function parseHheaTable(data, start) { - var hhea = {}; - var p = new parse.Parser(data, start); - hhea.version = p.parseVersion(); - hhea.ascender = p.parseShort(); - hhea.descender = p.parseShort(); - hhea.lineGap = p.parseShort(); - hhea.advanceWidthMax = p.parseUShort(); - hhea.minLeftSideBearing = p.parseShort(); - hhea.minRightSideBearing = p.parseShort(); - hhea.xMaxExtent = p.parseShort(); - hhea.caretSlopeRise = p.parseShort(); - hhea.caretSlopeRun = p.parseShort(); - hhea.caretOffset = p.parseShort(); - p.relativeOffset += 8; - hhea.metricDataFormat = p.parseShort(); - hhea.numberOfHMetrics = p.parseUShort(); - return hhea; -} - -function makeHheaTable(options) { - return new table.Table('hhea', [ - {name: 'version', type: 'FIXED', value: 0x00010000}, - {name: 'ascender', type: 'FWORD', value: 0}, - {name: 'descender', type: 'FWORD', value: 0}, - {name: 'lineGap', type: 'FWORD', value: 0}, - {name: 'advanceWidthMax', type: 'UFWORD', value: 0}, - {name: 'minLeftSideBearing', type: 'FWORD', value: 0}, - {name: 'minRightSideBearing', type: 'FWORD', value: 0}, - {name: 'xMaxExtent', type: 'FWORD', value: 0}, - {name: 'caretSlopeRise', type: 'SHORT', value: 1}, - {name: 'caretSlopeRun', type: 'SHORT', value: 0}, - {name: 'caretOffset', type: 'SHORT', value: 0}, - {name: 'reserved1', type: 'SHORT', value: 0}, - {name: 'reserved2', type: 'SHORT', value: 0}, - {name: 'reserved3', type: 'SHORT', value: 0}, - {name: 'reserved4', type: 'SHORT', value: 0}, - {name: 'metricDataFormat', type: 'SHORT', value: 0}, - {name: 'numberOfHMetrics', type: 'USHORT', value: 0} - ], options); -} - -exports.parse = parseHheaTable; -exports.make = makeHheaTable; - -},{"../parse":9,"../table":11}],18:[function(_dereq_,module,exports){ -// The `hmtx` table contains the horizontal metrics for all glyphs. -// https://www.microsoft.com/typography/OTSPEC/hmtx.htm - -'use strict'; - -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// Parse the `hmtx` table, which contains the horizontal metrics for all glyphs. -// This function augments the glyph array, adding the advanceWidth and leftSideBearing to each glyph. -function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) { - var advanceWidth; - var leftSideBearing; - var p = new parse.Parser(data, start); - for (var i = 0; i < numGlyphs; i += 1) { - // If the font is monospaced, only one entry is needed. This last entry applies to all subsequent glyphs. - if (i < numMetrics) { - advanceWidth = p.parseUShort(); - leftSideBearing = p.parseShort(); - } - - var glyph = glyphs.get(i); - glyph.advanceWidth = advanceWidth; - glyph.leftSideBearing = leftSideBearing; - } -} - -function makeHmtxTable(glyphs) { - var t = new table.Table('hmtx', []); - for (var i = 0; i < glyphs.length; i += 1) { - var glyph = glyphs.get(i); - var advanceWidth = glyph.advanceWidth || 0; - var leftSideBearing = glyph.leftSideBearing || 0; - t.fields.push({name: 'advanceWidth_' + i, type: 'USHORT', value: advanceWidth}); - t.fields.push({name: 'leftSideBearing_' + i, type: 'SHORT', value: leftSideBearing}); - } - - return t; -} - -exports.parse = parseHmtxTable; -exports.make = makeHmtxTable; - -},{"../parse":9,"../table":11}],19:[function(_dereq_,module,exports){ -// The `kern` table contains kerning pairs. -// Note that some fonts use the GPOS OpenType layout table to specify kerning. -// https://www.microsoft.com/typography/OTSPEC/kern.htm - -'use strict'; - -var check = _dereq_('../check'); -var parse = _dereq_('../parse'); - -// Parse the `kern` table which contains kerning pairs. -function parseKernTable(data, start) { - var pairs = {}; - var p = new parse.Parser(data, start); - var tableVersion = p.parseUShort(); - check.argument(tableVersion === 0, 'Unsupported kern table version.'); - // Skip nTables. - p.skip('uShort', 1); - var subTableVersion = p.parseUShort(); - check.argument(subTableVersion === 0, 'Unsupported kern sub-table version.'); - // Skip subTableLength, subTableCoverage - p.skip('uShort', 2); - var nPairs = p.parseUShort(); - // Skip searchRange, entrySelector, rangeShift. - p.skip('uShort', 3); - for (var i = 0; i < nPairs; i += 1) { - var leftIndex = p.parseUShort(); - var rightIndex = p.parseUShort(); - var value = p.parseShort(); - pairs[leftIndex + ',' + rightIndex] = value; - } - - return pairs; -} - -exports.parse = parseKernTable; - -},{"../check":2,"../parse":9}],20:[function(_dereq_,module,exports){ -// The `loca` table stores the offsets to the locations of the glyphs in the font. -// https://www.microsoft.com/typography/OTSPEC/loca.htm - -'use strict'; - -var parse = _dereq_('../parse'); - -// Parse the `loca` table. This table stores the offsets to the locations of the glyphs in the font, -// relative to the beginning of the glyphData table. -// The number of glyphs stored in the `loca` table is specified in the `maxp` table (under numGlyphs) -// The loca table has two versions: a short version where offsets are stored as uShorts, and a long -// version where offsets are stored as uLongs. The `head` table specifies which version to use -// (under indexToLocFormat). -function parseLocaTable(data, start, numGlyphs, shortVersion) { - var p = new parse.Parser(data, start); - var parseFn = shortVersion ? p.parseUShort : p.parseULong; - // There is an extra entry after the last index element to compute the length of the last glyph. - // That's why we use numGlyphs + 1. - var glyphOffsets = []; - for (var i = 0; i < numGlyphs + 1; i += 1) { - var glyphOffset = parseFn.call(p); - if (shortVersion) { - // The short table version stores the actual offset divided by 2. - glyphOffset *= 2; - } - - glyphOffsets.push(glyphOffset); - } - - return glyphOffsets; -} - -exports.parse = parseLocaTable; - -},{"../parse":9}],21:[function(_dereq_,module,exports){ -// The `maxp` table establishes the memory requirements for the font. -// We need it just to get the number of glyphs in the font. -// https://www.microsoft.com/typography/OTSPEC/maxp.htm - -'use strict'; - -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// Parse the maximum profile `maxp` table. -function parseMaxpTable(data, start) { - var maxp = {}; - var p = new parse.Parser(data, start); - maxp.version = p.parseVersion(); - maxp.numGlyphs = p.parseUShort(); - if (maxp.version === 1.0) { - maxp.maxPoints = p.parseUShort(); - maxp.maxContours = p.parseUShort(); - maxp.maxCompositePoints = p.parseUShort(); - maxp.maxCompositeContours = p.parseUShort(); - maxp.maxZones = p.parseUShort(); - maxp.maxTwilightPoints = p.parseUShort(); - maxp.maxStorage = p.parseUShort(); - maxp.maxFunctionDefs = p.parseUShort(); - maxp.maxInstructionDefs = p.parseUShort(); - maxp.maxStackElements = p.parseUShort(); - maxp.maxSizeOfInstructions = p.parseUShort(); - maxp.maxComponentElements = p.parseUShort(); - maxp.maxComponentDepth = p.parseUShort(); - } - - return maxp; -} - -function makeMaxpTable(numGlyphs) { - return new table.Table('maxp', [ - {name: 'version', type: 'FIXED', value: 0x00005000}, - {name: 'numGlyphs', type: 'USHORT', value: numGlyphs} - ]); -} - -exports.parse = parseMaxpTable; -exports.make = makeMaxpTable; - -},{"../parse":9,"../table":11}],22:[function(_dereq_,module,exports){ -// The `name` naming table. -// https://www.microsoft.com/typography/OTSPEC/name.htm - -'use strict'; - -var encode = _dereq_('../types').encode; -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// NameIDs for the name table. -var nameTableNames = [ - 'copyright', // 0 - 'fontFamily', // 1 - 'fontSubfamily', // 2 - 'uniqueID', // 3 - 'fullName', // 4 - 'version', // 5 - 'postScriptName', // 6 - 'trademark', // 7 - 'manufacturer', // 8 - 'designer', // 9 - 'description', // 10 - 'manufacturerURL', // 11 - 'designerURL', // 12 - 'licence', // 13 - 'licenceURL', // 14 - 'reserved', // 15 - 'preferredFamily', // 16 - 'preferredSubfamily', // 17 - 'compatibleFullName', // 18 - 'sampleText', // 19 - 'postScriptFindFontName', // 20 - 'wwsFamily', // 21 - 'wwsSubfamily' // 22 -]; - -// Parse the naming `name` table -// Only Windows Unicode English names are supported. -// Format 1 additional fields are not supported -function parseNameTable(data, start) { - var name = {}; - var p = new parse.Parser(data, start); - name.format = p.parseUShort(); - var count = p.parseUShort(); - var stringOffset = p.offset + p.parseUShort(); - var unknownCount = 0; - for (var i = 0; i < count; i++) { - var platformID = p.parseUShort(); - var encodingID = p.parseUShort(); - var languageID = p.parseUShort(); - var nameID = p.parseUShort(); - var property = nameTableNames[nameID]; - var byteLength = p.parseUShort(); - var offset = p.parseUShort(); - // platformID - encodingID - languageID standard combinations : - // 1 - 0 - 0 : Macintosh, Roman, English - // 3 - 1 - 0x409 : Windows, Unicode BMP (UCS-2), en-US - if (platformID === 3 && encodingID === 1 && languageID === 0x409) { - var codePoints = []; - var length = byteLength / 2; - for (var j = 0; j < length; j++, offset += 2) { - codePoints[j] = parse.getShort(data, stringOffset + offset); - } - - var str = String.fromCharCode.apply(null, codePoints); - if (property) { - name[property] = str; - } - else { - unknownCount++; - name['unknown' + unknownCount] = str; - } - } - - } - - if (name.format === 1) { - name.langTagCount = p.parseUShort(); - } - - return name; -} - -function makeNameRecord(platformID, encodingID, languageID, nameID, length, offset) { - return new table.Table('NameRecord', [ - {name: 'platformID', type: 'USHORT', value: platformID}, - {name: 'encodingID', type: 'USHORT', value: encodingID}, - {name: 'languageID', type: 'USHORT', value: languageID}, - {name: 'nameID', type: 'USHORT', value: nameID}, - {name: 'length', type: 'USHORT', value: length}, - {name: 'offset', type: 'USHORT', value: offset} - ]); -} - -function addMacintoshNameRecord(t, recordID, s, offset) { - // Macintosh, Roman, English - var stringBytes = encode.STRING(s); - t.records.push(makeNameRecord(1, 0, 0, recordID, stringBytes.length, offset)); - t.strings.push(stringBytes); - offset += stringBytes.length; - return offset; -} - -function addWindowsNameRecord(t, recordID, s, offset) { - // Windows, Unicode BMP (UCS-2), US English - var utf16Bytes = encode.UTF16(s); - t.records.push(makeNameRecord(3, 1, 0x0409, recordID, utf16Bytes.length, offset)); - t.strings.push(utf16Bytes); - offset += utf16Bytes.length; - return offset; -} - -function makeNameTable(options) { - var t = new table.Table('name', [ - {name: 'format', type: 'USHORT', value: 0}, - {name: 'count', type: 'USHORT', value: 0}, - {name: 'stringOffset', type: 'USHORT', value: 0} - ]); - t.records = []; - t.strings = []; - var offset = 0; - var i; - var s; - // Add Macintosh records first - for (i = 0; i < nameTableNames.length; i += 1) { - if (options[nameTableNames[i]] !== undefined) { - s = options[nameTableNames[i]]; - offset = addMacintoshNameRecord(t, i, s, offset); - } - } - // Then add Windows records - for (i = 0; i < nameTableNames.length; i += 1) { - if (options[nameTableNames[i]] !== undefined) { - s = options[nameTableNames[i]]; - offset = addWindowsNameRecord(t, i, s, offset); - } - } - - t.count = t.records.length; - t.stringOffset = 6 + t.count * 12; - for (i = 0; i < t.records.length; i += 1) { - t.fields.push({name: 'record_' + i, type: 'TABLE', value: t.records[i]}); - } - - for (i = 0; i < t.strings.length; i += 1) { - t.fields.push({name: 'string_' + i, type: 'LITERAL', value: t.strings[i]}); - } - - return t; -} - -exports.parse = parseNameTable; -exports.make = makeNameTable; - -},{"../parse":9,"../table":11,"../types":26}],23:[function(_dereq_,module,exports){ -// The `OS/2` table contains metrics required in OpenType fonts. -// https://www.microsoft.com/typography/OTSPEC/os2.htm - -'use strict'; - -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -var unicodeRanges = [ - {begin: 0x0000, end: 0x007F}, // Basic Latin - {begin: 0x0080, end: 0x00FF}, // Latin-1 Supplement - {begin: 0x0100, end: 0x017F}, // Latin Extended-A - {begin: 0x0180, end: 0x024F}, // Latin Extended-B - {begin: 0x0250, end: 0x02AF}, // IPA Extensions - {begin: 0x02B0, end: 0x02FF}, // Spacing Modifier Letters - {begin: 0x0300, end: 0x036F}, // Combining Diacritical Marks - {begin: 0x0370, end: 0x03FF}, // Greek and Coptic - {begin: 0x2C80, end: 0x2CFF}, // Coptic - {begin: 0x0400, end: 0x04FF}, // Cyrillic - {begin: 0x0530, end: 0x058F}, // Armenian - {begin: 0x0590, end: 0x05FF}, // Hebrew - {begin: 0xA500, end: 0xA63F}, // Vai - {begin: 0x0600, end: 0x06FF}, // Arabic - {begin: 0x07C0, end: 0x07FF}, // NKo - {begin: 0x0900, end: 0x097F}, // Devanagari - {begin: 0x0980, end: 0x09FF}, // Bengali - {begin: 0x0A00, end: 0x0A7F}, // Gurmukhi - {begin: 0x0A80, end: 0x0AFF}, // Gujarati - {begin: 0x0B00, end: 0x0B7F}, // Oriya - {begin: 0x0B80, end: 0x0BFF}, // Tamil - {begin: 0x0C00, end: 0x0C7F}, // Telugu - {begin: 0x0C80, end: 0x0CFF}, // Kannada - {begin: 0x0D00, end: 0x0D7F}, // Malayalam - {begin: 0x0E00, end: 0x0E7F}, // Thai - {begin: 0x0E80, end: 0x0EFF}, // Lao - {begin: 0x10A0, end: 0x10FF}, // Georgian - {begin: 0x1B00, end: 0x1B7F}, // Balinese - {begin: 0x1100, end: 0x11FF}, // Hangul Jamo - {begin: 0x1E00, end: 0x1EFF}, // Latin Extended Additional - {begin: 0x1F00, end: 0x1FFF}, // Greek Extended - {begin: 0x2000, end: 0x206F}, // General Punctuation - {begin: 0x2070, end: 0x209F}, // Superscripts And Subscripts - {begin: 0x20A0, end: 0x20CF}, // Currency Symbol - {begin: 0x20D0, end: 0x20FF}, // Combining Diacritical Marks For Symbols - {begin: 0x2100, end: 0x214F}, // Letterlike Symbols - {begin: 0x2150, end: 0x218F}, // Number Forms - {begin: 0x2190, end: 0x21FF}, // Arrows - {begin: 0x2200, end: 0x22FF}, // Mathematical Operators - {begin: 0x2300, end: 0x23FF}, // Miscellaneous Technical - {begin: 0x2400, end: 0x243F}, // Control Pictures - {begin: 0x2440, end: 0x245F}, // Optical Character Recognition - {begin: 0x2460, end: 0x24FF}, // Enclosed Alphanumerics - {begin: 0x2500, end: 0x257F}, // Box Drawing - {begin: 0x2580, end: 0x259F}, // Block Elements - {begin: 0x25A0, end: 0x25FF}, // Geometric Shapes - {begin: 0x2600, end: 0x26FF}, // Miscellaneous Symbols - {begin: 0x2700, end: 0x27BF}, // Dingbats - {begin: 0x3000, end: 0x303F}, // CJK Symbols And Punctuation - {begin: 0x3040, end: 0x309F}, // Hiragana - {begin: 0x30A0, end: 0x30FF}, // Katakana - {begin: 0x3100, end: 0x312F}, // Bopomofo - {begin: 0x3130, end: 0x318F}, // Hangul Compatibility Jamo - {begin: 0xA840, end: 0xA87F}, // Phags-pa - {begin: 0x3200, end: 0x32FF}, // Enclosed CJK Letters And Months - {begin: 0x3300, end: 0x33FF}, // CJK Compatibility - {begin: 0xAC00, end: 0xD7AF}, // Hangul Syllables - {begin: 0xD800, end: 0xDFFF}, // Non-Plane 0 * - {begin: 0x10900, end: 0x1091F}, // Phoenicia - {begin: 0x4E00, end: 0x9FFF}, // CJK Unified Ideographs - {begin: 0xE000, end: 0xF8FF}, // Private Use Area (plane 0) - {begin: 0x31C0, end: 0x31EF}, // CJK Strokes - {begin: 0xFB00, end: 0xFB4F}, // Alphabetic Presentation Forms - {begin: 0xFB50, end: 0xFDFF}, // Arabic Presentation Forms-A - {begin: 0xFE20, end: 0xFE2F}, // Combining Half Marks - {begin: 0xFE10, end: 0xFE1F}, // Vertical Forms - {begin: 0xFE50, end: 0xFE6F}, // Small Form Variants - {begin: 0xFE70, end: 0xFEFF}, // Arabic Presentation Forms-B - {begin: 0xFF00, end: 0xFFEF}, // Halfwidth And Fullwidth Forms - {begin: 0xFFF0, end: 0xFFFF}, // Specials - {begin: 0x0F00, end: 0x0FFF}, // Tibetan - {begin: 0x0700, end: 0x074F}, // Syriac - {begin: 0x0780, end: 0x07BF}, // Thaana - {begin: 0x0D80, end: 0x0DFF}, // Sinhala - {begin: 0x1000, end: 0x109F}, // Myanmar - {begin: 0x1200, end: 0x137F}, // Ethiopic - {begin: 0x13A0, end: 0x13FF}, // Cherokee - {begin: 0x1400, end: 0x167F}, // Unified Canadian Aboriginal Syllabics - {begin: 0x1680, end: 0x169F}, // Ogham - {begin: 0x16A0, end: 0x16FF}, // Runic - {begin: 0x1780, end: 0x17FF}, // Khmer - {begin: 0x1800, end: 0x18AF}, // Mongolian - {begin: 0x2800, end: 0x28FF}, // Braille Patterns - {begin: 0xA000, end: 0xA48F}, // Yi Syllables - {begin: 0x1700, end: 0x171F}, // Tagalog - {begin: 0x10300, end: 0x1032F}, // Old Italic - {begin: 0x10330, end: 0x1034F}, // Gothic - {begin: 0x10400, end: 0x1044F}, // Deseret - {begin: 0x1D000, end: 0x1D0FF}, // Byzantine Musical Symbols - {begin: 0x1D400, end: 0x1D7FF}, // Mathematical Alphanumeric Symbols - {begin: 0xFF000, end: 0xFFFFD}, // Private Use (plane 15) - {begin: 0xFE00, end: 0xFE0F}, // Variation Selectors - {begin: 0xE0000, end: 0xE007F}, // Tags - {begin: 0x1900, end: 0x194F}, // Limbu - {begin: 0x1950, end: 0x197F}, // Tai Le - {begin: 0x1980, end: 0x19DF}, // New Tai Lue - {begin: 0x1A00, end: 0x1A1F}, // Buginese - {begin: 0x2C00, end: 0x2C5F}, // Glagolitic - {begin: 0x2D30, end: 0x2D7F}, // Tifinagh - {begin: 0x4DC0, end: 0x4DFF}, // Yijing Hexagram Symbols - {begin: 0xA800, end: 0xA82F}, // Syloti Nagri - {begin: 0x10000, end: 0x1007F}, // Linear B Syllabary - {begin: 0x10140, end: 0x1018F}, // Ancient Greek Numbers - {begin: 0x10380, end: 0x1039F}, // Ugaritic - {begin: 0x103A0, end: 0x103DF}, // Old Persian - {begin: 0x10450, end: 0x1047F}, // Shavian - {begin: 0x10480, end: 0x104AF}, // Osmanya - {begin: 0x10800, end: 0x1083F}, // Cypriot Syllabary - {begin: 0x10A00, end: 0x10A5F}, // Kharoshthi - {begin: 0x1D300, end: 0x1D35F}, // Tai Xuan Jing Symbols - {begin: 0x12000, end: 0x123FF}, // Cuneiform - {begin: 0x1D360, end: 0x1D37F}, // Counting Rod Numerals - {begin: 0x1B80, end: 0x1BBF}, // Sundanese - {begin: 0x1C00, end: 0x1C4F}, // Lepcha - {begin: 0x1C50, end: 0x1C7F}, // Ol Chiki - {begin: 0xA880, end: 0xA8DF}, // Saurashtra - {begin: 0xA900, end: 0xA92F}, // Kayah Li - {begin: 0xA930, end: 0xA95F}, // Rejang - {begin: 0xAA00, end: 0xAA5F}, // Cham - {begin: 0x10190, end: 0x101CF}, // Ancient Symbols - {begin: 0x101D0, end: 0x101FF}, // Phaistos Disc - {begin: 0x102A0, end: 0x102DF}, // Carian - {begin: 0x1F030, end: 0x1F09F} // Domino Tiles -]; - -function getUnicodeRange(unicode) { - for (var i = 0; i < unicodeRanges.length; i += 1) { - var range = unicodeRanges[i]; - if (unicode >= range.begin && unicode < range.end) { - return i; - } - } - - return -1; -} - -// Parse the OS/2 and Windows metrics `OS/2` table -function parseOS2Table(data, start) { - var os2 = {}; - var p = new parse.Parser(data, start); - os2.version = p.parseUShort(); - os2.xAvgCharWidth = p.parseShort(); - os2.usWeightClass = p.parseUShort(); - os2.usWidthClass = p.parseUShort(); - os2.fsType = p.parseUShort(); - os2.ySubscriptXSize = p.parseShort(); - os2.ySubscriptYSize = p.parseShort(); - os2.ySubscriptXOffset = p.parseShort(); - os2.ySubscriptYOffset = p.parseShort(); - os2.ySuperscriptXSize = p.parseShort(); - os2.ySuperscriptYSize = p.parseShort(); - os2.ySuperscriptXOffset = p.parseShort(); - os2.ySuperscriptYOffset = p.parseShort(); - os2.yStrikeoutSize = p.parseShort(); - os2.yStrikeoutPosition = p.parseShort(); - os2.sFamilyClass = p.parseShort(); - os2.panose = []; - for (var i = 0; i < 10; i++) { - os2.panose[i] = p.parseByte(); - } - - os2.ulUnicodeRange1 = p.parseULong(); - os2.ulUnicodeRange2 = p.parseULong(); - os2.ulUnicodeRange3 = p.parseULong(); - os2.ulUnicodeRange4 = p.parseULong(); - os2.achVendID = String.fromCharCode(p.parseByte(), p.parseByte(), p.parseByte(), p.parseByte()); - os2.fsSelection = p.parseUShort(); - os2.usFirstCharIndex = p.parseUShort(); - os2.usLastCharIndex = p.parseUShort(); - os2.sTypoAscender = p.parseShort(); - os2.sTypoDescender = p.parseShort(); - os2.sTypoLineGap = p.parseShort(); - os2.usWinAscent = p.parseUShort(); - os2.usWinDescent = p.parseUShort(); - if (os2.version >= 1) { - os2.ulCodePageRange1 = p.parseULong(); - os2.ulCodePageRange2 = p.parseULong(); - } - - if (os2.version >= 2) { - os2.sxHeight = p.parseShort(); - os2.sCapHeight = p.parseShort(); - os2.usDefaultChar = p.parseUShort(); - os2.usBreakChar = p.parseUShort(); - os2.usMaxContent = p.parseUShort(); - } - - return os2; -} - -function makeOS2Table(options) { - return new table.Table('OS/2', [ - {name: 'version', type: 'USHORT', value: 0x0003}, - {name: 'xAvgCharWidth', type: 'SHORT', value: 0}, - {name: 'usWeightClass', type: 'USHORT', value: 0}, - {name: 'usWidthClass', type: 'USHORT', value: 0}, - {name: 'fsType', type: 'USHORT', value: 0}, - {name: 'ySubscriptXSize', type: 'SHORT', value: 650}, - {name: 'ySubscriptYSize', type: 'SHORT', value: 699}, - {name: 'ySubscriptXOffset', type: 'SHORT', value: 0}, - {name: 'ySubscriptYOffset', type: 'SHORT', value: 140}, - {name: 'ySuperscriptXSize', type: 'SHORT', value: 650}, - {name: 'ySuperscriptYSize', type: 'SHORT', value: 699}, - {name: 'ySuperscriptXOffset', type: 'SHORT', value: 0}, - {name: 'ySuperscriptYOffset', type: 'SHORT', value: 479}, - {name: 'yStrikeoutSize', type: 'SHORT', value: 49}, - {name: 'yStrikeoutPosition', type: 'SHORT', value: 258}, - {name: 'sFamilyClass', type: 'SHORT', value: 0}, - {name: 'bFamilyType', type: 'BYTE', value: 0}, - {name: 'bSerifStyle', type: 'BYTE', value: 0}, - {name: 'bWeight', type: 'BYTE', value: 0}, - {name: 'bProportion', type: 'BYTE', value: 0}, - {name: 'bContrast', type: 'BYTE', value: 0}, - {name: 'bStrokeVariation', type: 'BYTE', value: 0}, - {name: 'bArmStyle', type: 'BYTE', value: 0}, - {name: 'bLetterform', type: 'BYTE', value: 0}, - {name: 'bMidline', type: 'BYTE', value: 0}, - {name: 'bXHeight', type: 'BYTE', value: 0}, - {name: 'ulUnicodeRange1', type: 'ULONG', value: 0}, - {name: 'ulUnicodeRange2', type: 'ULONG', value: 0}, - {name: 'ulUnicodeRange3', type: 'ULONG', value: 0}, - {name: 'ulUnicodeRange4', type: 'ULONG', value: 0}, - {name: 'achVendID', type: 'CHARARRAY', value: 'XXXX'}, - {name: 'fsSelection', type: 'USHORT', value: 0}, - {name: 'usFirstCharIndex', type: 'USHORT', value: 0}, - {name: 'usLastCharIndex', type: 'USHORT', value: 0}, - {name: 'sTypoAscender', type: 'SHORT', value: 0}, - {name: 'sTypoDescender', type: 'SHORT', value: 0}, - {name: 'sTypoLineGap', type: 'SHORT', value: 0}, - {name: 'usWinAscent', type: 'USHORT', value: 0}, - {name: 'usWinDescent', type: 'USHORT', value: 0}, - {name: 'ulCodePageRange1', type: 'ULONG', value: 0}, - {name: 'ulCodePageRange2', type: 'ULONG', value: 0}, - {name: 'sxHeight', type: 'SHORT', value: 0}, - {name: 'sCapHeight', type: 'SHORT', value: 0}, - {name: 'usDefaultChar', type: 'USHORT', value: 0}, - {name: 'usBreakChar', type: 'USHORT', value: 0}, - {name: 'usMaxContext', type: 'USHORT', value: 0} - ], options); -} - -exports.unicodeRanges = unicodeRanges; -exports.getUnicodeRange = getUnicodeRange; -exports.parse = parseOS2Table; -exports.make = makeOS2Table; - -},{"../parse":9,"../table":11}],24:[function(_dereq_,module,exports){ -// The `post` table stores additional PostScript information, such as glyph names. -// https://www.microsoft.com/typography/OTSPEC/post.htm - -'use strict'; - -var encoding = _dereq_('../encoding'); -var parse = _dereq_('../parse'); -var table = _dereq_('../table'); - -// Parse the PostScript `post` table -function parsePostTable(data, start) { - var post = {}; - var p = new parse.Parser(data, start); - var i; - post.version = p.parseVersion(); - post.italicAngle = p.parseFixed(); - post.underlinePosition = p.parseShort(); - post.underlineThickness = p.parseShort(); - post.isFixedPitch = p.parseULong(); - post.minMemType42 = p.parseULong(); - post.maxMemType42 = p.parseULong(); - post.minMemType1 = p.parseULong(); - post.maxMemType1 = p.parseULong(); - switch (post.version) { - case 1: - post.names = encoding.standardNames.slice(); - break; - case 2: - post.numberOfGlyphs = p.parseUShort(); - post.glyphNameIndex = new Array(post.numberOfGlyphs); - for (i = 0; i < post.numberOfGlyphs; i++) { - post.glyphNameIndex[i] = p.parseUShort(); - } - - post.names = []; - for (i = 0; i < post.numberOfGlyphs; i++) { - if (post.glyphNameIndex[i] >= encoding.standardNames.length) { - var nameLength = p.parseChar(); - post.names.push(p.parseString(nameLength)); - } - } - - break; - case 2.5: - post.numberOfGlyphs = p.parseUShort(); - post.offset = new Array(post.numberOfGlyphs); - for (i = 0; i < post.numberOfGlyphs; i++) { - post.offset[i] = p.parseChar(); - } - - break; - } - return post; -} - -function makePostTable() { - return new table.Table('post', [ - {name: 'version', type: 'FIXED', value: 0x00030000}, - {name: 'italicAngle', type: 'FIXED', value: 0}, - {name: 'underlinePosition', type: 'FWORD', value: 0}, - {name: 'underlineThickness', type: 'FWORD', value: 0}, - {name: 'isFixedPitch', type: 'ULONG', value: 0}, - {name: 'minMemType42', type: 'ULONG', value: 0}, - {name: 'maxMemType42', type: 'ULONG', value: 0}, - {name: 'minMemType1', type: 'ULONG', value: 0}, - {name: 'maxMemType1', type: 'ULONG', value: 0} - ]); -} - -exports.parse = parsePostTable; -exports.make = makePostTable; - -},{"../encoding":4,"../parse":9,"../table":11}],25:[function(_dereq_,module,exports){ -// The `sfnt` wrapper provides organization for the tables in the font. -// It is the top-level data structure in a font. -// https://www.microsoft.com/typography/OTSPEC/otff.htm -// Recommendations for creating OpenType Fonts: -// http://www.microsoft.com/typography/otspec140/recom.htm - -'use strict'; - -var check = _dereq_('../check'); -var table = _dereq_('../table'); - -var cmap = _dereq_('./cmap'); -var cff = _dereq_('./cff'); -var head = _dereq_('./head'); -var hhea = _dereq_('./hhea'); -var hmtx = _dereq_('./hmtx'); -var maxp = _dereq_('./maxp'); -var _name = _dereq_('./name'); -var os2 = _dereq_('./os2'); -var post = _dereq_('./post'); - -function log2(v) { - return Math.log(v) / Math.log(2) | 0; -} - -function computeCheckSum(bytes) { - while (bytes.length % 4 !== 0) { - bytes.push(0); - } - - var sum = 0; - for (var i = 0; i < bytes.length; i += 4) { - sum += (bytes[i] << 24) + - (bytes[i + 1] << 16) + - (bytes[i + 2] << 8) + - (bytes[i + 3]); - } - - sum %= Math.pow(2, 32); - return sum; -} - -function makeTableRecord(tag, checkSum, offset, length) { - return new table.Table('Table Record', [ - {name: 'tag', type: 'TAG', value: tag !== undefined ? tag : ''}, - {name: 'checkSum', type: 'ULONG', value: checkSum !== undefined ? checkSum : 0}, - {name: 'offset', type: 'ULONG', value: offset !== undefined ? offset : 0}, - {name: 'length', type: 'ULONG', value: length !== undefined ? length : 0} - ]); -} - -function makeSfntTable(tables) { - var sfnt = new table.Table('sfnt', [ - {name: 'version', type: 'TAG', value: 'OTTO'}, - {name: 'numTables', type: 'USHORT', value: 0}, - {name: 'searchRange', type: 'USHORT', value: 0}, - {name: 'entrySelector', type: 'USHORT', value: 0}, - {name: 'rangeShift', type: 'USHORT', value: 0} - ]); - sfnt.tables = tables; - sfnt.numTables = tables.length; - var highestPowerOf2 = Math.pow(2, log2(sfnt.numTables)); - sfnt.searchRange = 16 * highestPowerOf2; - sfnt.entrySelector = log2(highestPowerOf2); - sfnt.rangeShift = sfnt.numTables * 16 - sfnt.searchRange; - - var recordFields = []; - var tableFields = []; - - var offset = sfnt.sizeOf() + (makeTableRecord().sizeOf() * sfnt.numTables); - while (offset % 4 !== 0) { - offset += 1; - tableFields.push({name: 'padding', type: 'BYTE', value: 0}); - } - - for (var i = 0; i < tables.length; i += 1) { - var t = tables[i]; - check.argument(t.tableName.length === 4, 'Table name' + t.tableName + ' is invalid.'); - var tableLength = t.sizeOf(); - var tableRecord = makeTableRecord(t.tableName, computeCheckSum(t.encode()), offset, tableLength); - recordFields.push({name: tableRecord.tag + ' Table Record', type: 'TABLE', value: tableRecord}); - tableFields.push({name: t.tableName + ' table', type: 'TABLE', value: t}); - offset += tableLength; - check.argument(!isNaN(offset), 'Something went wrong calculating the offset.'); - while (offset % 4 !== 0) { - offset += 1; - tableFields.push({name: 'padding', type: 'BYTE', value: 0}); - } - } - - // Table records need to be sorted alphabetically. - recordFields.sort(function(r1, r2) { - if (r1.value.tag > r2.value.tag) { - return 1; - } else { - return -1; - } - }); - - sfnt.fields = sfnt.fields.concat(recordFields); - sfnt.fields = sfnt.fields.concat(tableFields); - return sfnt; -} - -// Get the metrics for a character. If the string has more than one character -// this function returns metrics for the first available character. -// You can provide optional fallback metrics if no characters are available. -function metricsForChar(font, chars, notFoundMetrics) { - for (var i = 0; i < chars.length; i += 1) { - var glyphIndex = font.charToGlyphIndex(chars[i]); - if (glyphIndex > 0) { - var glyph = font.glyphs.get(glyphIndex); - return glyph.getMetrics(); - } - } - - return notFoundMetrics; -} - -function average(vs) { - var sum = 0; - for (var i = 0; i < vs.length; i += 1) { - sum += vs[i]; - } - - return sum / vs.length; -} - -// Convert the font object to a SFNT data structure. -// This structure contains all the necessary tables and metadata to create a binary OTF file. -function fontToSfntTable(font) { - var xMins = []; - var yMins = []; - var xMaxs = []; - var yMaxs = []; - var advanceWidths = []; - var leftSideBearings = []; - var rightSideBearings = []; - var firstCharIndex; - var lastCharIndex = 0; - var ulUnicodeRange1 = 0; - var ulUnicodeRange2 = 0; - var ulUnicodeRange3 = 0; - var ulUnicodeRange4 = 0; - - for (var i = 0; i < font.glyphs.length; i += 1) { - var glyph = font.glyphs.get(i); - var unicode = glyph.unicode | 0; - if (firstCharIndex > unicode || firstCharIndex === null) { - firstCharIndex = unicode; - } - - if (lastCharIndex < unicode) { - lastCharIndex = unicode; - } - - var position = os2.getUnicodeRange(unicode); - if (position < 32) { - ulUnicodeRange1 |= 1 << position; - } else if (position < 64) { - ulUnicodeRange2 |= 1 << position - 32; - } else if (position < 96) { - ulUnicodeRange3 |= 1 << position - 64; - } else if (position < 123) { - ulUnicodeRange4 |= 1 << position - 96; - } else { - throw new Error('Unicode ranges bits > 123 are reserved for internal usage'); - } - // Skip non-important characters. - if (glyph.name === '.notdef') continue; - var metrics = glyph.getMetrics(); - xMins.push(metrics.xMin); - yMins.push(metrics.yMin); - xMaxs.push(metrics.xMax); - yMaxs.push(metrics.yMax); - leftSideBearings.push(metrics.leftSideBearing); - rightSideBearings.push(metrics.rightSideBearing); - advanceWidths.push(glyph.advanceWidth); - } - - var globals = { - xMin: Math.min.apply(null, xMins), - yMin: Math.min.apply(null, yMins), - xMax: Math.max.apply(null, xMaxs), - yMax: Math.max.apply(null, yMaxs), - advanceWidthMax: Math.max.apply(null, advanceWidths), - advanceWidthAvg: average(advanceWidths), - minLeftSideBearing: Math.min.apply(null, leftSideBearings), - maxLeftSideBearing: Math.max.apply(null, leftSideBearings), - minRightSideBearing: Math.min.apply(null, rightSideBearings) - }; - globals.ascender = font.ascender !== undefined ? font.ascender : globals.yMax; - globals.descender = font.descender !== undefined ? font.descender : globals.yMin; - - var headTable = head.make({ - unitsPerEm: font.unitsPerEm, - xMin: globals.xMin, - yMin: globals.yMin, - xMax: globals.xMax, - yMax: globals.yMax - }); - - var hheaTable = hhea.make({ - ascender: globals.ascender, - descender: globals.descender, - advanceWidthMax: globals.advanceWidthMax, - minLeftSideBearing: globals.minLeftSideBearing, - minRightSideBearing: globals.minRightSideBearing, - xMaxExtent: globals.maxLeftSideBearing + (globals.xMax - globals.xMin), - numberOfHMetrics: font.glyphs.length - }); - - var maxpTable = maxp.make(font.glyphs.length); - - var os2Table = os2.make({ - xAvgCharWidth: Math.round(globals.advanceWidthAvg), - usWeightClass: 500, // Medium FIXME Make this configurable - usWidthClass: 5, // Medium (normal) FIXME Make this configurable - usFirstCharIndex: firstCharIndex, - usLastCharIndex: lastCharIndex, - ulUnicodeRange1: ulUnicodeRange1, - ulUnicodeRange2: ulUnicodeRange2, - ulUnicodeRange3: ulUnicodeRange3, - ulUnicodeRange4: ulUnicodeRange4, - // See http://typophile.com/node/13081 for more info on vertical metrics. - // We get metrics for typical characters (such as "x" for xHeight). - // We provide some fallback characters if characters are unavailable: their - // ordering was chosen experimentally. - sTypoAscender: globals.ascender, - sTypoDescender: globals.descender, - sTypoLineGap: 0, - usWinAscent: globals.ascender, - usWinDescent: -globals.descender, - sxHeight: metricsForChar(font, 'xyvw', {yMax: 0}).yMax, - sCapHeight: metricsForChar(font, 'HIKLEFJMNTZBDPRAGOQSUVWXY', globals).yMax, - usBreakChar: font.hasChar(' ') ? 32 : 0 // Use space as the break character, if available. - }); - - var hmtxTable = hmtx.make(font.glyphs); - var cmapTable = cmap.make(font.glyphs); - - var fullName = font.familyName + ' ' + font.styleName; - var postScriptName = font.familyName.replace(/\s/g, '') + '-' + font.styleName; - var nameTable = _name.make({ - copyright: font.copyright, - fontFamily: font.familyName, - fontSubfamily: font.styleName, - uniqueID: font.manufacturer + ':' + fullName, - fullName: fullName, - version: font.version, - postScriptName: postScriptName, - trademark: font.trademark, - manufacturer: font.manufacturer, - designer: font.designer, - description: font.description, - manufacturerURL: font.manufacturerURL, - designerURL: font.designerURL, - license: font.license, - licenseURL: font.licenseURL, - preferredFamily: font.familyName, - preferredSubfamily: font.styleName - }); - var postTable = post.make(); - var cffTable = cff.make(font.glyphs, { - version: font.version, - fullName: fullName, - familyName: font.familyName, - weightName: font.styleName, - postScriptName: postScriptName, - unitsPerEm: font.unitsPerEm - }); - // Order the tables according to the the OpenType specification 1.4. - var tables = [headTable, hheaTable, maxpTable, os2Table, nameTable, cmapTable, postTable, cffTable, hmtxTable]; - - var sfntTable = makeSfntTable(tables); - - // Compute the font's checkSum and store it in head.checkSumAdjustment. - var bytes = sfntTable.encode(); - var checkSum = computeCheckSum(bytes); - var tableFields = sfntTable.fields; - var checkSumAdjusted = false; - for (i = 0; i < tableFields.length; i += 1) { - if (tableFields[i].name === 'head table') { - tableFields[i].value.checkSumAdjustment = 0xB1B0AFBA - checkSum; - checkSumAdjusted = true; - break; - } - } - - if (!checkSumAdjusted) { - throw new Error('Could not find head table with checkSum to adjust.'); - } - - return sfntTable; -} - -exports.computeCheckSum = computeCheckSum; -exports.make = makeSfntTable; -exports.fontToTable = fontToSfntTable; - -},{"../check":2,"../table":11,"./cff":12,"./cmap":13,"./head":16,"./hhea":17,"./hmtx":18,"./maxp":21,"./name":22,"./os2":23,"./post":24}],26:[function(_dereq_,module,exports){ -// Data types used in the OpenType font file. -// All OpenType fonts use Motorola-style byte ordering (Big Endian) - -/* global WeakMap */ - -'use strict'; - -var check = _dereq_('./check'); - -var LIMIT16 = 32768; // The limit at which a 16-bit number switches signs == 2^15 -var LIMIT32 = 2147483648; // The limit at which a 32-bit number switches signs == 2 ^ 31 - -var decode = {}; -var encode = {}; -var sizeOf = {}; - -// Return a function that always returns the same value. -function constant(v) { - return function() { - return v; - }; -} - -// OpenType data types ////////////////////////////////////////////////////// - -// Convert an 8-bit unsigned integer to a list of 1 byte. -encode.BYTE = function(v) { - check.argument(v >= 0 && v <= 255, 'Byte value should be between 0 and 255.'); - return [v]; -}; - -sizeOf.BYTE = constant(1); - -// Convert a 8-bit signed integer to a list of 1 byte. -encode.CHAR = function(v) { - return [v.charCodeAt(0)]; -}; - -sizeOf.BYTE = constant(1); - -// Convert an ASCII string to a list of bytes. -encode.CHARARRAY = function(v) { - var b = []; - for (var i = 0; i < v.length; i += 1) { - b.push(v.charCodeAt(i)); - } - - return b; -}; - -sizeOf.CHARARRAY = function(v) { - return v.length; -}; - -// Convert a 16-bit unsigned integer to a list of 2 bytes. -encode.USHORT = function(v) { - return [(v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.USHORT = constant(2); - -// Convert a 16-bit signed integer to a list of 2 bytes. -encode.SHORT = function(v) { - // Two's complement - if (v >= LIMIT16) { - v = -(2 * LIMIT16 - v); - } - - return [(v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.SHORT = constant(2); - -// Convert a 24-bit unsigned integer to a list of 3 bytes. -encode.UINT24 = function(v) { - return [(v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.UINT24 = constant(3); - -// Convert a 32-bit unsigned integer to a list of 4 bytes. -encode.ULONG = function(v) { - return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.ULONG = constant(4); - -// Convert a 32-bit unsigned integer to a list of 4 bytes. -encode.LONG = function(v) { - // Two's complement - if (v >= LIMIT32) { - v = -(2 * LIMIT32 - v); - } - - return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.LONG = constant(4); - -encode.FIXED = encode.ULONG; -sizeOf.FIXED = sizeOf.ULONG; - -encode.FWORD = encode.SHORT; -sizeOf.FWORD = sizeOf.SHORT; - -encode.UFWORD = encode.USHORT; -sizeOf.UFWORD = sizeOf.USHORT; - -// FIXME Implement LONGDATETIME -encode.LONGDATETIME = function() { - return [0, 0, 0, 0, 0, 0, 0, 0]; -}; - -sizeOf.LONGDATETIME = constant(8); - -// Convert a 4-char tag to a list of 4 bytes. -encode.TAG = function(v) { - check.argument(v.length === 4, 'Tag should be exactly 4 ASCII characters.'); - return [v.charCodeAt(0), - v.charCodeAt(1), - v.charCodeAt(2), - v.charCodeAt(3)]; -}; - -sizeOf.TAG = constant(4); - -// CFF data types /////////////////////////////////////////////////////////// - -encode.Card8 = encode.BYTE; -sizeOf.Card8 = sizeOf.BYTE; - -encode.Card16 = encode.USHORT; -sizeOf.Card16 = sizeOf.USHORT; - -encode.OffSize = encode.BYTE; -sizeOf.OffSize = sizeOf.BYTE; - -encode.SID = encode.USHORT; -sizeOf.SID = sizeOf.USHORT; - -// Convert a numeric operand or charstring number to a variable-size list of bytes. -encode.NUMBER = function(v) { - if (v >= -107 && v <= 107) { - return [v + 139]; - } else if (v >= 108 && v <= 1131) { - v = v - 108; - return [(v >> 8) + 247, v & 0xFF]; - } else if (v >= -1131 && v <= -108) { - v = -v - 108; - return [(v >> 8) + 251, v & 0xFF]; - } else if (v >= -32768 && v <= 32767) { - return encode.NUMBER16(v); - } else { - return encode.NUMBER32(v); - } -}; - -sizeOf.NUMBER = function(v) { - return encode.NUMBER(v).length; -}; - -// Convert a signed number between -32768 and +32767 to a three-byte value. -// This ensures we always use three bytes, but is not the most compact format. -encode.NUMBER16 = function(v) { - return [28, (v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.NUMBER16 = constant(2); - -// Convert a signed number between -(2^31) and +(2^31-1) to a four-byte value. -// This is useful if you want to be sure you always use four bytes, -// at the expense of wasting a few bytes for smaller numbers. -encode.NUMBER32 = function(v) { - return [29, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; -}; - -sizeOf.NUMBER32 = constant(4); - -encode.REAL = function(v) { - var value = v.toString(); - - // Some numbers use an epsilon to encode the value. (e.g. JavaScript will store 0.0000001 as 1e-7) - // This code converts it back to a number without the epsilon. - var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value); - if (m) { - var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length)); - value = (Math.round(v * epsilon) / epsilon).toString(); - } - - var nibbles = ''; - var i; - var ii; - for (i = 0, ii = value.length; i < ii; i += 1) { - var c = value[i]; - if (c === 'e') { - nibbles += value[++i] === '-' ? 'c' : 'b'; - } else if (c === '.') { - nibbles += 'a'; - } else if (c === '-') { - nibbles += 'e'; - } else { - nibbles += c; - } - } - - nibbles += (nibbles.length & 1) ? 'f' : 'ff'; - var out = [30]; - for (i = 0, ii = nibbles.length; i < ii; i += 2) { - out.push(parseInt(nibbles.substr(i, 2), 16)); - } - - return out; -}; - -sizeOf.REAL = function(v) { - return encode.REAL(v).length; -}; - -encode.NAME = encode.CHARARRAY; -sizeOf.NAME = sizeOf.CHARARRAY; - -encode.STRING = encode.CHARARRAY; -sizeOf.STRING = sizeOf.CHARARRAY; - -// Convert a ASCII string to a list of UTF16 bytes. -encode.UTF16 = function(v) { - var b = []; - for (var i = 0; i < v.length; i += 1) { - b.push(0); - b.push(v.charCodeAt(i)); - } - - return b; -}; - -sizeOf.UTF16 = function(v) { - return v.length * 2; -}; - -// Convert a list of values to a CFF INDEX structure. -// The values should be objects containing name / type / value. -encode.INDEX = function(l) { - var i; - //var offset, offsets, offsetEncoder, encodedOffsets, encodedOffset, data, - // dataSize, i, v; - // Because we have to know which data type to use to encode the offsets, - // we have to go through the values twice: once to encode the data and - // calculate the offets, then again to encode the offsets using the fitting data type. - var offset = 1; // First offset is always 1. - var offsets = [offset]; - var data = []; - var dataSize = 0; - for (i = 0; i < l.length; i += 1) { - var v = encode.OBJECT(l[i]); - Array.prototype.push.apply(data, v); - dataSize += v.length; - offset += v.length; - offsets.push(offset); - } - - if (data.length === 0) { - return [0, 0]; - } - - var encodedOffsets = []; - var offSize = (1 + Math.floor(Math.log(dataSize) / Math.log(2)) / 8) | 0; - var offsetEncoder = [undefined, encode.BYTE, encode.USHORT, encode.UINT24, encode.ULONG][offSize]; - for (i = 0; i < offsets.length; i += 1) { - var encodedOffset = offsetEncoder(offsets[i]); - Array.prototype.push.apply(encodedOffsets, encodedOffset); - } - - return Array.prototype.concat(encode.Card16(l.length), - encode.OffSize(offSize), - encodedOffsets, - data); -}; - -sizeOf.INDEX = function(v) { - return encode.INDEX(v).length; -}; - -// Convert an object to a CFF DICT structure. -// The keys should be numeric. -// The values should be objects containing name / type / value. -encode.DICT = function(m) { - var d = []; - var keys = Object.keys(m); - var length = keys.length; - - for (var i = 0; i < length; i += 1) { - // Object.keys() return string keys, but our keys are always numeric. - var k = parseInt(keys[i], 0); - var v = m[k]; - // Value comes before the key. - d = d.concat(encode.OPERAND(v.value, v.type)); - d = d.concat(encode.OPERATOR(k)); - } - - return d; -}; - -sizeOf.DICT = function(m) { - return encode.DICT(m).length; -}; - -encode.OPERATOR = function(v) { - if (v < 1200) { - return [v]; - } else { - return [12, v - 1200]; - } -}; - -encode.OPERAND = function(v, type) { - var d = []; - if (Array.isArray(type)) { - for (var i = 0; i < type.length; i += 1) { - check.argument(v.length === type.length, 'Not enough arguments given for type' + type); - d = d.concat(encode.OPERAND(v[i], type[i])); - } - } else { - if (type === 'SID') { - d = d.concat(encode.NUMBER(v)); - } else if (type === 'offset') { - // We make it easy for ourselves and always encode offsets as - // 4 bytes. This makes offset calculation for the top dict easier. - d = d.concat(encode.NUMBER32(v)); - } else if (type === 'number') { - d = d.concat(encode.NUMBER(v)); - } else if (type === 'real') { - d = d.concat(encode.REAL(v)); - } else { - throw new Error('Unknown operand type ' + type); - // FIXME Add support for booleans - } - } - - return d; -}; - -encode.OP = encode.BYTE; -sizeOf.OP = sizeOf.BYTE; - -// memoize charstring encoding using WeakMap if available -var wmm = typeof WeakMap === 'function' && new WeakMap(); -// Convert a list of CharString operations to bytes. -encode.CHARSTRING = function(ops) { - if (wmm && wmm.has(ops)) { - return wmm.get(ops); - } - - var d = []; - var length = ops.length; - - for (var i = 0; i < length; i += 1) { - var op = ops[i]; - d = d.concat(encode[op.type](op.value)); - } - - if (wmm) { - wmm.set(ops, d); - } - - return d; -}; - -sizeOf.CHARSTRING = function(ops) { - return encode.CHARSTRING(ops).length; -}; - -// Utility functions //////////////////////////////////////////////////////// - -// Convert an object containing name / type / value to bytes. -encode.OBJECT = function(v) { - var encodingFunction = encode[v.type]; - check.argument(encodingFunction !== undefined, 'No encoding function for type ' + v.type); - return encodingFunction(v.value); -}; - -// Convert a table object to bytes. -// A table contains a list of fields containing the metadata (name, type and default value). -// The table itself has the field values set as attributes. -encode.TABLE = function(table) { - var d = []; - var length = table.fields.length; - - for (var i = 0; i < length; i += 1) { - var field = table.fields[i]; - var encodingFunction = encode[field.type]; - check.argument(encodingFunction !== undefined, 'No encoding function for field type ' + field.type); - var value = table[field.name]; - if (value === undefined) { - value = field.value; - } - - var bytes = encodingFunction(value); - d = d.concat(bytes); - } - - return d; -}; - -// Merge in a list of bytes. -encode.LITERAL = function(v) { - return v; -}; - -sizeOf.LITERAL = function(v) { - return v.length; -}; - -exports.decode = decode; -exports.encode = encode; -exports.sizeOf = sizeOf; - -},{"./check":2}],27:[function(_dereq_,module,exports){ -/*! - * Reqwest! A general purpose XHR connection manager - * license MIT (c) Dustin Diaz 2014 - * https://github.com/ded/reqwest - */ - -!function (name, context, definition) { - if (typeof module != 'undefined' && module.exports) module.exports = definition() - else if (typeof define == 'function' && define.amd) define(definition) - else context[name] = definition() -}('reqwest', this, function () { - - var win = window - , doc = document - , httpsRe = /^http/ - , protocolRe = /(^\w+):\/\// - , twoHundo = /^(20\d|1223)$/ //http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request - , byTag = 'getElementsByTagName' - , readyState = 'readyState' - , contentType = 'Content-Type' - , requestedWith = 'X-Requested-With' - , head = doc[byTag]('head')[0] - , uniqid = 0 - , callbackPrefix = 'reqwest_' + (+new Date()) - , lastValue // data stored by the most recent JSONP callback - , xmlHttpRequest = 'XMLHttpRequest' - , xDomainRequest = 'XDomainRequest' - , noop = function () {} - - , isArray = typeof Array.isArray == 'function' - ? Array.isArray - : function (a) { - return a instanceof Array - } - - , defaultHeaders = { - 'contentType': 'application/x-www-form-urlencoded' - , 'requestedWith': xmlHttpRequest - , 'accept': { - '*': 'text/javascript, text/html, application/xml, text/xml, */*' - , 'xml': 'application/xml, text/xml' - , 'html': 'text/html' - , 'text': 'text/plain' - , 'json': 'application/json, text/javascript' - , 'js': 'application/javascript, text/javascript' - } - } - - , xhr = function(o) { - // is it x-domain - if (o['crossOrigin'] === true) { - var xhr = win[xmlHttpRequest] ? new XMLHttpRequest() : null - if (xhr && 'withCredentials' in xhr) { - return xhr - } else if (win[xDomainRequest]) { - return new XDomainRequest() - } else { - throw new Error('Browser does not support cross-origin requests') - } - } else if (win[xmlHttpRequest]) { - return new XMLHttpRequest() - } else { - return new ActiveXObject('Microsoft.XMLHTTP') - } - } - , globalSetupOptions = { - dataFilter: function (data) { - return data - } - } - - function succeed(r) { - var protocol = protocolRe.exec(r.url); - protocol = (protocol && protocol[1]) || window.location.protocol; - return httpsRe.test(protocol) ? twoHundo.test(r.request.status) : !!r.request.response; - } - - function handleReadyState(r, success, error) { - return function () { - // use _aborted to mitigate against IE err c00c023f - // (can't read props on aborted request objects) - if (r._aborted) return error(r.request) - if (r._timedOut) return error(r.request, 'Request is aborted: timeout') - if (r.request && r.request[readyState] == 4) { - r.request.onreadystatechange = noop - if (succeed(r)) success(r.request) - else - error(r.request) - } - } - } - - function setHeaders(http, o) { - var headers = o['headers'] || {} - , h - - headers['Accept'] = headers['Accept'] - || defaultHeaders['accept'][o['type']] - || defaultHeaders['accept']['*'] - - var isAFormData = typeof FormData === 'function' && (o['data'] instanceof FormData); - // breaks cross-origin requests with legacy browsers - if (!o['crossOrigin'] && !headers[requestedWith]) headers[requestedWith] = defaultHeaders['requestedWith'] - if (!headers[contentType] && !isAFormData) headers[contentType] = o['contentType'] || defaultHeaders['contentType'] - for (h in headers) - headers.hasOwnProperty(h) && 'setRequestHeader' in http && http.setRequestHeader(h, headers[h]) - } - - function setCredentials(http, o) { - if (typeof o['withCredentials'] !== 'undefined' && typeof http.withCredentials !== 'undefined') { - http.withCredentials = !!o['withCredentials'] - } - } - - function generalCallback(data) { - lastValue = data - } - - function urlappend (url, s) { - return url + (/\?/.test(url) ? '&' : '?') + s - } - - function handleJsonp(o, fn, err, url) { - var reqId = uniqid++ - , cbkey = o['jsonpCallback'] || 'callback' // the 'callback' key - , cbval = o['jsonpCallbackName'] || reqwest.getcallbackPrefix(reqId) - , cbreg = new RegExp('((^|\\?|&)' + cbkey + ')=([^&]+)') - , match = url.match(cbreg) - , script = doc.createElement('script') - , loaded = 0 - , isIE10 = navigator.userAgent.indexOf('MSIE 10.0') !== -1 - - if (match) { - if (match[3] === '?') { - url = url.replace(cbreg, '$1=' + cbval) // wildcard callback func name - } else { - cbval = match[3] // provided callback func name - } - } else { - url = urlappend(url, cbkey + '=' + cbval) // no callback details, add 'em - } - - win[cbval] = generalCallback - - script.type = 'text/javascript' - script.src = url - script.async = true - if (typeof script.onreadystatechange !== 'undefined' && !isIE10) { - // need this for IE due to out-of-order onreadystatechange(), binding script - // execution to an event listener gives us control over when the script - // is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html - script.htmlFor = script.id = '_reqwest_' + reqId - } - - script.onload = script.onreadystatechange = function () { - if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) { - return false - } - script.onload = script.onreadystatechange = null - script.onclick && script.onclick() - // Call the user callback with the last value stored and clean up values and scripts. - fn(lastValue) - lastValue = undefined - head.removeChild(script) - loaded = 1 - } - - // Add the script to the DOM head - head.appendChild(script) - - // Enable JSONP timeout - return { - abort: function () { - script.onload = script.onreadystatechange = null - err({}, 'Request is aborted: timeout', {}) - lastValue = undefined - head.removeChild(script) - loaded = 1 - } - } - } - - function getRequest(fn, err) { - var o = this.o - , method = (o['method'] || 'GET').toUpperCase() - , url = typeof o === 'string' ? o : o['url'] - // convert non-string objects to query-string form unless o['processData'] is false - , data = (o['processData'] !== false && o['data'] && typeof o['data'] !== 'string') - ? reqwest.toQueryString(o['data']) - : (o['data'] || null) - , http - , sendWait = false - - // if we're working on a GET request and we have data then we should append - // query string to end of URL and not post data - if ((o['type'] == 'jsonp' || method == 'GET') && data) { - url = urlappend(url, data) - data = null - } - - if (o['type'] == 'jsonp') return handleJsonp(o, fn, err, url) - - // get the xhr from the factory if passed - // if the factory returns null, fall-back to ours - http = (o.xhr && o.xhr(o)) || xhr(o) - - http.open(method, url, o['async'] === false ? false : true) - setHeaders(http, o) - setCredentials(http, o) - if (win[xDomainRequest] && http instanceof win[xDomainRequest]) { - http.onload = fn - http.onerror = err - // NOTE: see - // http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/30ef3add-767c-4436-b8a9-f1ca19b4812e - http.onprogress = function() {} - sendWait = true - } else { - http.onreadystatechange = handleReadyState(this, fn, err) - } - o['before'] && o['before'](http) - if (sendWait) { - setTimeout(function () { - http.send(data) - }, 200) - } else { - http.send(data) - } - return http - } - - function Reqwest(o, fn) { - this.o = o - this.fn = fn - - init.apply(this, arguments) - } - - function setType(header) { - // json, javascript, text/plain, text/html, xml - if (header.match('json')) return 'json' - if (header.match('javascript')) return 'js' - if (header.match('text')) return 'html' - if (header.match('xml')) return 'xml' - } - - function init(o, fn) { - - this.url = typeof o == 'string' ? o : o['url'] - this.timeout = null - - // whether request has been fulfilled for purpose - // of tracking the Promises - this._fulfilled = false - // success handlers - this._successHandler = function(){} - this._fulfillmentHandlers = [] - // error handlers - this._errorHandlers = [] - // complete (both success and fail) handlers - this._completeHandlers = [] - this._erred = false - this._responseArgs = {} - - var self = this - - fn = fn || function () {} - - if (o['timeout']) { - this.timeout = setTimeout(function () { - timedOut() - }, o['timeout']) - } - - if (o['success']) { - this._successHandler = function () { - o['success'].apply(o, arguments) - } - } - - if (o['error']) { - this._errorHandlers.push(function () { - o['error'].apply(o, arguments) - }) - } - - if (o['complete']) { - this._completeHandlers.push(function () { - o['complete'].apply(o, arguments) - }) - } - - function complete (resp) { - o['timeout'] && clearTimeout(self.timeout) - self.timeout = null - while (self._completeHandlers.length > 0) { - self._completeHandlers.shift()(resp) - } - } - - function success (resp) { - var type = o['type'] || resp && setType(resp.getResponseHeader('Content-Type')) // resp can be undefined in IE - resp = (type !== 'jsonp') ? self.request : resp - // use global data filter on response text - var filteredResponse = globalSetupOptions.dataFilter(resp.responseText, type) - , r = filteredResponse - try { - resp.responseText = r - } catch (e) { - // can't assign this in IE<=8, just ignore - } - if (r) { - switch (type) { - case 'json': - try { - resp = win.JSON ? win.JSON.parse(r) : eval('(' + r + ')') - } catch (err) { - return error(resp, 'Could not parse JSON in response', err) - } - break - case 'js': - resp = eval(r) - break - case 'html': - resp = r - break - case 'xml': - resp = resp.responseXML - && resp.responseXML.parseError // IE trololo - && resp.responseXML.parseError.errorCode - && resp.responseXML.parseError.reason - ? null - : resp.responseXML - break - } - } - - self._responseArgs.resp = resp - self._fulfilled = true - fn(resp) - self._successHandler(resp) - while (self._fulfillmentHandlers.length > 0) { - resp = self._fulfillmentHandlers.shift()(resp) - } - - complete(resp) - } - - function timedOut() { - self._timedOut = true - self.request.abort() - } - - function error(resp, msg, t) { - resp = self.request - self._responseArgs.resp = resp - self._responseArgs.msg = msg - self._responseArgs.t = t - self._erred = true - while (self._errorHandlers.length > 0) { - self._errorHandlers.shift()(resp, msg, t) - } - complete(resp) - } - - this.request = getRequest.call(this, success, error) - } - - Reqwest.prototype = { - abort: function () { - this._aborted = true - this.request.abort() - } - - , retry: function () { - init.call(this, this.o, this.fn) - } - - /** - * Small deviation from the Promises A CommonJs specification - * http://wiki.commonjs.org/wiki/Promises/A - */ - - /** - * `then` will execute upon successful requests - */ - , then: function (success, fail) { - success = success || function () {} - fail = fail || function () {} - if (this._fulfilled) { - this._responseArgs.resp = success(this._responseArgs.resp) - } else if (this._erred) { - fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t) - } else { - this._fulfillmentHandlers.push(success) - this._errorHandlers.push(fail) - } - return this - } - - /** - * `always` will execute whether the request succeeds or fails - */ - , always: function (fn) { - if (this._fulfilled || this._erred) { - fn(this._responseArgs.resp) - } else { - this._completeHandlers.push(fn) - } - return this - } - - /** - * `fail` will execute when the request fails - */ - , fail: function (fn) { - if (this._erred) { - fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t) - } else { - this._errorHandlers.push(fn) - } - return this - } - , 'catch': function (fn) { - return this.fail(fn) - } - } - - function reqwest(o, fn) { - return new Reqwest(o, fn) - } - - // normalize newline variants according to spec -> CRLF - function normalize(s) { - return s ? s.replace(/\r?\n/g, '\r\n') : '' - } - - function serial(el, cb) { - var n = el.name - , t = el.tagName.toLowerCase() - , optCb = function (o) { - // IE gives value="" even where there is no value attribute - // 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273 - if (o && !o['disabled']) - cb(n, normalize(o['attributes']['value'] && o['attributes']['value']['specified'] ? o['value'] : o['text'])) - } - , ch, ra, val, i - - // don't serialize elements that are disabled or without a name - if (el.disabled || !n) return - - switch (t) { - case 'input': - if (!/reset|button|image|file/i.test(el.type)) { - ch = /checkbox/i.test(el.type) - ra = /radio/i.test(el.type) - val = el.value - // WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here - ;(!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val)) - } - break - case 'textarea': - cb(n, normalize(el.value)) - break - case 'select': - if (el.type.toLowerCase() === 'select-one') { - optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null) - } else { - for (i = 0; el.length && i < el.length; i++) { - el.options[i].selected && optCb(el.options[i]) - } - } - break - } - } - - // collect up all form elements found from the passed argument elements all - // the way down to child elements; pass a '<form>' or form fields. - // called with 'this'=callback to use for serial() on each element - function eachFormElement() { - var cb = this - , e, i - , serializeSubtags = function (e, tags) { - var i, j, fa - for (i = 0; i < tags.length; i++) { - fa = e[byTag](tags[i]) - for (j = 0; j < fa.length; j++) serial(fa[j], cb) - } - } - - for (i = 0; i < arguments.length; i++) { - e = arguments[i] - if (/input|select|textarea/i.test(e.tagName)) serial(e, cb) - serializeSubtags(e, [ 'input', 'select', 'textarea' ]) - } - } - - // standard query string style serialization - function serializeQueryString() { - return reqwest.toQueryString(reqwest.serializeArray.apply(null, arguments)) - } - - // { 'name': 'value', ... } style serialization - function serializeHash() { - var hash = {} - eachFormElement.apply(function (name, value) { - if (name in hash) { - hash[name] && !isArray(hash[name]) && (hash[name] = [hash[name]]) - hash[name].push(value) - } else hash[name] = value - }, arguments) - return hash - } - - // [ { name: 'name', value: 'value' }, ... ] style serialization - reqwest.serializeArray = function () { - var arr = [] - eachFormElement.apply(function (name, value) { - arr.push({name: name, value: value}) - }, arguments) - return arr - } - - reqwest.serialize = function () { - if (arguments.length === 0) return '' - var opt, fn - , args = Array.prototype.slice.call(arguments, 0) - - opt = args.pop() - opt && opt.nodeType && args.push(opt) && (opt = null) - opt && (opt = opt.type) - - if (opt == 'map') fn = serializeHash - else if (opt == 'array') fn = reqwest.serializeArray - else fn = serializeQueryString - - return fn.apply(null, args) - } - - reqwest.toQueryString = function (o, trad) { - var prefix, i - , traditional = trad || false - , s = [] - , enc = encodeURIComponent - , add = function (key, value) { - // If value is a function, invoke it and return its value - value = ('function' === typeof value) ? value() : (value == null ? '' : value) - s[s.length] = enc(key) + '=' + enc(value) - } - // If an array was passed in, assume that it is an array of form elements. - if (isArray(o)) { - for (i = 0; o && i < o.length; i++) add(o[i]['name'], o[i]['value']) - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for (prefix in o) { - if (o.hasOwnProperty(prefix)) buildParams(prefix, o[prefix], traditional, add) - } - } - - // spaces should be + according to spec - return s.join('&').replace(/%20/g, '+') - } - - function buildParams(prefix, obj, traditional, add) { - var name, i, v - , rbracket = /\[\]$/ - - if (isArray(obj)) { - // Serialize array item. - for (i = 0; obj && i < obj.length; i++) { - v = obj[i] - if (traditional || rbracket.test(prefix)) { - // Treat each array item as a scalar. - add(prefix, v) - } else { - buildParams(prefix + '[' + (typeof v === 'object' ? i : '') + ']', v, traditional, add) - } - } - } else if (obj && obj.toString() === '[object Object]') { - // Serialize object item. - for (name in obj) { - buildParams(prefix + '[' + name + ']', obj[name], traditional, add) - } - - } else { - // Serialize scalar item. - add(prefix, obj) - } - } - - reqwest.getcallbackPrefix = function () { - return callbackPrefix - } - - // jQuery and Zepto compatibility, differences can be remapped here so you can call - // .ajax.compat(options, callback) - reqwest.compat = function (o, fn) { - if (o) { - o['type'] && (o['method'] = o['type']) && delete o['type'] - o['dataType'] && (o['type'] = o['dataType']) - o['jsonpCallback'] && (o['jsonpCallbackName'] = o['jsonpCallback']) && delete o['jsonpCallback'] - o['jsonp'] && (o['jsonpCallback'] = o['jsonp']) - } - return new Reqwest(o, fn) - } - - reqwest.ajaxSetup = function (options) { - options = options || {} - for (var k in options) { - globalSetupOptions[k] = options[k] - } - } - - return reqwest -}); - -},{}],28:[function(_dereq_,module,exports){ -/** - * @module Shape - * @submodule 3D Primitives - * @for p5 - * @requires core - * @requires p5.Geometry3D - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -_dereq_('./p5.Geometry3D'); - -/** - * Draw a plane with given a width and height - * @method plane - * @param {Number} width width of the plane - * @param {Number} height height of the plane - * @return {p5} the p5 object - * @example - * <div> - * <code> - * //draw a plane with width 200 and height 200 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * plane(200, 200); - * } - * </code> - * </div> - */ -p5.prototype.plane = function(width, height){ - - width = width || 50; - height = height || 50; - - //details for plane are highly optional - var detailX = typeof arguments[2] === Number ? arguments[2] : 1; - var detailY = typeof arguments[3] === Number ? arguments[3] : 1; - - var gId = 'plane|'+width+'|'+height+'|'+detailX+'|'+detailY; - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createPlane = function(u, v){ - var x = 2 * width * u - width; - var y = 2 * height * v - height; - var z = 0; - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry(createPlane, detailX, detailY); - - var obj = geometry3d.generateObj(); - - this._renderer.initBuffer(gId, [obj]); - - } - - this._renderer.drawBuffer(gId); - -}; - -/** - * Draw a sphere with given raduis - * @method sphere - * @param {Number} radius radius of circle - * @param {Number} [detail] number of segments, - * the more segments the smoother geometry - * default is 24. Avoid detail number above - * 150, it may crash the browser. - * @example - * <div> - * <code> - * // draw a sphere with radius 200 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.sphere = function(radius, detail){ - - radius = radius || 50; - - var detailX = detail || 24; - var detailY = detail || 16; - - var gId = 'sphere|'+radius+'|'+detailX+'|'+detailY; - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createSphere = function(u, v){ - var theta = 2 * Math.PI * u; - var phi = Math.PI * v - Math.PI / 2; - var x = radius * Math.cos(phi) * Math.sin(theta); - var y = radius * Math.sin(phi); - var z = radius * Math.cos(phi) * Math.cos(theta); - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry(createSphere, detailX, detailY); - - var obj = geometry3d.generateObj(true, true); - - this._renderer.initBuffer(gId, [obj]); - } - - this._renderer.drawBuffer(gId); - - return this; -}; - -/** - * Draw an ellipsoid with given radius - * @method ellipsoid - * @param {Number} radiusx xradius of circle - * @param {Number} radiusy yradius of circle - * @param {Number} radiusz zradius of circle - * @param {Number} [detail] Number of segments. - * The more segments, the smoother the - * geometry (default is 24). Avoid detail - * number above 150. It may crash the - * browser. - * @return {p5} the p5 object - * @example - * <div> - * <code> - * // draw an ellipsoid with radius 200, 300 and 400 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * ellipsoid(200,300,400); - * } - * </code> - * </div> - */ -p5.prototype.ellipsoid = function(radiusx, radiusy, radiusz, detail){ - - radiusx = radiusx || 50; - radiusy = radiusy || 50; - radiusz = radiusz || 50; - - var detailX = detail || 24; - var detailY = detail || 24; - - var gId = 'ellipsoid|'+radiusx+'|'+radiusy+ - '|'+radiusz+'|'+detailX+'|'+detailY; - - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createEllipsoid = function(u, v){ - var theta = 2 * Math.PI * u; - var phi = Math.PI * v - Math.PI / 2; - var x = radiusx * Math.cos(phi) * Math.sin(theta); - var y = radiusy * Math.sin(phi); - var z = radiusz * Math.cos(phi) * Math.cos(theta); - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry(createEllipsoid, detailX, detailY); - - var obj = geometry3d.generateObj(true, true); - - this._renderer.initBuffer(gId, [obj]); - } - - this._renderer.drawBuffer(gId); - - return this; -}; - -/** - * Draw a cylinder with given radius and height - * @method cylinder - * @param {Number} radius radius of the surface - * @param {Number} height height of the cylinder - * @param {Number} [detail] number of segments, - * the more segments the smoother geometry - * default is 24. Avoid detail number above - * 150. It may crash the browser. - * @return {p5} the p5 object - * @example - * <div> - * <code> - * //draw a spinning cylinder with radius 200 and height 200 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * rotateX(frameCount * 0.01); - * rotateZ(frameCount * 0.01); - * cylinder(200, 200); - * } - * </code> - * </div> - */ -p5.prototype.cylinder = function(radius, height, detail){ - - radius = radius || 50; - height = height || 50; - - var detailX = detail || 24; - var detailY = detail || 16; - - var gId = 'cylinder|'+radius+'|'+height+'|'+detailX+'|'+detailY; - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createCylinder = function(u, v){ - var theta = 2 * Math.PI * u; - var x = radius * Math.sin(theta); - var y = 2 * height * v - height; - var z = radius * Math.cos(theta); - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry(createCylinder, detailX, detailY); - var obj = geometry3d.generateObj(true); - - var createTop = function(u, v){ - var theta = 2 * Math.PI * u; - var x = radius * Math.sin(-theta); - var y = height; - var z = radius * Math.cos(theta); - if(v === 0){ - return new p5.Vector(0, height, 0); - } - else{ - return new p5.Vector(x, y, z); - } - }; - - var geometry3d1 = new p5.Geometry3D(); - geometry3d1.parametricGeometry( - createTop, detailX, 1); - var obj1 = geometry3d1.generateObj(); - - var createBottom = function(u, v){ - var theta = 2 * Math.PI * u; - var x = radius * Math.sin(theta); - var y = -height; - var z = radius * Math.cos(theta); - if(v === 0){ - return new p5.Vector(0, -height, 0); - }else{ - return new p5.Vector(x, y, z); - } - }; - - var geometry3d2 = new p5.Geometry3D(); - geometry3d2.parametricGeometry( - createBottom, detailX, 1); - var obj2 = geometry3d2.generateObj(); - - - this._renderer.initBuffer(gId, [obj, obj1, obj2]); - } - - this._renderer.drawBuffer(gId); - - return this; -}; - - -/** - * Draw a cone with given radius and height - * @method cone - * @param {Number} radius radius of the bottom surface - * @param {Number} height height of the cone - * @param {Number} [detail] number of segments, - * the more segments the smoother geometry - * default is 24. Avoid detail number above - * 150. It may crash the browser. - * @example - * <div> - * <code> - * //draw a spinning cone with radius 200 and height 200 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * rotateX(frameCount * 0.01); - * rotateZ(frameCount * 0.01); - * cone(200, 200); - * } - * </code> - * </div> - */ -p5.prototype.cone = function(radius, height, detail){ - - radius = radius || 50; - height = height || 50; - - var detailX = detail || 24; - var detailY = detail || 16; - - var gId = 'cone|'+radius+'|'+height+'|'+detailX+'|'+detailY; - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createCone = function(u, v){ - var theta = 2 * Math.PI * u; - var x = radius * (1 - v) * Math.sin(theta); - var y = 2 * height * v - height; - var z = radius * (1 - v) * Math.cos(theta); - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry(createCone, detailX, detailY); - var obj = geometry3d.generateObj(true); - - var geometry3d1 = new p5.Geometry3D(); - var createBottom = function(u, v){ - var theta = 2 * Math.PI * u; - var x = radius * (1 - v) * Math.sin(-theta); - var y = -height; - var z = radius * (1 - v) * Math.cos(theta); - return new p5.Vector(x, y, z); - }; - - geometry3d1.parametricGeometry( - createBottom, detailX, 1); - var obj1 = geometry3d1.generateObj(); - - this._renderer.initBuffer(gId, [obj, obj1]); - } - - this._renderer.drawBuffer(gId); - - return this; -}; - - -/** - * Draw a torus with given radius and tube radius - * @method torus - * @param {Number} radius radius of the whole ring - * @param {Number} tubeRadius radius of the tube - * @param {Number} [detail] number of segments, - * the more segments the smoother geometry - * default is 24. Avoid detail number above - * 150. It may crash the browser. - * @example - * <div> - * <code> - * //draw a spinning torus with radius 200 and tube radius 60 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * rotateX(frameCount * 0.01); - * rotateY(frameCount * 0.01); - * torus(200, 60); - * } - * </code> - * </div> - */ -p5.prototype.torus = function(radius, tubeRadius, detail){ - - radius = radius || 50; - tubeRadius = tubeRadius || 10; - - var detailX = detail || 24; - var detailY = detail || 16; - - var gId = 'torus|'+radius+'|'+tubeRadius+'|'+detailX+'|'+detailY; - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createTorus = function(u, v){ - var theta = 2 * Math.PI * u; - var phi = 2 * Math.PI * v; - var x = (radius + tubeRadius * Math.cos(phi)) * Math.cos(theta); - var y = (radius + tubeRadius * Math.cos(phi)) * Math.sin(theta); - var z = tubeRadius * Math.sin(phi); - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry(createTorus, detailX, detailY); - - var obj = geometry3d.generateObj(true); - - this._renderer.initBuffer(gId, [obj]); - } - - this._renderer.drawBuffer(gId); - - return this; -}; - -/** - * Draw a box with given width, height and depth - * @method box - * @param {Number} width width of the box - * @param {Number} height height of the box - * @param {Number} depth depth of the box - * @return {p5} the p5 object - * @example - * <div> - * <code> - * //draw a spinning box with width, height and depth 200 - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * rotateX(frameCount * 0.01); - * rotateY(frameCount * 0.01); - * box(200, 200, 200); - * } - * </code> - * </div> - */ -p5.prototype.box = function(width, height, depth){ - - width = width || 50; - height = height || width; - depth = depth || width; - - //details for box are highly optional - var detailX = typeof arguments[3] === Number ? arguments[3] : 1; - var detailY = typeof arguments[4] === Number ? arguments[4] : 1; - - var gId = 'cube|'+width+'|'+height+'|'+depth+'|'+detailX+'|'+detailY; - - if(!this._renderer.geometryInHash(gId)){ - - var geometry3d = new p5.Geometry3D(); - - var createPlane1 = function(u, v){ - var x = 2 * width * u - width; - var y = 2 * height * v - height; - var z = depth; - return new p5.Vector(x, y, z); - }; - var createPlane2 = function(u, v){ - var x = 2 * width * ( 1 - u ) - width; - var y = 2 * height * v - height; - var z = -depth; - return new p5.Vector(x, y, z); - }; - var createPlane3 = function(u, v){ - var x = 2 * width * ( 1 - u ) - width; - var y = height; - var z = 2 * depth * v - depth; - return new p5.Vector(x, y, z); - }; - var createPlane4 = function(u, v){ - var x = 2 * width * u - width; - var y = -height; - var z = 2 * depth * v - depth; - return new p5.Vector(x, y, z); - }; - var createPlane5 = function(u, v){ - var x = width; - var y = 2 * height * u - height; - var z = 2 * depth * v - depth; - return new p5.Vector(x, y, z); - }; - var createPlane6 = function(u, v){ - var x = -width; - var y = 2 * height * ( 1 - u ) - height; - var z = 2 * depth * v - depth; - return new p5.Vector(x, y, z); - }; - - geometry3d.parametricGeometry( - createPlane1, detailX, detailY, geometry3d.vertices.length); - geometry3d.parametricGeometry( - createPlane2, detailX, detailY, geometry3d.vertices.length); - geometry3d.parametricGeometry( - createPlane3, detailX, detailY, geometry3d.vertices.length); - geometry3d.parametricGeometry( - createPlane4, detailX, detailY, geometry3d.vertices.length); - geometry3d.parametricGeometry( - createPlane5, detailX, detailY, geometry3d.vertices.length); - geometry3d.parametricGeometry( - createPlane6, detailX, detailY, geometry3d.vertices.length); - - var obj = geometry3d.generateObj(); - - this._renderer.initBuffer(gId, [obj]); - } - - this._renderer.drawBuffer(gId); - - return this; - -}; - -module.exports = p5; -},{"../core/core":48,"./p5.Geometry3D":34}],29:[function(_dereq_,module,exports){ -/** - * @module Lights, Camera - * @submodule Camera - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Sets camera position - * @method camera - * @param {Number} x camera postion value on x axis - * @param {Number} y camera postion value on y axis - * @param {Number} z camera postion value on z axis - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * function draw(){ - * //move the camera away from the plane by a sin wave - * camera(0, 0, sin(frameCount * 0.01) * 100); - * plane(120, 120); - * } - * </code> - * </div> - */ -p5.prototype.camera = function(x, y, z){ - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'camera', - args, - ['Number', 'Number', 'Number'] - ); - //what it manipulates is the model view matrix - this._renderer.translate(-x, -y, -z); -}; - -/** - * Sets perspective camera - * @method perspective - * @param {Number} fovy camera frustum vertical field of view, - * from bottom to top of view, in degrees - * @param {Number} aspect camera frustum aspect ratio - * @param {Number} near frustum near plane length - * @param {Number} far frustum far plane length - * @return {p5} the p5 object - * @example - * <div> - * <code> - * //drag mouse to toggle the world! - * //you will see there's a vanish point - * function setup(){ - * createCanvas(100, 100, WEBGL); - * perspective(60 / 180 * PI, width/height, 0.1, 100); - * } - * function draw(){ - * background(200); - * orbitControl(); - * for(var i = -1; i < 2; i++){ - * for(var j = -2; j < 3; j++){ - * push(); - * translate(i*160, 0, j*160); - * box(40, 40, 40); - * pop(); - * } - * } - * } - * </code> - * </div> - */ -p5.prototype.perspective = function(fovy,aspect,near,far) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'perspective', - args, - ['Number', 'Number', 'Number', 'Number'] - ); - this._renderer.uPMatrix = p5.Matrix.identity(); - this._renderer.uPMatrix.perspective(fovy,aspect,near,far); - this._renderer._setCamera = true; -}; - -/** - * Setup ortho camera - * @method ortho - * @param {Number} left camera frustum left plane - * @param {Number} right camera frustum right plane - * @param {Number} bottom camera frustum bottom plane - * @param {Number} top camera frustum top plane - * @param {Number} near camera frustum near plane - * @param {Number} far camera frustum far plane - * @return {p5} the p5 object - * @example - * <div> - * <code> - * //drag mouse to toggle the world! - * //there's no vanish point - * function setup(){ - * createCanvas(100, 100, WEBGL); - * ortho(-width/2, width/2, height/2, -height/2, 0.1, 100); - * } - * function draw(){ - * background(200); - * orbitControl(); - * for(var i = -1; i < 2; i++){ - * for(var j = -2; j < 3; j++){ - * push(); - * translate(i*160, 0, j*160); - * box(40, 40, 40); - * pop(); - * } - * } - * } - * </code> - * </div> - */ -p5.prototype.ortho = function(left,right,bottom,top,near,far) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'ortho', - args, - ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'] - ); - left /= this.width; - right /= this.width; - top /= this.height; - bottom /= this.height; - this._renderer.uPMatrix = p5.Matrix.identity(); - this._renderer.uPMatrix.ortho(left,right,bottom,top,near,far); - this._renderer._setCamera = true; -}; - -module.exports = p5; - -},{"../core/core":48}],30:[function(_dereq_,module,exports){ -//@TODO: documentation of immediate mode - -'use strict'; - -var p5 = _dereq_('../core/core'); - -////////////////////////////////////////////// -// _primitives2D in 3D space -////////////////////////////////////////////// - -p5.Renderer3D.prototype._primitives2D = function(arr){ - this._setDefaultCamera(); - var gl = this.GL; - var shaderProgram = this._getColorVertexShader(); - - //create vertice buffer - var vertexPositionBuffer = this.verticeBuffer; - gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer); - - gl.bufferData( - gl.ARRAY_BUFFER, new Float32Array(arr), gl.STATIC_DRAW); - gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, - 3, gl.FLOAT, false, 0, 0); - - //create vertexcolor buffer - var vertexColorBuffer = this.colorBuffer; - gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer); - var color = this._getCurColor(); - var colors = []; - for(var i = 0; i < arr.length / 3; i++){ - colors = colors.concat(color); - } - - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); - gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, - 4, gl.FLOAT, false, 0, 0); - - //matrix - var mId = 'vertexColorVert|vertexColorFrag'; - this.setMatrixUniforms(mId); -}; - -p5.Renderer3D.prototype.point = function(x, y, z){ - var gl = this.GL; - this._primitives2D([x, y, z]); - gl.drawArrays(gl.POINTS, 0, 1); - return this; -}; - -p5.Renderer3D.prototype.line = function(x1, y1, z1, x2, y2, z2){ - var gl = this.GL; - this._primitives2D([x1, y1, z1, x2, y2, z2]); - gl.drawArrays(gl.LINES, 0, 2); - return this; -}; - -p5.Renderer3D.prototype.triangle = function -(x1, y1, z1, x2, y2, z2, x3, y3, z3){ - var gl = this.GL; - this._primitives2D([x1, y1, z1, x2, y2, z2, x3, y3, z3]); - this._strokeCheck(); - gl.drawArrays(gl.TRIANGLES, 0, 3); - return this; -}; - -//@TODO: how to define the order of 4 points -p5.Renderer3D.prototype.quad = function -(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4){ - var gl = this.GL; - this._primitives2D( - [x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4]); - this._strokeCheck(); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - return this; -}; - -p5.Renderer3D.prototype.beginShape = function(mode){ - this.shapeMode = mode; - this.verticeStack = []; - return this; -}; - -p5.Renderer3D.prototype.vertex = function(x, y, z){ - this.verticeStack.push(x, y, z); - return this; -}; - -p5.Renderer3D.prototype.endShape = function(){ - var gl = this.GL; - this._primitives2D(this.verticeStack); - this.verticeStack = []; - - switch(this.shapeMode){ - case 'POINTS': - gl.drawArrays(gl.POINTS, 0, 1); - break; - case 'LINES': - gl.drawArrays(gl.LINES, 0, 2); - break; - case 'TRIANGLES': - this._strokeCheck(); - gl.drawArrays(gl.TRIANGLES, 0, 3); - break; - case 'TRIANGLE_STRIP': - this._strokeCheck(); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - break; - default: - this._strokeCheck(); - gl.drawArrays(gl.TRIANGLES, 0, 3); - break; - } - return this; -}; - -//@TODO: figure out how to actually do stroke on shapes in 3D -p5.Renderer3D.prototype._strokeCheck = function(){ - if(this.drawMode === 'stroke'){ - throw new Error( - 'stroke for shapes in 3D not yet implemented, use fill for now :(' - ); - } -}; - -//@TODO -p5.Renderer3D.prototype.strokeWeight = function() { - throw new Error('strokeWeight for 3d not yet implemented'); -}; - -////////////////////////////////////////////// -// COLOR -////////////////////////////////////////////// - -p5.Renderer3D.prototype.fill = function(r, g, b, a) { - var color = this._pInst.color.apply(this, arguments); - var colorNormalized = color._array; - this.curColor = colorNormalized; - this.drawMode = 'fill'; - return this; -}; - -p5.Renderer3D.prototype.stroke = function(r, g, b, a) { - var color = this._pInst.color.apply(this, arguments); - var colorNormalized = color._array; - this.curColor = colorNormalized; - this.drawMode = 'stroke'; - return this; -}; - -p5.Renderer3D.prototype._getColorVertexShader = function(){ - var gl = this.GL; - var mId = 'vertexColorVert|vertexColorFrag'; - var shaderProgram; - - if(!this.materialInHash(mId)){ - shaderProgram = - this.initShaders('vertexColorVert', 'vertexColorFrag', true); - this.mHash[mId] = shaderProgram; - shaderProgram.vertexColorAttribute = - gl.getAttribLocation(shaderProgram, 'aVertexColor'); - gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute); - }else{ - shaderProgram = this.mHash[mId]; - } - return shaderProgram; -}; - -module.exports = p5.Renderer3D; - -},{"../core/core":48}],31:[function(_dereq_,module,exports){ -'use strict'; - -var p5 = _dereq_('../core/core'); - -//@TODO: implement full orbit controls including -//pan, zoom, quaternion rotation, etc. -p5.prototype.orbitControl = function(){ - if(this.mouseIsPressed){ - this.rotateY((this.mouseX - this.width / 2) / (this.width / 2)); - this.rotateX((this.mouseY - this.height / 2) / (this.width / 2)); - } - return this; -}; - -module.exports = p5; -},{"../core/core":48}],32:[function(_dereq_,module,exports){ -/** - * @module Lights, Camera - * @submodule Lights - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Creates an ambient light with a color - * @method ambientLight - * @param {Number|Array|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] optional: green or saturation value - * @param {Number} [v3] optional: blue or brightness value - * @param {Number} [a] optional: opacity - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * function draw(){ - * background(0); - * ambientLight(150); - * ambientMaterial(250); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.ambientLight = function(v1, v2, v3, a){ - var gl = this._renderer.GL; - var shaderProgram = this._renderer._getShader( - 'lightVert', 'lightTextureFrag'); - - gl.useProgram(shaderProgram); - shaderProgram.uAmbientColor = gl.getUniformLocation( - shaderProgram, - 'uAmbientColor[' + this._renderer.ambientLightCount + ']'); - - var color = this._renderer._pInst.color.apply( - this._renderer._pInst, arguments); - var colors = color._array; - - gl.uniform3f( shaderProgram.uAmbientColor, - colors[0], colors[1], colors[2]); - - //in case there's no material color for the geometry - shaderProgram.uMaterialColor = gl.getUniformLocation( - shaderProgram, 'uMaterialColor' ); - gl.uniform4f( shaderProgram.uMaterialColor, 1, 1, 1, 1); - - this._renderer.ambientLightCount ++; - shaderProgram.uAmbientLightCount = - gl.getUniformLocation(shaderProgram, 'uAmbientLightCount'); - gl.uniform1i(shaderProgram.uAmbientLightCount, - this._renderer.ambientLightCount); - - return this; -}; - -/** - * Creates a directional light with a color and a direction - * @method directionalLight - * @param {Number|Array|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] optional: green or saturation value - * @param {Number} [v3] optional: blue or brightness value - * @param {Number} [a] optional: opacity - * @param {Number|p5.Vector} x x axis direction or a p5.Vector - * @param {Number} [y] optional: y axis direction - * @param {Number} [z] optional: z axis direction - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * function draw(){ - * background(0); - * //move your mouse to change light direction - * var dirX = (mouseX / width - 0.5) *2; - * var dirY = (mouseY / height - 0.5) *(-2); - * directionalLight(250, 250, 250, dirX, dirY, 0.25); - * ambientMaterial(250); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.directionalLight = function(v1, v2, v3, a, x, y, z) { - // TODO(jgessner): Find an example using this and profile it. - // var args = new Array(arguments.length); - // for (var i = 0; i < args.length; ++i) { - // args[i] = arguments[i]; - // } - // this._validateParameters( - // 'directionalLight', - // args, - // [ - // //rgbaxyz - // ['Number', 'Number', 'Number', 'Number', 'Number', 'Number', 'Number'], - // //rgbxyz - // ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'], - // //caxyz - // ['Number', 'Number', 'Number', 'Number', 'Number'], - // //cxyz - // ['Number', 'Number', 'Number', 'Number'], - // ['String', 'Number', 'Number', 'Number'], - // ['Array', 'Number', 'Number', 'Number'], - // ['Object', 'Number', 'Number', 'Number'], - // //rgbavector - // ['Number', 'Number', 'Number', 'Number', 'Object'], - // //rgbvector - // ['Number', 'Number', 'Number', 'Object'], - // //cavector - // ['Number', 'Number', 'Object'], - // //cvector - // ['Number', 'Object'], - // ['String', 'Object'], - // ['Array', 'Object'], - // ['Object', 'Object'] - // ] - // ); - - var gl = this._renderer.GL; - var shaderProgram = this._renderer._getShader( - 'lightVert', 'lightTextureFrag'); - - gl.useProgram(shaderProgram); - shaderProgram.uDirectionalColor = gl.getUniformLocation( - shaderProgram, - 'uDirectionalColor[' + this._renderer.directionalLightCount + ']'); - - //@TODO: check parameters number - var color = this._renderer._pInst.color.apply( - this._renderer._pInst, [v1, v2, v3]); - var colors = color._array; - - gl.uniform3f( shaderProgram.uDirectionalColor, - colors[0], colors[1], colors[2]); - - var _x, _y, _z; - - if(typeof arguments[arguments.length-1] === 'number'){ - _x = arguments[arguments.length-3]; - _y = arguments[arguments.length-2]; - _z = arguments[arguments.length-1]; - - }else{ - try{ - _x = arguments[arguments.length-1].x; - _y = arguments[arguments.length-1].y; - _z = arguments[arguments.length-1].z; - } - catch(error){ - throw error; - } - } - - shaderProgram.uLightingDirection = gl.getUniformLocation( - shaderProgram, - 'uLightingDirection[' + this._renderer.directionalLightCount + ']'); - gl.uniform3f( shaderProgram.uLightingDirection, _x, _y, _z); - - //in case there's no material color for the geometry - shaderProgram.uMaterialColor = gl.getUniformLocation( - shaderProgram, 'uMaterialColor' ); - gl.uniform4f( shaderProgram.uMaterialColor, 1, 1, 1, 1); - - this._renderer.directionalLightCount ++; - shaderProgram.uDirectionalLightCount = - gl.getUniformLocation(shaderProgram, 'uDirectionalLightCount'); - gl.uniform1i(shaderProgram.uDirectionalLightCount, - this._renderer.directionalLightCount); - - return this; -}; - -/** - * Creates a point light with a color and a light position - * @method pointLight - * @param {Number|Array|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] optional: green or saturation value - * @param {Number} [v3] optional: blue or brightness value - * @param {Number} [a] optional: opacity - * @param {Number|p5.Vector} x x axis position or a p5.Vector - * @param {Number} [y] optional: y axis position - * @param {Number} [z] optional: z axis position - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * function draw(){ - * background(0); - * //move your mouse to change light position - * var locY = (mouseY / height - 0.5) *(-2); - * var locX = (mouseX / width - 0.5) *2; - * //to set the light position, - * //think of the world's coordinate as: - * // -1,1 -------- 1,1 - * // | | - * // | | - * // | | - * // -1,-1---------1,-1 - * pointLight(250, 250, 250, locX, locY, 0); - * ambientMaterial(250); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.pointLight = function(v1, v2, v3, a, x, y, z) { - // TODO(jgessner): Find an example using this and profile it. - // var args = new Array(arguments.length); - // for (var i = 0; i < args.length; ++i) { - // args[i] = arguments[i]; - // } - // this._validateParameters( - // 'pointLight', - // arguments, - // [ - // //rgbaxyz - // ['Number', 'Number', 'Number', 'Number', 'Number', 'Number', 'Number'], - // //rgbxyz - // ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'], - // //caxyz - // ['Number', 'Number', 'Number', 'Number', 'Number'], - // //cxyz - // ['Number', 'Number', 'Number', 'Number'], - // ['String', 'Number', 'Number', 'Number'], - // ['Array', 'Number', 'Number', 'Number'], - // ['Object', 'Number', 'Number', 'Number'], - // //rgbavector - // ['Number', 'Number', 'Number', 'Number', 'Object'], - // //rgbvector - // ['Number', 'Number', 'Number', 'Object'], - // //cavector - // ['Number', 'Number', 'Object'], - // //cvector - // ['Number', 'Object'], - // ['String', 'Object'], - // ['Array', 'Object'], - // ['Object', 'Object'] - // ] - // ); - - var gl = this._renderer.GL; - var shaderProgram = this._renderer._getShader( - 'lightVert', 'lightTextureFrag'); - - gl.useProgram(shaderProgram); - shaderProgram.uPointLightColor = gl.getUniformLocation( - shaderProgram, - 'uPointLightColor[' + this._renderer.pointLightCount + ']'); - - //@TODO: check parameters number - var color = this._renderer._pInst.color.apply( - this._renderer._pInst, [v1, v2, v3]); - var colors = color._array; - - gl.uniform3f( shaderProgram.uPointLightColor, - colors[0], colors[1], colors[2]); - - var _x, _y, _z; - - if(typeof arguments[arguments.length-1] === 'number'){ - _x = arguments[arguments.length-3]; - _y = arguments[arguments.length-2]; - _z = arguments[arguments.length-1]; - - }else{ - try{ - _x = arguments[arguments.length-1].x; - _y = arguments[arguments.length-1].y; - _z = arguments[arguments.length-1].z; - } - catch(error){ - throw error; - } - } - - shaderProgram.uPointLightLocation = gl.getUniformLocation( - shaderProgram, - 'uPointLightLocation[' + this._renderer.pointLightCount + ']'); - gl.uniform3f( shaderProgram.uPointLightLocation, _x, _y, _z); - - //in case there's no material color for the geometry - shaderProgram.uMaterialColor = gl.getUniformLocation( - shaderProgram, 'uMaterialColor' ); - gl.uniform4f( shaderProgram.uMaterialColor, 1, 1, 1, 1); - - this._renderer.pointLightCount ++; - shaderProgram.uPointLightCount = - gl.getUniformLocation(shaderProgram, 'uPointLightCount'); - gl.uniform1i(shaderProgram.uPointLightCount, - this._renderer.pointLightCount); - - return this; -}; - -module.exports = p5; - -},{"../core/core":48}],33:[function(_dereq_,module,exports){ -/** - * @module Lights, Camera - * @submodule Material - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -//require('./p5.Texture'); - -/** - * Normal material for geometry - * @method normalMaterial - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(0); - * normalMaterial(); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.normalMaterial = function(){ - this._renderer._getShader('normalVert', 'normalFrag'); - return this; -}; - -/** - * Texture for geometry - * @method texture - * @return {p5} the p5 object - * @example - * <div> - * <code> - * var img; - * function setup(){ - * createCanvas(100, 100, WEBGL); - * img = loadImage("assets/laDefense.jpg"); - * } - * - * function draw(){ - * background(0); - * rotateZ(frameCount * 0.01); - * rotateX(frameCount * 0.01); - * rotateY(frameCount * 0.01); - * //pass image as texture - * texture(img); - * box(200, 200, 200); - * } - * </code> - * </div> - */ -p5.prototype.texture = function(image){ - var gl = this._renderer.GL; - var shaderProgram = this._renderer._getShader('lightVert', - 'lightTextureFrag'); - gl.useProgram(shaderProgram); - if (image instanceof p5.Image) { - //check if image is already used as texture - if(!image.isTexture){ - //createTexture and set isTexture to true - var tex = gl.createTexture(); - image.createTexture(tex); - gl.bindTexture(gl.TEXTURE_2D, tex); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); - image._setProperty('isTexture', true); - } - //otherwise we're good to bind texture without creating - //a new one on the gl - else { - //TODO - } - image.loadPixels(); - var data = new Uint8Array(image.pixels); - gl.texImage2D(gl.TEXTURE_2D, 0, - gl.RGBA, image.width, image.height, - 0, gl.RGBA, gl.UNSIGNED_BYTE, data); - } - //if param is a video - else if (image instanceof p5.MediaElement){ - if(!image.loadedmetadata) {return;} - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, - gl.UNSIGNED_BYTE, image.elt); - } - else { - //@TODO handle following cases: - //- 2D canvas (p5 inst) - } - if (_isPowerOf2(image.width) && _isPowerOf2(image.height)) { - gl.generateMipmap(gl.TEXTURE_2D); - } else { - //@TODO this is problematic - //image.width = _nextHighestPOT(image.width); - //image.height = _nextHighestPOT(image.height); - gl.texParameteri(gl.TEXTURE_2D, - gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, - gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, - gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, - gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - //this is where we'd activate multi textures - //eg. gl.activeTexture(gl.TEXTURE0 + (unit || 0)); - //but for now we just have a single texture. - //@TODO need to extend this functionality - //gl.activeTexture(gl.TEXTURE0 + 0); - //gl.bindTexture(gl.TEXTURE_2D, tex); - gl.uniform1i(gl.getUniformLocation(shaderProgram, 'uSampler'), 0); - gl.uniform1i(gl.getUniformLocation(shaderProgram, 'isTexture'), true); - return this; -}; - -/** - * Helper functions; Checks whether val is a pot - * more info on power of 2 here: - * https://www.opengl.org/wiki/NPOT_Texture - * @param {Number} value - * @return {Boolean} - */ -function _isPowerOf2 (value){ - return (value & (value - 1)) === 0; -} - -/** - * returns the next highest power of 2 value - * @param {Number} value [description] - * @return {Number} [description] - */ -// function _nextHighestPOT (value){ -// --value; -// for (var i = 1; i < 32; i <<= 1) { -// value = value | value >> i; -// } -// return value + 1; -// } - -/** - * Basic material for geometry with a given color - * @method basicMaterial - * @param {Number|Array|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] optional: green or saturation value - * @param {Number} [v3] optional: blue or brightness value - * @param {Number} [a] optional: opacity - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(0); - * basicMaterial(250, 0, 0); - * rotateX(frameCount * 0.01); - * rotateY(frameCount * 0.01); - * rotateZ(frameCount * 0.01); - * box(200, 200, 200); - * } - * </code> - * </div> - */ -p5.prototype.basicMaterial = function(v1, v2, v3, a){ - var gl = this._renderer.GL; - - var shaderProgram = this._renderer._getShader('normalVert', 'basicFrag'); - - gl.useProgram(shaderProgram); - shaderProgram.uMaterialColor = gl.getUniformLocation( - shaderProgram, 'uMaterialColor' ); - - var color = this._renderer._pInst.color.apply( - this._renderer._pInst, arguments); - var colors = color._array; - - gl.uniform4f( shaderProgram.uMaterialColor, - colors[0], colors[1], colors[2], colors[3]); - - return this; - -}; - -/** - * Ambient material for geometry with a given color - * @method ambientMaterial - * @param {Number|Array|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] optional: green or saturation value - * @param {Number} [v3] optional: blue or brightness value - * @param {Number} [a] optional: opacity -* @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * function draw(){ - * background(0); - * ambientLight(100); - * pointLight(250, 250, 250, 100, 100, 0); - * ambientMaterial(250); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.ambientMaterial = function(v1, v2, v3, a) { - var gl = this._renderer.GL; - var shaderProgram = - this._renderer._getShader('lightVert', 'lightTextureFrag'); - - gl.useProgram(shaderProgram); - shaderProgram.uMaterialColor = gl.getUniformLocation( - shaderProgram, 'uMaterialColor' ); - - var color = this._renderer._pInst.color.apply( - this._renderer._pInst, arguments); - var colors = color._array; - - gl.uniform4f(shaderProgram.uMaterialColor, - colors[0], colors[1], colors[2], colors[3]); - - shaderProgram.uSpecular = gl.getUniformLocation( - shaderProgram, 'uSpecular' ); - gl.uniform1i(shaderProgram.uSpecular, false); - - gl.uniform1i(gl.getUniformLocation(shaderProgram, 'isTexture'), false); - - return this; -}; - -/** - * Specular material for geometry with a given color - * @method specularMaterial - * @param {Number|Array|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] optional: green or saturation value - * @param {Number} [v3] optional: blue or brightness value - * @param {Number} [a] optional: opacity - * @return {p5} the p5 object - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * function draw(){ - * background(0); - * ambientLight(100); - * pointLight(250, 250, 250, 100, 100, 0); - * specularMaterial(250); - * sphere(200); - * } - * </code> - * </div> - */ -p5.prototype.specularMaterial = function(v1, v2, v3, a) { - var gl = this._renderer.GL; - var shaderProgram = - this._renderer._getShader('lightVert', 'lightTextureFrag'); - gl.uniform1i(gl.getUniformLocation(shaderProgram, 'isTexture'), false); - gl.useProgram(shaderProgram); - shaderProgram.uMaterialColor = gl.getUniformLocation( - shaderProgram, 'uMaterialColor' ); - - var color = this._renderer._pInst.color.apply( - this._renderer._pInst, arguments); - var colors = color._array; - - gl.uniform4f(shaderProgram.uMaterialColor, - colors[0], colors[1], colors[2], colors[3]); - - shaderProgram.uSpecular = gl.getUniformLocation( - shaderProgram, 'uSpecular' ); - gl.uniform1i(shaderProgram.uSpecular, true); - - return this; -}; - -module.exports = p5; - -},{"../core/core":48}],34:[function(_dereq_,module,exports){ -//some of the functions are adjusted from Three.js(http://threejs.org) - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * p5 Geometry3D class - */ -p5.Geometry3D = function(){ - //an array holding every vertice - //each vertex is a p5.Vector - this.vertices = []; - //an array holding each normals for each vertice - //each normal is a p5.Vector - this.vertexNormals = []; - //an array holding each three indecies of vertices that form a face - //[[0, 1, 2], [1, 2, 3], ...] - this.faces = []; - //an array holding every noraml for each face - //each faceNormal is a p5.Vector - //[[p5.Vector, p5.Vector, p5.Vector],[p5.Vector, p5.Vector, p5.Vector],...] - this.faceNormals = []; - //an array of array holding uvs (group according to faces) - //[[[0, 0], [1, 0], [1, 0]],...] - this.uvs = []; -}; - -/** - * generate geometriy with parametric method - * @param {Function} func callback function for how to generate geometry - * @param {Number} detailX number of vertices on horizontal surface - * @param {Number} detailY number of vertices on horizontal surface - * @param {Number} offset offset of vertices index - */ -p5.Geometry3D.prototype.parametricGeometry = function -//@TODO: put func as the last parameters -(func, detailX, detailY, offset){ - - var i, j, p; - var u, v; - offset = offset || 0; - this.detailX = detailX; - this.detailY = detailY; - - var sliceCount = detailX + 1; - for (i = 0; i <= detailY; i++){ - v = i / detailY; - for (j = 0; j <= detailX; j++){ - u = j / detailX; - p = func(u, v); - this.vertices.push(p); - } - } - - var a, b, c, d; - var uva, uvb, uvc, uvd; - - for (i = 0; i < detailY; i++){ - for (j = 0; j < detailX; j++){ - a = i * sliceCount + j + offset; - b = i * sliceCount + j + 1 + offset; - c = (i + 1)* sliceCount + j + 1 + offset; - d = (i + 1)* sliceCount + j + offset; - - uva = [j/detailX, i/detailY]; - uvb = [(j + 1)/ detailX, i/detailY]; - uvc = [(j + 1)/ detailX, (i + 1)/detailY]; - uvd = [j/detailX, (i + 1)/detailY]; - - this.faces.push([a, b, d]); - this.uvs.push([uva, uvb, uvd]); - - this.faces.push([b, c, d]); - this.uvs.push([uvb, uvc, uvd]); - } - } -}; - -/** - * compute faceNormals for a geometry - */ -p5.Geometry3D.prototype.computeFaceNormals = function(){ - - var cb = new p5.Vector(); - var ab = new p5.Vector(); - - for (var f = 0; f < this.faces.length; f++){ - var face = this.faces[f]; - var vA = this.vertices[face[0]]; - var vB = this.vertices[face[1]]; - var vC = this.vertices[face[2]]; - - p5.Vector.sub(vC, vB, cb); - p5.Vector.sub(vA, vB, ab); - - var normal = p5.Vector.cross(ab, cb); - normal.normalize(); - normal.mult(-1); - this.faceNormals[f] = normal; - } - -}; - -/** - * compute vertexNormals for a geometry - */ -p5.Geometry3D.prototype.computeVertexNormals = function (){ - - var v, f, face, faceNormal, vertices; - var vertexNormals = []; - - vertices = new Array(this.vertices.length); - for (v = 0; v < this.vertices.length; v++) { - vertices[v] = new p5.Vector(); - } - - for (f = 0; f < this.faces.length; f++) { - face = this.faces[f]; - faceNormal = this.faceNormals[f]; - - vertices[face[0]].add(faceNormal); - vertices[face[1]].add(faceNormal); - vertices[face[2]].add(faceNormal); - } - - for (v = 0; v < this.vertices.length; v++) { - vertices[v].normalize(); - } - - for (f = 0; f < this.faces.length; f++) { - face = this.faces[f]; - vertexNormals[f] = []; - vertexNormals[f][0]= vertices[face[0]].copy(); - vertexNormals[f][1]= vertices[face[1]].copy(); - vertexNormals[f][2]= vertices[face[2]].copy(); - } - - for (f = 0; f < this.faces.length; f++){ - face = this.faces[f]; - faceNormal = this.faceNormals[f]; - this.vertexNormals[face[0]] = vertexNormals[f][0]; - this.vertexNormals[face[1]] = vertexNormals[f][1]; - this.vertexNormals[face[2]] = vertexNormals[f][2]; - } - -}; - -p5.Geometry3D.prototype.averageNormals = function() { - - for(var i = 0; i <= this.detailY; i++){ - var offset = this.detailX + 1; - var temp = p5.Vector - .add(this.vertexNormals[i*offset], - this.vertexNormals[i*offset + this.detailX]); - temp = p5.Vector.div(temp, 2); - this.vertexNormals[i*offset] = temp; - this.vertexNormals[i*offset + this.detailX] = temp; - } -}; - -p5.Geometry3D.prototype.averagePoleNormals = function() { - - //average the north pole - var sum = new p5.Vector(0, 0, 0); - for(var i = 0; i < this.detailX; i++){ - sum.add(this.vertexNormals[i]); - } - sum = p5.Vector.div(sum, this.detailX); - - for(i = 0; i < this.detailX; i++){ - this.vertexNormals[i] = sum; - } - - //average the south pole - sum = new p5.Vector(0, 0, 0); - for(i = this.vertices.length - 1; - i > this.vertices.length - 1 - this.detailX; i--){ - sum.add(this.vertexNormals[i]); - } - sum = p5.Vector.div(sum, this.detailX); - - for(i = this.vertices.length - 1; - i > this.vertices.length - 1 - this.detailX; i--){ - this.vertexNormals[i] = sum; - } -}; - -/** - * [generateUV description] - * @param {Array} faces [description] - * @param {Array} uvs [description] - */ -p5.Geometry3D.prototype.generateUV = function(faces, uvs){ - - faces = flatten(faces); - uvs = flatten(uvs); - var arr = []; - faces.forEach(function(item, index){ - arr[item] = uvs[index]; - }); - return flatten(arr); -}; - - -/** - * generate an object containing information needed to create buffer - */ -p5.Geometry3D.prototype.generateObj = function(average, sphere){ - - this.computeFaceNormals(); - this.computeVertexNormals(); - - if(average){ - this.averageNormals(); - } - - if(sphere){ - this.averagePoleNormals(); - } - - var obj = { - vertices: turnVectorArrayIntoNumberArray(this.vertices), - vertexNormals: turnVectorArrayIntoNumberArray(this.vertexNormals), - uvs: this.generateUV(this.faces, this.uvs), - faces: flatten(this.faces), - len: this.faces.length * 3 - }; - return obj; -}; - -/** - * turn a two dimensional array into one dimensional array - * @param {Array} arr 2-dimensional array - * @return {Array} 1-dimensional array - * [[1, 2, 3],[4, 5, 6]] -> [1, 2, 3, 4, 5, 6] - */ -function flatten(arr){ - return arr.reduce(function(a, b){ - return a.concat(b); - }); -} - -/** - * turn an array of Vector into a one dimensional array of numbers - * @param {Array} arr an array of p5.Vector - * @return {Array]} a one dimensional array of numbers - * [p5.Vector(1, 2, 3), p5.Vector(4, 5, 6)] -> - * [1, 2, 3, 4, 5, 6] - */ -function turnVectorArrayIntoNumberArray(arr){ - return flatten(arr.map(function(item){ - return [item.x, item.y, item.z]; - })); -} - -module.exports = p5.Geometry3D; -},{"../core/core":48}],35:[function(_dereq_,module,exports){ -/** -* @requires constants -* @todo see methods below needing further implementation. -* future consideration: implement SIMD optimizations -* when browser compatibility becomes available -* https://developer.mozilla.org/en-US/docs/Web/JavaScript/ -* Reference/Global_Objects/SIMD -*/ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var polarGeometry = _dereq_('../math/polargeometry'); -var constants = _dereq_('../core/constants'); -var GLMAT_ARRAY_TYPE = ( - typeof Float32Array !== 'undefined') ? - Float32Array : Array; - -/** - * A class to describe a 4x4 matrix - * for model and view matrix manipulation in the p5js webgl renderer. - * class p5.Matrix - * @constructor - * @param {Array} [mat4] array literal of our 4x4 matrix - */ -p5.Matrix = function() { - // This is how it comes in with createMatrix() - if(arguments[0] instanceof p5) { - // save reference to p5 if passed in - this.p5 = arguments[0]; - this.mat4 = arguments[1] || new GLMAT_ARRAY_TYPE([ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ]); - // This is what we'll get with new p5.Matrix() - // a mat4 identity matrix - } else { - this.mat4 = arguments[0] || new GLMAT_ARRAY_TYPE([ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ]); - } - return this; -}; - -/** - * Sets the x, y, and z component of the vector using two or three separate - * variables, the data from a p5.Matrix, or the values from a float array. - * - * @param {p5.Matrix|Array} [inMatrix] the input p5.Matrix or - * an Array of length 16 - */ -p5.Matrix.prototype.set = function (inMatrix) { - if (inMatrix instanceof p5.Matrix) { - this.mat4 = inMatrix.mat4; - return this; - } - else if (inMatrix instanceof GLMAT_ARRAY_TYPE) { - this.mat4 = inMatrix; - return this; - } - return this; -}; - -/** - * Gets a copy of the vector, returns a p5.Matrix object. - * - * @return {p5.Matrix} the copy of the p5.Matrix object - */ -p5.Matrix.prototype.get = function () { - return new p5.Matrix(this.mat4); -}; - -/** - * return a copy of a matrix - * @return {p5.Matrix} the result matrix - */ -p5.Matrix.prototype.copy = function(){ - var copied = new p5.Matrix(); - copied.mat4[0] = this.mat4[0]; - copied.mat4[1] = this.mat4[1]; - copied.mat4[2] = this.mat4[2]; - copied.mat4[3] = this.mat4[3]; - copied.mat4[4] = this.mat4[4]; - copied.mat4[5] = this.mat4[5]; - copied.mat4[6] = this.mat4[6]; - copied.mat4[7] = this.mat4[7]; - copied.mat4[8] = this.mat4[8]; - copied.mat4[9] = this.mat4[9]; - copied.mat4[10] = this.mat4[10]; - copied.mat4[11] = this.mat4[11]; - copied.mat4[12] = this.mat4[12]; - copied.mat4[13] = this.mat4[13]; - copied.mat4[14] = this.mat4[14]; - copied.mat4[15] = this.mat4[15]; - return copied; -}; - -/** - * return an identity matrix - * @return {p5.Matrix} the result matrix - */ -p5.Matrix.identity = function(){ - return new p5.Matrix(); -}; - -/** - * transpose according to a given matrix - * @param {p5.Matrix | Typed Array} a the matrix to be based on to transpose - * @return {p5.Matrix} this - */ -p5.Matrix.prototype.transpose = function(a){ - var a01, a02, a03, a12, a13, a23; - if(a instanceof p5.Matrix){ - a01 = a.mat4[1]; - a02 = a.mat4[2]; - a03 = a.mat4[3]; - a12 = a.mat4[6]; - a13 = a.mat4[7]; - a23 = a.mat4[11]; - - this.mat4[0] = a.mat4[0]; - this.mat4[1] = a.mat4[4]; - this.mat4[2] = a.mat4[8]; - this.mat4[3] = a.mat4[12]; - this.mat4[4] = a01; - this.mat4[5] = a.mat4[5]; - this.mat4[6] = a.mat4[9]; - this.mat4[7] = a.mat4[13]; - this.mat4[8] = a02; - this.mat4[9] = a12; - this.mat4[10] = a.mat4[10]; - this.mat4[11] = a.mat4[14]; - this.mat4[12] = a03; - this.mat4[13] = a13; - this.mat4[14] = a23; - this.mat4[15] = a.mat4[15]; - - }else if(a instanceof GLMAT_ARRAY_TYPE){ - a01 = a[1]; - a02 = a[2]; - a03 = a[3]; - a12 = a[6]; - a13 = a[7]; - a23 = a[11]; - - this.mat4[0] = a[0]; - this.mat4[1] = a[4]; - this.mat4[2] = a[8]; - this.mat4[3] = a[12]; - this.mat4[4] = a01; - this.mat4[5] = a[5]; - this.mat4[6] = a[9]; - this.mat4[7] = a[13]; - this.mat4[8] = a02; - this.mat4[9] = a12; - this.mat4[10] = a[10]; - this.mat4[11] = a[14]; - this.mat4[12] = a03; - this.mat4[13] = a13; - this.mat4[14] = a23; - this.mat4[15] = a[15]; - } - return this; -}; - -/** - * invert matrix according to a give matrix - * @param {p5.Matrix or Typed Array} a the matrix to be based on to invert - * @return {p5.Matrix} this - */ -p5.Matrix.prototype.invert = function(a){ - var a00, a01, a02, a03, a10, a11, a12, a13, - a20, a21, a22, a23, a30, a31, a32, a33; - if(a instanceof p5.Matrix){ - a00 = a.mat4[0]; - a01 = a.mat4[1]; - a02 = a.mat4[2]; - a03 = a.mat4[3]; - a10 = a.mat4[4]; - a11 = a.mat4[5]; - a12 = a.mat4[6]; - a13 = a.mat4[7]; - a20 = a.mat4[8]; - a21 = a.mat4[9]; - a22 = a.mat4[10]; - a23 = a.mat4[11]; - a30 = a.mat4[12]; - a31 = a.mat4[13]; - a32 = a.mat4[14]; - a33 = a.mat4[15]; - }else if(a instanceof GLMAT_ARRAY_TYPE){ - a00 = a[0]; - a01 = a[1]; - a02 = a[2]; - a03 = a[3]; - a10 = a[4]; - a11 = a[5]; - a12 = a[6]; - a13 = a[7]; - a20 = a[8]; - a21 = a[9]; - a22 = a[10]; - a23 = a[11]; - a30 = a[12]; - a31 = a[13]; - a32 = a[14]; - a33 = a[15]; - } - var b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - // Calculate the determinant - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - - b04 * b07 + b05 * b06; - - if (!det) { - return null; - } - det = 1.0 / det; - - this.mat4[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - this.mat4[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - this.mat4[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - this.mat4[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - this.mat4[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - this.mat4[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - this.mat4[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - this.mat4[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - this.mat4[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - this.mat4[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - this.mat4[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - this.mat4[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - this.mat4[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - this.mat4[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - this.mat4[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - this.mat4[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - - return this; -}; - -/** - * inspired by Toji's mat4 determinant - * @return {Number} Determinant of our 4x4 matrix - */ -p5.Matrix.prototype.determinant = function(){ - var d00 = (this.mat4[0] * this.mat4[5]) - (this.mat4[1] * this.mat4[4]), - d01 = (this.mat4[0] * this.mat4[6]) - (this.mat4[2] * this.mat4[4]), - d02 = (this.mat4[0] * this.mat4[7]) - (this.mat4[3] * this.mat4[4]), - d03 = (this.mat4[1] * this.mat4[6]) - (this.mat4[2] * this.mat4[5]), - d04 = (this.mat4[1] * this.mat4[7]) - (this.mat4[3] * this.mat4[5]), - d05 = (this.mat4[2] * this.mat4[7]) - (this.mat4[3] * this.mat4[6]), - d06 = (this.mat4[8] * this.mat4[13]) - (this.mat4[9] * this.mat4[12]), - d07 = (this.mat4[8] * this.mat4[14]) - (this.mat4[10] * this.mat4[12]), - d08 = (this.mat4[8] * this.mat4[15]) - (this.mat4[11] * this.mat4[12]), - d09 = (this.mat4[9] * this.mat4[14]) - (this.mat4[10] * this.mat4[13]), - d10 = (this.mat4[9] * this.mat4[15]) - (this.mat4[11] * this.mat4[13]), - d11 = (this.mat4[10] * this.mat4[15]) - (this.mat4[11] * this.mat4[14]); - - // Calculate the determinant - return d00 * d11 - d01 * d10 + d02 * d09 + - d03 * d08 - d04 * d07 + d05 * d06; -}; - -/** - * multiply two mat4s - * @param {p5.Matrix | Array} multMatrix The matrix we want to multiply by - * @return {p5.Matrix} this - */ -p5.Matrix.prototype.mult = function(multMatrix){ - var _dest = new GLMAT_ARRAY_TYPE(16); - var _src = new GLMAT_ARRAY_TYPE(16); - - if(multMatrix instanceof p5.Matrix) { - _src = multMatrix.mat4; - } - else if(multMatrix instanceof GLMAT_ARRAY_TYPE){ - _src = multMatrix; - } - - // each row is used for the multiplier - var b0 = this.mat4[0], b1 = this.mat4[1], - b2 = this.mat4[2], b3 = this.mat4[3]; - _dest[0] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; - _dest[1] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; - _dest[2] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; - _dest[3] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; - - b0 = this.mat4[4]; - b1 = this.mat4[5]; - b2 = this.mat4[6]; - b3 = this.mat4[7]; - _dest[4] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; - _dest[5] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; - _dest[6] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; - _dest[7] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; - - b0 = this.mat4[8]; - b1 = this.mat4[9]; - b2 = this.mat4[10]; - b3 = this.mat4[11]; - _dest[8] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; - _dest[9] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; - _dest[10] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; - _dest[11] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; - - b0 = this.mat4[12]; - b1 = this.mat4[13]; - b2 = this.mat4[14]; - b3 = this.mat4[15]; - _dest[12] = b0*_src[0] + b1*_src[4] + b2*_src[8] + b3*_src[12]; - _dest[13] = b0*_src[1] + b1*_src[5] + b2*_src[9] + b3*_src[13]; - _dest[14] = b0*_src[2] + b1*_src[6] + b2*_src[10] + b3*_src[14]; - _dest[15] = b0*_src[3] + b1*_src[7] + b2*_src[11] + b3*_src[15]; - - this.mat4 = _dest; - - return this; -}; - -/** - * scales a p5.Matrix by scalars or a vector - * @param {p5.Vector | Array } - * vector to scale by - * @return {p5.Matrix} this - */ -p5.Matrix.prototype.scale = function() { - var x,y,z; - var args = new Array(arguments.length); - for(var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - //if our 1st arg is a type p5.Vector - if (args[0] instanceof p5.Vector){ - x = args[0].x; - y = args[0].y; - z = args[0].z; - } - //otherwise if it's an array - else if (args[0] instanceof Array){ - x = args[0][0]; - y = args[0][1]; - z = args[0][2]; - } - var _dest = new GLMAT_ARRAY_TYPE(16); - _dest[0] = this.mat4[0] * x; - _dest[1] = this.mat4[1] * x; - _dest[2] = this.mat4[2] * x; - _dest[3] = this.mat4[3] * x; - _dest[4] = this.mat4[4] * y; - _dest[5] = this.mat4[5] * y; - _dest[6] = this.mat4[6] * y; - _dest[7] = this.mat4[7] * y; - _dest[8] = this.mat4[8] * z; - _dest[9] = this.mat4[9] * z; - _dest[10] = this.mat4[10] * z; - _dest[11] = this.mat4[11] * z; - _dest[12] = this.mat4[12]; - _dest[13] = this.mat4[13]; - _dest[14] = this.mat4[14]; - _dest[15] = this.mat4[15]; - - this.mat4 = _dest; - return this; -}; - -/** - * rotate our Matrix around an axis by the given angle. - * @param {Number} a The angle of rotation in radians - * @param {p5.Vector | Array} axis the axis(es) to rotate around - * @return {p5.Matrix} this - * inspired by Toji's gl-matrix lib, mat4 rotation - */ -p5.Matrix.prototype.rotate = function(a, axis){ - var x, y, z, _a, len; - - if (this.p5) { - if (this.p5._angleMode === constants.DEGREES) { - _a = polarGeometry.degreesToRadians(a); - } - } - else { - _a = a; - } - if (axis instanceof p5.Vector) { - x = axis.x; - y = axis.y; - z = axis.z; - } - else if (axis instanceof Array) { - x = axis[0]; - y = axis[1]; - z = axis[2]; - } - - len = Math.sqrt(x * x + y * y + z * z); - x *= (1/len); - y *= (1/len); - z *= (1/len); - - var a00 = this.mat4[0]; - var a01 = this.mat4[1]; - var a02 = this.mat4[2]; - var a03 = this.mat4[3]; - var a10 = this.mat4[4]; - var a11 = this.mat4[5]; - var a12 = this.mat4[6]; - var a13 = this.mat4[7]; - var a20 = this.mat4[8]; - var a21 = this.mat4[9]; - var a22 = this.mat4[10]; - var a23 = this.mat4[11]; - - //sin,cos, and tan of respective angle - var sA = Math.sin(_a); - var cA = Math.cos(_a); - var tA = 1 - cA; - // Construct the elements of the rotation matrix - var b00 = x * x * tA + cA; - var b01 = y * x * tA + z * sA; - var b02 = z * x * tA - y * sA; - var b10 = x * y * tA - z * sA; - var b11 = y * y * tA + cA; - var b12 = z * y * tA + x * sA; - var b20 = x * z * tA + y * sA; - var b21 = y * z * tA - x * sA; - var b22 = z * z * tA + cA; - - // rotation-specific matrix multiplication - this.mat4[0] = a00 * b00 + a10 * b01 + a20 * b02; - this.mat4[1] = a01 * b00 + a11 * b01 + a21 * b02; - this.mat4[2] = a02 * b00 + a12 * b01 + a22 * b02; - this.mat4[3] = a03 * b00 + a13 * b01 + a23 * b02; - this.mat4[4] = a00 * b10 + a10 * b11 + a20 * b12; - this.mat4[5] = a01 * b10 + a11 * b11 + a21 * b12; - this.mat4[6] = a02 * b10 + a12 * b11 + a22 * b12; - this.mat4[7] = a03 * b10 + a13 * b11 + a23 * b12; - this.mat4[8] = a00 * b20 + a10 * b21 + a20 * b22; - this.mat4[9] = a01 * b20 + a11 * b21 + a21 * b22; - this.mat4[10] = a02 * b20 + a12 * b21 + a22 * b22; - this.mat4[11] = a03 * b20 + a13 * b21 + a23 * b22; - - return this; -}; - -/** - * @todo finish implementing this method! - * translates - * @param {Array} v vector to translate by - * @return {p5.Matrix} this - */ -p5.Matrix.prototype.translate = function(v){ - var x = v[0], - y = v[1], - z = v[2] || 0; - this.mat4[12] = - this.mat4[0] * x +this.mat4[4] * y +this.mat4[8] * z +this.mat4[12]; - this.mat4[13] = - this.mat4[1] * x +this.mat4[5] * y +this.mat4[9] * z +this.mat4[13]; - this.mat4[14] = - this.mat4[2] * x +this.mat4[6] * y +this.mat4[10] * z +this.mat4[14]; - this.mat4[15] = - this.mat4[3] * x +this.mat4[7] * y +this.mat4[11] * z +this.mat4[15]; -}; - -p5.Matrix.prototype.rotateX = function(a){ - this.rotate(a, [1,0,0]); -}; -p5.Matrix.prototype.rotateY = function(a){ - this.rotate(a, [0,1,0]); -}; -p5.Matrix.prototype.rotateZ = function(a){ - this.rotate(a, [0,0,1]); -}; - -/** - * sets the perspective matrix - * @param {Number} fovy [description] - * @param {Number} aspect [description] - * @param {Number} near near clipping plane - * @param {Number} far far clipping plane - * @return {void} - */ -p5.Matrix.prototype.perspective = function(fovy,aspect,near,far){ - - var f = 1.0 / Math.tan(fovy / 2), - nf = 1 / (near - far); - - this.mat4[0] = f / aspect; - this.mat4[1] = 0; - this.mat4[2] = 0; - this.mat4[3] = 0; - this.mat4[4] = 0; - this.mat4[5] = f; - this.mat4[6] = 0; - this.mat4[7] = 0; - this.mat4[8] = 0; - this.mat4[9] = 0; - this.mat4[10] = (far + near) * nf; - this.mat4[11] = -1; - this.mat4[12] = 0; - this.mat4[13] = 0; - this.mat4[14] = (2 * far * near) * nf; - this.mat4[15] = 0; - - return this; - -}; - -/** - * sets the ortho matrix - * @param {Number} left [description] - * @param {Number} right [description] - * @param {Number} bottom [description] - * @param {Number} top [description] - * @param {Number} near near clipping plane - * @param {Number} far far clipping plane - * @return {void} - */ -p5.Matrix.prototype.ortho = function(left,right,bottom,top,near,far){ - - var lr = 1 / (left - right), - bt = 1 / (bottom - top), - nf = 1 / (near - far); - this.mat4[0] = -2 * lr; - this.mat4[1] = 0; - this.mat4[2] = 0; - this.mat4[3] = 0; - this.mat4[4] = 0; - this.mat4[5] = -2 * bt; - this.mat4[6] = 0; - this.mat4[7] = 0; - this.mat4[8] = 0; - this.mat4[9] = 0; - this.mat4[10] = 2 * nf; - this.mat4[11] = 0; - this.mat4[12] = (left + right) * lr; - this.mat4[13] = (top + bottom) * bt; - this.mat4[14] = (far + near) * nf; - this.mat4[15] = 1; - - return this; -}; - -/** - * PRIVATE - */ -// matrix methods adapted from: -// https://developer.mozilla.org/en-US/docs/Web/WebGL/ -// gluPerspective -// -// function _makePerspective(fovy, aspect, znear, zfar){ -// var ymax = znear * Math.tan(fovy * Math.PI / 360.0); -// var ymin = -ymax; -// var xmin = ymin * aspect; -// var xmax = ymax * aspect; -// return _makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); -// } - -//// -//// glFrustum -//// -//function _makeFrustum(left, right, bottom, top, znear, zfar){ -// var X = 2*znear/(right-left); -// var Y = 2*znear/(top-bottom); -// var A = (right+left)/(right-left); -// var B = (top+bottom)/(top-bottom); -// var C = -(zfar+znear)/(zfar-znear); -// var D = -2*zfar*znear/(zfar-znear); -// var frustrumMatrix =[ -// X, 0, A, 0, -// 0, Y, B, 0, -// 0, 0, C, D, -// 0, 0, -1, 0 -//]; -//return frustrumMatrix; -// } - -// function _setMVPMatrices(){ -////an identity matrix -////@TODO use the p5.Matrix class to abstract away our MV matrices and -///other math -//var _mvMatrix = -//[ -// 1.0,0.0,0.0,0.0, -// 0.0,1.0,0.0,0.0, -// 0.0,0.0,1.0,0.0, -// 0.0,0.0,0.0,1.0 -//]; - -module.exports = p5.Matrix; -},{"../core/constants":47,"../core/core":48,"../math/polargeometry":77}],36:[function(_dereq_,module,exports){ -'use strict'; - -var p5 = _dereq_('../core/core'); -var shader = _dereq_('./shader'); -_dereq_('../core/p5.Renderer'); -_dereq_('./p5.Matrix'); -var uMVMatrixStack = []; -var RESOLUTION = 1000; - -//@TODO should probably implement an override for these attributes -var attributes = { - alpha: true, - depth: true, - stencil: true, - antialias: false, - premultipliedAlpha: false, - preserveDrawingBuffer: false -}; - -/** - * 3D graphics class. Can also be used as an off-screen graphics buffer. - * A p5.Renderer3D object can be constructed - * - */ -p5.Renderer3D = function(elt, pInst, isMainCanvas) { - p5.Renderer.call(this, elt, pInst, isMainCanvas); - - try { - this.drawingContext = this.canvas.getContext('webgl', attributes) || - this.canvas.getContext('experimental-webgl', attributes); - if (this.drawingContext === null) { - throw new Error('Error creating webgl context'); - } else { - console.log('p5.Renderer3D: enabled webgl context'); - } - } catch (er) { - throw new Error(er); - } - - this.isP3D = true; //lets us know we're in 3d mode - this.GL = this.drawingContext; - var gl = this.GL; - gl.clearColor(1.0, 1.0, 1.0, 1.0); //background is initialized white - gl.clearDepth(1); - gl.enable(gl.DEPTH_TEST); - gl.depthFunc(gl.LEQUAL); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - this._init(); - return this; -}; - -p5.Renderer3D.prototype = Object.create(p5.Renderer.prototype); - -p5.Renderer3D.prototype._applyDefaults = function() { - return this; -}; - -////////////////////////////////////////////// -// Setting -////////////////////////////////////////////// - -p5.Renderer3D.prototype._init = function(first_argument) { - var gl = this.GL; - //for our default matrices - this.initMatrix(); - this.initHash(); - //for immedidate mode - this.verticeStack = []; - this.verticeBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); - //for camera - this._setCamera = false; - //for counting lights - this.ambientLightCount = 0; - this.directionalLightCount = 0; - this.pointLightCount = 0; -}; - -p5.Renderer3D.prototype._update = function() { - this.resetMatrix(); - this.translate(0, 0, -800); - this.ambientLightCount = 0; - this.directionalLightCount = 0; - this.pointLightCount = 0; - this.verticeStack = []; -}; - -/** - * [resize description] - * @param {[type]} w [description] - * @param {[tyoe]} h [description] - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.resize = function(w,h) { - var gl = this.GL; - p5.Renderer.prototype.resize.call(this, w, h); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); -}; - -/** - * [background description] - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.background = function() { - var gl = this.GL; - var _col = this._pInst.color.apply(this._pInst, arguments); - // gl.clearColor(0.0,0.0,0.0,1.0); - var _r = (_col.levels[0]) / 255; - var _g = (_col.levels[1]) / 255; - var _b = (_col.levels[2]) / 255; - var _a = (_col.levels[3]) / 255; - gl.clearColor(_r, _g, _b, _a); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); -}; - -//@TODO implement this -// p5.Renderer3D.prototype.clear = function() { -//@TODO -// }; - -////////////////////////////////////////////// -// SHADER -////////////////////////////////////////////// - -/** - * [initShaders description] - * @param {[type]} vertId [description] - * @param {[type]} fragId [description] - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.initShaders = function(vertId, fragId, immediateMode) { - var gl = this.GL; - //set up our default shaders by: - // 1. create the shader, - // 2. load the shader source, - // 3. compile the shader - var _vertShader = gl.createShader(gl.VERTEX_SHADER); - //load in our default vertex shader - gl.shaderSource(_vertShader, shader[vertId]); - gl.compileShader(_vertShader); - // if our vertex shader failed compilation? - if (!gl.getShaderParameter(_vertShader, gl.COMPILE_STATUS)) { - alert('Yikes! An error occurred compiling the shaders:' + - gl.getShaderInfoLog(_vertShader)); - return null; - } - - var _fragShader = gl.createShader(gl.FRAGMENT_SHADER); - //load in our material frag shader - gl.shaderSource(_fragShader, shader[fragId]); - gl.compileShader(_fragShader); - // if our frag shader failed compilation? - if (!gl.getShaderParameter(_fragShader, gl.COMPILE_STATUS)) { - alert('Darn! An error occurred compiling the shaders:' + - gl.getShaderInfoLog(_fragShader)); - return null; - } - - var shaderProgram = gl.createProgram(); - gl.attachShader(shaderProgram, _vertShader); - gl.attachShader(shaderProgram, _fragShader); - gl.linkProgram(shaderProgram); - if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { - alert('Snap! Error linking shader program'); - } - //END SHADERS SETUP - - this._getLocation(shaderProgram, immediateMode); - - return shaderProgram; -}; - -p5.Renderer3D.prototype._getLocation = function(shaderProgram, immediateMode) { - var gl = this.GL; - gl.useProgram(shaderProgram); - shaderProgram.uResolution = - gl.getUniformLocation(shaderProgram, 'uResolution'); - gl.uniform1f(shaderProgram.uResolution, RESOLUTION); - - //vertex position Attribute - shaderProgram.vertexPositionAttribute = - gl.getAttribLocation(shaderProgram, 'aPosition'); - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - - //projection Matrix uniform - shaderProgram.uPMatrixUniform = - gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'); - //model view Matrix uniform - shaderProgram.uMVMatrixUniform = - gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'); - - //@TODO: figure out a better way instead of if statement - if(immediateMode === undefined){ - //vertex normal Attribute - shaderProgram.vertexNormalAttribute = - gl.getAttribLocation(shaderProgram, 'aNormal'); - gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute); - - //normal Matrix uniform - shaderProgram.uNMatrixUniform = - gl.getUniformLocation(shaderProgram, 'uNormalMatrix'); - - //texture coordinate Attribute - shaderProgram.textureCoordAttribute = - gl.getAttribLocation(shaderProgram, 'aTexCoord'); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - - shaderProgram.samplerUniform = - gl.getUniformLocation(shaderProgram, 'uSampler'); - } -}; - -p5.Renderer3D.prototype.setMatrixUniforms = function(shaderKey) { - var gl = this.GL; - var shaderProgram = this.mHash[shaderKey]; - - gl.useProgram(shaderProgram); - - gl.uniformMatrix4fv( - shaderProgram.uPMatrixUniform, - false, this.uPMatrix.mat4); - - gl.uniformMatrix4fv( - shaderProgram.uMVMatrixUniform, - false, this.uMVMatrix.mat4); - - this.uNMatrix = new p5.Matrix(); - this.uNMatrix.invert(this.uMVMatrix); - this.uNMatrix.transpose(this.uNMatrix); - - gl.uniformMatrix4fv( - shaderProgram.uNMatrixUniform, - false, this.uNMatrix.mat4); -}; -////////////////////////////////////////////// -// GET CURRENT | for shader and color -////////////////////////////////////////////// -p5.Renderer3D.prototype._getShader = function(vertId, fragId, immediateMode) { - var mId = vertId+ '|' + fragId; - //create it and put it into hashTable - if(!this.materialInHash(mId)){ - var shaderProgram = this.initShaders(vertId, fragId, immediateMode); - this.mHash[mId] = shaderProgram; - } - this.curShaderId = mId; - - return this.mHash[this.curShaderId]; -}; - -p5.Renderer3D.prototype._getCurShaderId = function(){ - //if it's not defined yet - if(this.curShaderId === undefined){ - //default shader: normalMaterial() - var mId = 'normalVert|normalFrag'; - var shaderProgram = this.initShaders('normalVert', 'normalFrag'); - this.mHash[mId] = shaderProgram; - this.curShaderId = mId; - } - - return this.curShaderId; -}; - -p5.Renderer3D.prototype._getCurColor = function() { - //default color: gray - if(this.curColor === undefined) { - this.curColor = [0.5, 0.5, 0.5, 1.0]; - } - return this.curColor; -}; - -////////////////////////////////////////////// -// HASH | for material and geometry -////////////////////////////////////////////// - -p5.Renderer3D.prototype.initHash = function(){ - this.gHash = {}; - this.mHash = {}; -}; - -p5.Renderer3D.prototype.geometryInHash = function(gId){ - return this.gHash[gId] !== undefined; -}; - -p5.Renderer3D.prototype.materialInHash = function(mId){ - return this.mHash[mId] !== undefined; -}; - -////////////////////////////////////////////// -// MATRIX -////////////////////////////////////////////// - -p5.Renderer3D.prototype.initMatrix = function(){ - this.uMVMatrix = new p5.Matrix(); - this.uPMatrix = new p5.Matrix(); - this.uNMatrix = new p5.Matrix(); -}; - -p5.Renderer3D.prototype.resetMatrix = function() { - this.uMVMatrix = p5.Matrix.identity(); - //this.uPMatrix = p5.Matrix.identity(); -}; - -//detect if user didn't set the camera -//then call this function below -p5.Renderer3D.prototype._setDefaultCamera = function(){ - if(!this._setCamera){ - var _w = this.width; - var _h = this.height; - this.uPMatrix = p5.Matrix.identity(); - this.uPMatrix.perspective(60 / 180 * Math.PI, _w / _h, 0.1, 100); - this._setCamera = true; - } -}; - -/** - * [translate description] - * @param {[type]} x [description] - * @param {[type]} y [description] - * @param {[type]} z [description] - * @return {[type]} [description] - * @todo implement handle for components or vector as args - */ -p5.Renderer3D.prototype.translate = function(x, y, z) { - //@TODO: figure out how to fit the resolution - x = x / RESOLUTION; - y = -y / RESOLUTION; - z = z / RESOLUTION; - this.uMVMatrix.translate([x,y,z]); - return this; -}; - -/** - * Scales the Model View Matrix by a vector - * @param {Number | p5.Vector | Array} x [description] - * @param {Number} [y] y-axis scalar - * @param {Number} [z] z-axis scalar - * @return {this} [description] - */ -p5.Renderer3D.prototype.scale = function(x,y,z) { - this.uMVMatrix.scale([x,y,z]); - return this; -}; - -/** - * [rotate description] - * @param {Number} rad angle in radians - * @param {p5.Vector | Array} axis axis to rotate around - * @return {p5.Renderer3D} [description] - */ -p5.Renderer3D.prototype.rotate = function(rad, axis){ - this.uMVMatrix.rotate(rad, axis); - return this; -}; - -/** - * [rotateX description] - * @param {Number} rad radians to rotate - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.rotateX = function(rad) { - this.uMVMatrix.rotateX(rad); - return this; -}; - -/** - * [rotateY description] - * @param {Number} rad rad radians to rotate - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.rotateY = function(rad) { - this.uMVMatrix.rotateY(rad); - return this; -}; - -/** - * [rotateZ description] - * @param {Number} rad rad radians to rotate - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.rotateZ = function(rad) { - this.uMVMatrix.rotateZ(rad); - return this; -}; - -/** - * pushes a copy of the model view matrix onto the - * MV Matrix stack. - * NOTE to self: could probably make this more readable - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.push = function() { - uMVMatrixStack.push(this.uMVMatrix.copy()); -}; - -/** - * [pop description] - * @return {[type]} [description] - */ -p5.Renderer3D.prototype.pop = function() { - if (uMVMatrixStack.length === 0) { - throw new Error('Invalid popMatrix!'); - } - this.uMVMatrix = uMVMatrixStack.pop(); -}; - -module.exports = p5.Renderer3D; - -},{"../core/core":48,"../core/p5.Renderer":54,"./p5.Matrix":35,"./shader":38}],37:[function(_dereq_,module,exports){ -//retained mode is used by rendering 3d_primitives - -'use strict'; - -var p5 = _dereq_('../core/core'); -var hashCount = 0; - -/** - * createBuffer - * @param {String} gId key of the geometry object - * @param {Array} arr array holding bject containing geometry information - */ -p5.Renderer3D.prototype.createBuffer = function(gId, arr) { - - hashCount ++; - if(hashCount > 1000){ - var key = Object.keys(this.gHash)[0]; - delete this.gHash[key]; - hashCount --; - } - - var gl = this.GL; - this.gHash[gId] = {}; - this.gHash[gId].len = []; - this.gHash[gId].vertexBuffer = []; - this.gHash[gId].normalBuffer = []; - this.gHash[gId].uvBuffer = []; - this.gHash[gId].indexBuffer =[]; - - arr.forEach(function(obj){ - this.gHash[gId].len.push(obj.len); - this.gHash[gId].vertexBuffer.push(gl.createBuffer()); - this.gHash[gId].normalBuffer.push(gl.createBuffer()); - this.gHash[gId].uvBuffer.push(gl.createBuffer()); - this.gHash[gId].indexBuffer.push(gl.createBuffer()); - }.bind(this)); -}; - -/** - * initBuffer description - * @param {String} gId key of the geometry object - * @param {Array} arr array holding bject containing geometry information - */ -p5.Renderer3D.prototype.initBuffer = function(gId, arr) { - this._setDefaultCamera(); - var gl = this.GL; - this.createBuffer(gId, arr); - - var shaderProgram = this.mHash[this._getCurShaderId()]; - - arr.forEach(function(obj, i){ - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].vertexBuffer[i]); - gl.bufferData( - gl.ARRAY_BUFFER, new Float32Array(obj.vertices), gl.STATIC_DRAW); - gl.vertexAttribPointer( - shaderProgram.vertexPositionAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].normalBuffer[i]); - gl.bufferData( - gl.ARRAY_BUFFER, new Float32Array(obj.vertexNormals), gl.STATIC_DRAW); - gl.vertexAttribPointer( - shaderProgram.vertexNormalAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].uvBuffer[i]); - gl.bufferData( - gl.ARRAY_BUFFER, new Float32Array(obj.uvs), gl.STATIC_DRAW); - gl.vertexAttribPointer( - shaderProgram.textureCoordAttribute, - 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gHash[gId].indexBuffer[i]); - gl.bufferData - (gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(obj.faces), gl.STATIC_DRAW); - }.bind(this)); -}; - -/** - * drawBuffer - * @param {String} gId key of the geometery object - */ -p5.Renderer3D.prototype.drawBuffer = function(gId) { - this._setDefaultCamera(); - var gl = this.GL; - var shaderKey = this._getCurShaderId(); - var shaderProgram = this.mHash[shaderKey]; - - this.gHash[gId].len.forEach(function(d, i){ - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].vertexBuffer[i]); - gl.vertexAttribPointer( - shaderProgram.vertexPositionAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].normalBuffer[i]); - gl.vertexAttribPointer( - shaderProgram.vertexNormalAttribute, - 3, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.gHash[gId].uvBuffer[i]); - gl.vertexAttribPointer( - shaderProgram.textureCoordAttribute, - 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gHash[gId].indexBuffer[i]); - - this.setMatrixUniforms(shaderKey); - - gl.drawElements( - gl.TRIANGLES, this.gHash[gId].len[i], - gl.UNSIGNED_SHORT, 0); - }.bind(this)); -}; - -module.exports = p5.Renderer3D; -},{"../core/core":48}],38:[function(_dereq_,module,exports){ - - -module.exports = { - vertexColorVert: - "attribute vec3 aPosition;\nattribute vec4 aVertexColor;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform float uResolution;\n\nvarying vec4 vColor;\n\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition / uResolution * vec3(1.0, -1.0, 1.0), 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vColor = aVertexColor;\n}", - vertexColorFrag: - "precision mediump float;\nvarying vec4 vColor;\nvoid main(void) {\n gl_FragColor = vColor;\n}", - normalVert: - "attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat4 uNormalMatrix;\nuniform float uResolution;\n\nvarying vec3 vVertexNormal;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition / uResolution, 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vVertexNormal = vec3( uNormalMatrix * vec4( aNormal, 1.0 ) );\n vVertTexCoord = aTexCoord;\n}", - normalFrag: - "precision mediump float;\nvarying vec3 vVertexNormal;\nvoid main(void) {\n gl_FragColor = vec4(vVertexNormal, 1.0);\n}", - basicFrag: - "precision mediump float;\nvarying vec3 vVertexNormal;\nuniform vec4 uMaterialColor;\nvoid main(void) {\n gl_FragColor = uMaterialColor;\n}", - lightVert: - "attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat4 uNormalMatrix;\nuniform float uResolution;\nuniform int uAmbientLightCount;\nuniform int uDirectionalLightCount;\nuniform int uPointLightCount;\n\nuniform vec3 uAmbientColor[8];\nuniform vec3 uLightingDirection[8];\nuniform vec3 uDirectionalColor[8];\nuniform vec3 uPointLightLocation[8];\nuniform vec3 uPointLightColor[8];\nuniform bool uSpecular;\n\nvarying vec3 vVertexNormal;\nvarying vec2 vVertTexCoord;\nvarying vec3 vLightWeighting;\n\nvec3 ambientLightFactor = vec3(0.0, 0.0, 0.0);\nvec3 directionalLightFactor = vec3(0.0, 0.0, 0.0);\nvec3 pointLightFactor = vec3(0.0, 0.0, 0.0);\nvec3 pointLightFactor2 = vec3(0.0, 0.0, 0.0);\n\nvoid main(void){\n\n vec4 positionVec4 = vec4(aPosition / uResolution, 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n\n vec3 vertexNormal = vec3( uNormalMatrix * vec4( aNormal, 1.0 ) );\n vVertexNormal = vertexNormal;\n vVertTexCoord = aTexCoord;\n\n vec4 mvPosition = uModelViewMatrix * vec4(aPosition / uResolution, 1.0);\n vec3 eyeDirection = normalize(-mvPosition.xyz);\n\n float shininess = 32.0;\n float specularFactor = 2.0;\n float diffuseFactor = 0.3;\n\n for(int i = 0; i < 8; i++){\n if(uAmbientLightCount == i) break;\n ambientLightFactor += uAmbientColor[i];\n }\n\n for(int j = 0; j < 8; j++){\n if(uDirectionalLightCount == j) break;\n vec3 dir = uLightingDirection[j];\n float directionalLightWeighting = max(dot(vertexNormal, dir), 0.0);\n directionalLightFactor += uDirectionalColor[j] * directionalLightWeighting;\n }\n\n for(int k = 0; k < 8; k++){\n if(uPointLightCount == k) break;\n vec3 loc = uPointLightLocation[k];\n //loc = loc / uResolution;\n vec3 lightDirection = normalize(loc - mvPosition.xyz);\n\n float directionalLightWeighting = max(dot(vertexNormal, lightDirection), 0.0);\n pointLightFactor += uPointLightColor[k] * directionalLightWeighting;\n\n //factor2 for specular\n vec3 reflectionDirection = reflect(-lightDirection, vertexNormal);\n float specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), shininess);\n\n pointLightFactor2 += uPointLightColor[k] * (specularFactor * specularLightWeighting\n + directionalLightWeighting * diffuseFactor);\n }\n \n if(!uSpecular){\n vLightWeighting = ambientLightFactor + directionalLightFactor + pointLightFactor;\n }else{\n vLightWeighting = ambientLightFactor + directionalLightFactor + pointLightFactor2;\n }\n\n}", - lightTextureFrag: - "precision mediump float;\n\nuniform vec4 uMaterialColor;\nuniform sampler2D uSampler;\nuniform bool isTexture;\n\nvarying vec3 vLightWeighting;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n if(!isTexture){\n gl_FragColor = vec4(vec3(uMaterialColor.rgb * vLightWeighting), uMaterialColor.a);\n }else{\n vec4 textureColor = texture2D(uSampler, vVertTexCoord);\n if(vLightWeighting == vec3(0., 0., 0.)){\n gl_FragColor = textureColor;\n }else{\n gl_FragColor = vec4(vec3(textureColor.rgb * vLightWeighting), textureColor.a); \n }\n }\n}" -}; -},{}],39:[function(_dereq_,module,exports){ - -'use strict'; - -var p5 = _dereq_('./core/core'); -_dereq_('./color/p5.Color'); -_dereq_('./core/p5.Element'); -_dereq_('./typography/p5.Font'); -_dereq_('./core/p5.Graphics'); -_dereq_('./core/p5.Renderer2D'); - -_dereq_('./image/p5.Image'); -_dereq_('./math/p5.Vector'); -_dereq_('./io/p5.TableRow'); -_dereq_('./io/p5.Table'); - -_dereq_('./color/creating_reading'); -_dereq_('./color/setting'); -_dereq_('./core/constants'); -_dereq_('./utilities/conversion'); -_dereq_('./utilities/array_functions'); -_dereq_('./utilities/string_functions'); -_dereq_('./core/environment'); -_dereq_('./image/image'); -_dereq_('./image/loading_displaying'); -_dereq_('./image/pixels'); -_dereq_('./io/files'); -_dereq_('./events/keyboard'); -_dereq_('./events/acceleration'); //john -_dereq_('./events/mouse'); -_dereq_('./utilities/time_date'); -_dereq_('./events/touch'); -_dereq_('./math/math'); -_dereq_('./math/calculation'); -_dereq_('./math/random'); -_dereq_('./math/noise'); -_dereq_('./math/trigonometry'); -_dereq_('./core/rendering'); -_dereq_('./core/2d_primitives'); - -_dereq_('./core/attributes'); -_dereq_('./core/curves'); -_dereq_('./core/vertex'); -_dereq_('./core/structure'); -_dereq_('./core/transform'); -_dereq_('./typography/attributes'); -_dereq_('./typography/loading_displaying'); - -_dereq_('./3d/p5.Renderer3D'); -_dereq_('./3d/p5.Geometry3D'); -_dereq_('./3d/retainedMode3D'); -_dereq_('./3d/immediateMode3D'); -_dereq_('./3d/3d_primitives'); -_dereq_('./3d/p5.Matrix'); -_dereq_('./3d/material'); -_dereq_('./3d/light'); -_dereq_('./3d/shader'); -_dereq_('./3d/camera'); -_dereq_('./3d/interaction'); - -/** - * _globalInit - * - * TODO: ??? - * if sketch is on window - * assume "global" mode - * and instantiate p5 automatically - * otherwise do nothing - * - * @return {Undefined} - */ -var _globalInit = function() { - if (!window.PHANTOMJS && !window.mocha) { - // If there is a setup or draw function on the window - // then instantiate p5 in "global" mode - if((window.setup && typeof window.setup === 'function') || - (window.draw && typeof window.draw === 'function')) { - new p5(); - } - } -}; - -// TODO: ??? -if (document.readyState === 'complete') { - _globalInit(); -} else { - window.addEventListener('load', _globalInit , false); -} - -module.exports = p5; -},{"./3d/3d_primitives":28,"./3d/camera":29,"./3d/immediateMode3D":30,"./3d/interaction":31,"./3d/light":32,"./3d/material":33,"./3d/p5.Geometry3D":34,"./3d/p5.Matrix":35,"./3d/p5.Renderer3D":36,"./3d/retainedMode3D":37,"./3d/shader":38,"./color/creating_reading":41,"./color/p5.Color":42,"./color/setting":43,"./core/2d_primitives":44,"./core/attributes":45,"./core/constants":47,"./core/core":48,"./core/curves":49,"./core/environment":50,"./core/p5.Element":52,"./core/p5.Graphics":53,"./core/p5.Renderer2D":55,"./core/rendering":56,"./core/structure":58,"./core/transform":59,"./core/vertex":60,"./events/acceleration":61,"./events/keyboard":62,"./events/mouse":63,"./events/touch":64,"./image/image":66,"./image/loading_displaying":67,"./image/p5.Image":68,"./image/pixels":69,"./io/files":70,"./io/p5.Table":71,"./io/p5.TableRow":72,"./math/calculation":73,"./math/math":74,"./math/noise":75,"./math/p5.Vector":76,"./math/random":78,"./math/trigonometry":79,"./typography/attributes":80,"./typography/loading_displaying":81,"./typography/p5.Font":82,"./utilities/array_functions":83,"./utilities/conversion":84,"./utilities/string_functions":85,"./utilities/time_date":86}],40:[function(_dereq_,module,exports){ -/** - * module Conversion - * submodule Color Conversion - * @for p5 - * @requires core - */ - -'use strict'; - -/** - * Conversions adapted from <http://www.easyrgb.com/math.html>. - * - * In these functions, hue is always in the range [0,1); all other components - * are in the range [0,1]. 'Brightness' and 'value' are used interchangeably. - */ - -var p5 = _dereq_('../core/core'); -p5.ColorConversion = {}; - -/** - * Convert an HSBA array to HSLA. - */ -p5.ColorConversion._hsbaToHSLA = function(hsba) { - var hue = hsba[0]; - var sat = hsba[1]; - var val = hsba[2]; - - // Calculate lightness. - var li = (2 - sat) * val / 2; - - // Convert saturation. - if (li !== 0) { - if (li === 1) { - sat = 0; - } else if (li < 0.5) { - sat = sat / (2 - sat); - } else { - sat = sat * val / (2 - li * 2); - } - } - - // Hue and alpha stay the same. - return [hue, sat, li, hsba[3]]; -}; - -/** - * Convert an HSBA array to RGBA. - */ -p5.ColorConversion._hsbaToRGBA = function(hsba) { - var hue = hsba[0] * 6; // We will split hue into 6 sectors. - var sat = hsba[1]; - var val = hsba[2]; - - var RGBA = []; - - if (sat === 0) { - RGBA = [val, val, val, hsba[3]]; // Return early if grayscale. - } else { - var sector = Math.floor(hue); - var tint1 = val * (1 - sat); - var tint2 = val * (1 - sat * (hue - sector)); - var tint3 = val * (1 - sat * (1 + sector - hue)); - var red, green, blue; - if (sector === 0) { // Red to yellow. - red = val; - green = tint3; - blue = tint1; - } else if (sector === 1) { // Yellow to green. - red = tint2; - green = val; - blue = tint1; - } else if (sector === 2) { // Green to cyan. - red = tint1; - green = val; - blue = tint3; - } else if (sector === 3) { // Cyan to blue. - red = tint1; - green = tint2; - blue = val; - } else if (sector === 4) { // Blue to magenta. - red = tint3; - green = tint1; - blue = val; - } else { // Magenta to red. - red = val; - green = tint1; - blue = tint2; - } - RGBA = [red, green, blue, hsba[3]]; - } - - return RGBA; -}; - -/** - * Convert an HSLA array to HSBA. - */ -p5.ColorConversion._hslaToHSBA = function(hsla) { - var hue = hsla[0]; - var sat = hsla[1]; - var li = hsla[2]; - - // Calculate brightness. - var val; - if (li < 0.5) { - val = (1 + sat) * li; - } else { - val = li + sat - li * sat; - } - - // Convert saturation. - sat = 2 * (val - li) / val; - - // Hue and alpha stay the same. - return [hue, sat, val, hsla[3]]; -}; - -/** - * Convert an HSLA array to RGBA. - * - * We need to change basis from HSLA to something that can be more easily be - * projected onto RGBA. We will choose hue and brightness as our first two - * components, and pick a convenient third one ('zest') so that we don't need - * to calculate formal HSBA saturation. - */ -p5.ColorConversion._hslaToRGBA = function(hsla){ - var hue = hsla[0] * 6; // We will split hue into 6 sectors. - var sat = hsla[1]; - var li = hsla[2]; - - var RGBA = []; - - if (sat === 0) { - RGBA = [li, li, li, hsla[3]]; // Return early if grayscale. - } else { - - // Calculate brightness. - var val; - if (li < 0.5) { - val = (1 + sat) * li; - } else { - val = li + sat - li * sat; - } - - // Define zest. - var zest = 2 * li - val; - - // Implement projection (project onto green by default). - var hzvToRGB = function(hue, zest, val) { - if (hue < 0) { // Hue must wrap to allow projection onto red and blue. - hue += 6; - } else if (hue >= 6) { - hue -= 6; - } - if (hue < 1) { // Red to yellow (increasing green). - return (zest + (val - zest) * hue); - } else if (hue < 3) { // Yellow to cyan (greatest green). - return val; - } else if (hue < 4) { // Cyan to blue (decreasing green). - return (zest + (val - zest) * (4 - hue)); - } else { // Blue to red (least green). - return zest; - } - }; - - // Perform projections, offsetting hue as necessary. - RGBA = [hzvToRGB(hue + 2, zest, val), - hzvToRGB(hue , zest, val), - hzvToRGB(hue - 2, zest, val), - hsla[3]]; - } - - return RGBA; -}; - -/** - * Convert an RGBA array to HSBA. - */ -p5.ColorConversion._rgbaToHSBA = function(rgba) { - var red = rgba[0]; - var green = rgba[1]; - var blue = rgba[2]; - - var val = Math.max(red, green, blue); - var chroma = val - Math.min(red, green, blue); - - var hue, sat; - if (chroma === 0) { // Return early if grayscale. - hue = 0; - sat = 0; - } - else { - sat = chroma / val; - if (red === val) { // Magenta to yellow. - hue = (green - blue) / chroma; - } else if (green === val) { // Yellow to cyan. - hue = 2 + (blue - red) / chroma; - } else if (blue === val) { // Cyan to magenta. - hue = 4 + (red - green) / chroma; - } - if (hue < 0) { // Confine hue to the interval [0, 1). - hue += 6; - } else if (hue >= 6) { - hue -= 6; - } - } - - return [hue / 6, sat, val, rgba[3]]; -}; - -/** - * Convert an RGBA array to HSLA. - */ -p5.ColorConversion._rgbaToHSLA = function(rgba) { - var red = rgba[0]; - var green = rgba[1]; - var blue = rgba[2]; - - var val = Math.max(red, green, blue); - var min = Math.min(red, green, blue); - var li = val + min; // We will halve this later. - var chroma = val - min; - - var hue, sat; - if (chroma === 0) { // Return early if grayscale. - hue = 0; - sat = 0; - } else { - if (li < 1) { - sat = chroma / li; - } else { - sat = chroma / (2 - chroma); - } - if (red === val) { // Magenta to yellow. - hue = (green - blue) / chroma; - } else if (green === val) { // Yellow to cyan. - hue = 2 + (blue - red) / chroma; - } else if (blue === val) { // Cyan to magenta. - hue = 4 + (red - green) / chroma; - } - if (hue < 0) { // Confine hue to the interval [0, 1). - hue += 6; - } else if (hue >= 6) { - hue -= 6; - } - } - - return [hue / 6, sat, li / 2, rgba[3]]; -}; - -module.exports = p5.ColorConversion; - -},{"../core/core":48}],41:[function(_dereq_,module,exports){ -/** - * @module Color - * @submodule Creating & Reading - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var constants = _dereq_('../core/constants'); -_dereq_('./p5.Color'); - -/** - * Extracts the alpha value from a color or pixel array. - * - * @method alpha - * @param {Object} obj p5.Color object or pixel array - * @example - * <div> - * <code> - * noStroke(); - * c = color(0, 126, 255, 102); - * fill(c); - * rect(15, 15, 35, 70); - * value = alpha(c); // Sets 'value' to 102 - * fill(value); - * rect(50, 15, 35, 70); - * </code> - * </div> - */ -p5.prototype.alpha = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getAlpha(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Extracts the blue value from a color or pixel array. - * - * @method blue - * @param {Object} obj p5.Color object or pixel array - * @example - * <div> - * <code> - * c = color(175, 100, 220); // Define color 'c' - * fill(c); // Use color variable 'c' as fill color - * rect(15, 20, 35, 60); // Draw left rectangle - * - * blueValue = blue(c); // Get blue in 'c' - * println(blueValue); // Prints "220.0" - * fill(0, 0, blueValue); // Use 'blueValue' in new fill - * rect(50, 20, 35, 60); // Draw right rectangle - * </code> - * </div> - */ -p5.prototype.blue = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getBlue(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Extracts the HSB brightness value from a color or pixel array. - * - * @method brightness - * @param {Object} color p5.Color object or pixel array - * @example - * <div> - * <code> - * noStroke(); - * colorMode(HSB, 255); - * c = color(0, 126, 255); - * fill(c); - * rect(15, 20, 35, 60); - * value = brightness(c); // Sets 'value' to 255 - * fill(value); - * rect(50, 20, 35, 60); - * </code> - * </div> - */ -p5.prototype.brightness = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getBrightness(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Creates colors for storing in variables of the color datatype. The - * parameters are interpreted as RGB or HSB values depending on the - * current colorMode(). The default mode is RGB values from 0 to 255 - * and, therefore, the function call color(255, 204, 0) will return a - * bright yellow color. - * <br><br> - * Note that if only one value is provided to color(), it will be interpreted - * as a grayscale value. Add a second value, and it will be used for alpha - * transparency. When three values are specified, they are interpreted as - * either RGB or HSB values. Adding a fourth value applies alpha - * transparency. If a single string parameter is provided it will be - * interpreted as a CSS-compatible color string. - * - * Colors are stored as Numbers or Arrays. - * - * @method color - * @param {Number|String} v1 gray value or red or hue value relative to - * the current color range, or a color string - * @param {Number} [v2] gray value or green or saturation value - * relative to the current color range (or - * alpha value if first param is gray value) - * @param {Number} [v3] gray value or blue or brightness value - * relative to the current color range - * @param {Number} [alpha] alpha value relative to current color range - * @return {Array} resulting color - * - * @example - * <div> - * <code> - * var c = color(255, 204, 0); // Define color 'c' - * fill(c); // Use color variable 'c' as fill color - * noStroke(); // Don't draw a stroke around shapes - * rect(30, 20, 55, 55); // Draw rectangle - * </code> - * </div> - * - * <div> - * <code> - * var c = color(255, 204, 0); // Define color 'c' - * fill(c); // Use color variable 'c' as fill color - * noStroke(); // Don't draw a stroke around shapes - * ellipse(25, 25, 80, 80); // Draw left circle - * - * // Using only one value with color() - * // generates a grayscale value. - * var c = color(65); // Update 'c' with grayscale value - * fill(c); // Use updated 'c' as fill color - * ellipse(75, 75, 80, 80); // Draw right circle - * </code> - * </div> - * - * <div> - * <code> - * // Named SVG & CSS colors may be used, - * var c = color('magenta'); - * fill(c); // Use 'c' as fill color - * noStroke(); // Don't draw a stroke around shapes - * rect(20, 20, 60, 60); // Draw rectangle - * </code> - * </div> - * - * <div> - * <code> - * // as can hex color codes: - * noStroke(); // Don't draw a stroke around shapes - * var c = color('#0f0'); - * fill(c); // Use 'c' as fill color - * rect(0, 10, 45, 80); // Draw rectangle - * - * c = color('#00ff00'); - * fill(c); // Use updated 'c' as fill color - * rect(55, 10, 45, 80); // Draw rectangle - * </code> - * </div> - * - * <div> - * <code> - * // RGB and RGBA color strings are also supported: - * // these all set to the same color (solid blue) - * var c; - * noStroke(); // Don't draw a stroke around shapes - * c = color('rgb(0,0,255)'); - * fill(c); // Use 'c' as fill color - * rect(10, 10, 35, 35); // Draw rectangle - * - * c = color('rgb(0%, 0%, 100%)'); - * fill(c); // Use updated 'c' as fill color - * rect(55, 10, 35, 35); // Draw rectangle - * - * c = color('rgba(0, 0, 255, 1)'); - * fill(c); // Use updated 'c' as fill color - * rect(10, 55, 35, 35); // Draw rectangle - * - * c = color('rgba(0%, 0%, 100%, 1)'); - * fill(c); // Use updated 'c' as fill color - * rect(55, 55, 35, 35); // Draw rectangle - * </code> - * </div> - * - * <div> - * <code> - * // HSL color is also supported and can be specified - * // by value - * var c; - * noStroke(); // Don't draw a stroke around shapes - * c = color('hsl(160, 100%, 50%)'); - * fill(c); // Use 'c' as fill color - * rect(0, 10, 45, 80); // Draw rectangle - * - * c = color('hsla(160, 100%, 50%, 0.5)'); - * fill(c); // Use updated 'c' as fill color - * rect(55, 10, 45, 80); // Draw rectangle - * </code> - * </div> - * - * <div> - * <code> - * // HSB color is also supported and can be specified - * // by value - * var c; - * noStroke(); // Don't draw a stroke around shapes - * c = color('hsb(160, 100%, 50%)'); - * fill(c); // Use 'c' as fill color - * rect(0, 10, 45, 80); // Draw rectangle - * - * c = color('hsba(160, 100%, 50%, 0.5)'); - * fill(c); // Use updated 'c' as fill color - * rect(55, 10, 45, 80); // Draw rectangle - * </code> - * </div> - * - * <div> - * <code> - * var c; // Declare color 'c' - * noStroke(); // Don't draw a stroke around shapes - * - * // If no colorMode is specified, then the - * // default of RGB with scale of 0-255 is used. - * c = color(50, 55, 100); // Create a color for 'c' - * fill(c); // Use color variable 'c' as fill color - * rect(0, 10, 45, 80); // Draw left rect - * - * colorMode(HSB, 100); // Use HSB with scale of 0-100 - * c = color(50, 55, 100); // Update 'c' with new color - * fill(c); // Use updated 'c' as fill color - * rect(55, 10, 45, 80); // Draw right rect - * </code> - * </div> - */ -p5.prototype.color = function() { - if (arguments[0] instanceof p5.Color) { - return arguments[0]; // Do nothing if argument is already a color object. - } else if (arguments[0] instanceof Array) { - if (this instanceof p5.Renderer) { - return new p5.Color(this, arguments[0]); - } else { - return new p5.Color(this._renderer, arguments[0]); - } - } else { - if (this instanceof p5.Renderer) { - return new p5.Color(this, arguments); - } else { - return new p5.Color(this._renderer, arguments); - } - } -}; - -/** - * Extracts the green value from a color or pixel array. - * - * @method green - * @param {Object} color p5.Color object or pixel array - * @example - * <div> - * <code> - * c = color(20, 75, 200); // Define color 'c' - * fill(c); // Use color variable 'c' as fill color - * rect(15, 20, 35, 60); // Draw left rectangle - * - * greenValue = green(c); // Get green in 'c' - * println(greenValue); // Print "75.0" - * fill(0, greenValue, 0); // Use 'greenValue' in new fill - * rect(50, 20, 35, 60); // Draw right rectangle - * </code> - * </div> - */ -p5.prototype.green = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getGreen(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Extracts the hue value from a color or pixel array. - * - * Hue exists in both HSB and HSL. This function will return the - * HSB-normalized hue when supplied with an HSB color object (or when supplied - * with a pixel array while the color mode is HSB), but will default to the - * HSL-normalized hue otherwise. (The values will only be different if the - * maximum hue setting for each system is different.) - * - * @method hue - * @param {Object} color p5.Color object or pixel array - * @example - * <div> - * <code> - * noStroke(); - * colorMode(HSB, 255); - * c = color(0, 126, 255); - * fill(c); - * rect(15, 20, 35, 60); - * value = hue(c); // Sets 'value' to "0" - * fill(value); - * rect(50, 20, 35, 60); - * </code> - * </div> - */ -p5.prototype.hue = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getHue(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Blends two colors to find a third color somewhere between them. The amt - * parameter is the amount to interpolate between the two values where 0.0 - * equal to the first color, 0.1 is very near the first color, 0.5 is halfway - * in between, etc. An amount below 0 will be treated as 0. Likewise, amounts - * above 1 will be capped at 1. This is different from the behavior of lerp(), - * but necessary because otherwise numbers outside the range will produce - * strange and unexpected colors. - * <br><br> - * The way that colours are interpolated depends on the current color mode. - * - * @method lerpColor - * @param {Array/Number} c1 interpolate from this color - * @param {Array/Number} c2 interpolate to this color - * @param {Number} amt number between 0 and 1 - * @return {Array/Number} interpolated color - * @example - * <div> - * <code> - * colorMode(RGB); - * stroke(255); - * background(51); - * from = color(218, 165, 32); - * to = color(72, 61, 139); - * colorMode(RGB); // Try changing to HSB. - * interA = lerpColor(from, to, .33); - * interB = lerpColor(from, to, .66); - * fill(from); - * rect(10, 20, 20, 60); - * fill(interA); - * rect(30, 20, 20, 60); - * fill(interB); - * rect(50, 20, 20, 60); - * fill(to); - * rect(70, 20, 20, 60); - * </code> - * </div> - */ -p5.prototype.lerpColor = function(c1, c2, amt) { - var mode = this._renderer._colorMode; - var maxes = this._renderer._colorMaxes; - var l0, l1, l2, l3; - var fromArray, toArray; - - if (mode === constants.RGB) { - fromArray = c1.levels.map(function(level) { - return level / 255; - }); - toArray = c2.levels.map(function(level) { - return level / 255; - }); - } else if (mode === constants.HSB) { - c1._getBrightness(); // Cache hsba so it definitely exists. - c2._getBrightness(); - fromArray = c1.hsba; - toArray = c2.hsba; - } else if (mode === constants.HSL) { - c1._getLightness(); // Cache hsla so it definitely exists. - c2._getLightness(); - fromArray = c1.hsla; - toArray = c2.hsla; - } else { - throw new Error (mode + 'cannot be used for interpolation.'); - } - - // Prevent extrapolation. - amt = Math.max(Math.min(amt, 1), 0); - - // Perform interpolation. - l0 = this.lerp(fromArray[0], toArray[0], amt); - l1 = this.lerp(fromArray[1], toArray[1], amt); - l2 = this.lerp(fromArray[2], toArray[2], amt); - l3 = this.lerp(fromArray[3], toArray[3], amt); - - // Scale components. - l0 *= maxes[mode][0]; - l1 *= maxes[mode][1]; - l2 *= maxes[mode][2]; - l3 *= maxes[mode][3]; - - return this.color(l0, l1, l2, l3); -}; - -/** - * Extracts the HSL lightness value from a color or pixel array. - * - * @method lightness - * @param {Object} color p5.Color object or pixel array - * @example - * <div> - * <code> - * noStroke(); - * colorMode(HSL); - * c = color(156, 100, 50, 1); - * fill(c); - * rect(15, 20, 35, 60); - * value = lightness(c); // Sets 'value' to 50 - * fill(value); - * rect(50, 20, 35, 60); - * </code> - * </div> - */ -p5.prototype.lightness = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getLightness(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Extracts the red value from a color or pixel array. - * - * @method red - * @param {Object} obj p5.Color object or pixel array - * @example - * <div> - * <code> - * c = color(255, 204, 0); // Define color 'c' - * fill(c); // Use color variable 'c' as fill color - * rect(15, 20, 35, 60); // Draw left rectangle - * - * redValue = red(c); // Get red in 'c' - * println(redValue); // Print "255.0" - * fill(redValue, 0, 0); // Use 'redValue' in new fill - * rect(50, 20, 35, 60); // Draw right rectangle - * </code> - * </div> - * - * <div> - * <code> - * colorMode(RGB, 255); - * var c = color(127, 255, 0); - * colorMode(RGB, 1); - * var myColor = red(c); - * print(myColor); - * </code> - * </div> - */ -p5.prototype.red = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getRed(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -/** - * Extracts the saturation value from a color or pixel array. - * - * Saturation is scaled differently in HSB and HSL. This function will return - * the HSB saturation when supplied with an HSB color object (or when supplied - * with a pixel array while the color mode is HSB), but will default to the - * HSL saturation otherwise. - * - * @method saturation - * @param {Object} color p5.Color object or pixel array - * @example - * <div> - * <code> - * noStroke(); - * colorMode(HSB, 255); - * c = color(0, 126, 255); - * fill(c); - * rect(15, 20, 35, 60); - * value = saturation(c); // Sets 'value' to 126 - * fill(value); - * rect(50, 20, 35, 60); - * </code> - * </div> - */ -p5.prototype.saturation = function(c) { - if (c instanceof p5.Color || c instanceof Array) { - return this.color(c)._getSaturation(); - } else { - throw new Error('Needs p5.Color or pixel array as argument.'); - } -}; - -module.exports = p5; - -},{"../core/constants":47,"../core/core":48,"./p5.Color":42}],42:[function(_dereq_,module,exports){ -/** - * @module Color - * @submodule Creating & Reading - * @for p5 - * @requires core - * @requires constants - * @requires color_conversion - */ - -var p5 = _dereq_('../core/core'); -var constants = _dereq_('../core/constants'); -var color_conversion = _dereq_('./color_conversion'); - -/** - * We define colors to be immutable objects. Each color stores the color mode - * and level maxes that applied at the time of its construction. These are - * used to interpret the input arguments and to format the output e.g. when - * saturation() is requested. - * - * Internally we store an array representing the ideal RGBA values in floating - * point form, normalized from 0 to 1. From this we calculate the closest - * screen color (RGBA levels from 0 to 255) and expose this to the renderer. - * - * We also cache normalized, floating point components of the color in various - * representations as they are calculated. This is done to prevent repeating a - * conversion that has already been performed. - * - * @class p5.Color - * @constructor - */ -p5.Color = function(renderer, vals) { - - // Record color mode and maxes at time of construction. - this.mode = renderer._colorMode; - this.maxes = renderer._colorMaxes; - - // Calculate normalized RGBA values. - if (this.mode !== constants.RGB && - this.mode !== constants.HSL && - this.mode !== constants.HSB) { - throw new Error(this.mode + ' is an invalid colorMode.'); - } else { - this._array = p5.Color._parseInputs.apply(renderer, vals); - } - - // Expose closest screen color. - this.levels = this._array.map(function(level) { - return Math.round(level * 255); - }); - - return this; -}; - -p5.Color.prototype.toString = function() { - var a = this.levels; - a[3] = this._array[3]; // String representation uses normalized alpha. - return 'rgba('+a[0]+','+a[1]+','+a[2]+','+ a[3] +')'; -}; - -p5.Color.prototype._getAlpha = function() { - return this._array[3] * this.maxes[this.mode][3]; -}; - -p5.Color.prototype._getBlue = function() { - return this._array[2] * this.maxes[constants.RGB][2]; -}; - -p5.Color.prototype._getBrightness = function() { - if (!this.hsba) { - this.hsba = color_conversion._rgbaToHSBA(this._array); - } - return this.hsba[2] * this.maxes[constants.HSB][2]; -}; - -p5.Color.prototype._getGreen = function() { - return this._array[1] * this.maxes[constants.RGB][1]; -}; - -/** - * Hue is the same in HSB and HSL, but the maximum value may be different. - * This function will return the HSB-normalized saturation when supplied with - * an HSB color object, but will default to the HSL-normalized saturation - * otherwise. - */ -p5.Color.prototype._getHue = function() { - if (this.mode === constants.HSB) { - if (!this.hsba) { - this.hsba = color_conversion._rgbaToHSBA(this._array); - } - return this.hsba[0] * this.maxes[constants.HSB][0]; - } else { - if (!this.hsla) { - this.hsla = color_conversion._rgbaToHSLA(this._array); - } - return this.hsla[0] * this.maxes[constants.HSL][0]; - } -}; - -p5.Color.prototype._getLightness = function() { - if (!this.hsla) { - this.hsla = color_conversion._rgbaToHSLA(this._array); - } - return this.hsla[2] * this.maxes[constants.HSL][2]; -}; - -p5.Color.prototype._getRed = function() { - return this._array[0] * this.maxes[constants.RGB][0]; -}; - -/** - * Saturation is scaled differently in HSB and HSL. This function will return - * the HSB saturation when supplied with an HSB color object, but will default - * to the HSL saturation otherwise. - */ -p5.Color.prototype._getSaturation = function() { - if (this.mode === constants.HSB) { - if (!this.hsba) { - this.hsba = color_conversion._rgbaToHSBA(this._array); - } - return this.hsba[1] * this.maxes[constants.HSB][1]; - } else { - if (!this.hsla) { - this.hsla = color_conversion._rgbaToHSLA(this._array); - } - return this.hsla[1] * this.maxes[constants.HSL][1]; - } -}; - -/** - * CSS named colors. - */ -var namedColors = { - aliceblue: '#f0f8ff', - antiquewhite: '#faebd7', - aqua: '#00ffff', - aquamarine: '#7fffd4', - azure: '#f0ffff', - beige: '#f5f5dc', - bisque: '#ffe4c4', - black: '#000000', - blanchedalmond: '#ffebcd', - blue: '#0000ff', - blueviolet: '#8a2be2', - brown: '#a52a2a', - burlywood: '#deb887', - cadetblue: '#5f9ea0', - chartreuse: '#7fff00', - chocolate: '#d2691e', - coral: '#ff7f50', - cornflowerblue: '#6495ed', - cornsilk: '#fff8dc', - crimson: '#dc143c', - cyan: '#00ffff', - darkblue: '#00008b', - darkcyan: '#008b8b', - darkgoldenrod: '#b8860b', - darkgray: '#a9a9a9', - darkgreen: '#006400', - darkgrey: '#a9a9a9', - darkkhaki: '#bdb76b', - darkmagenta: '#8b008b', - darkolivegreen: '#556b2f', - darkorange: '#ff8c00', - darkorchid: '#9932cc', - darkred: '#8b0000', - darksalmon: '#e9967a', - darkseagreen: '#8fbc8f', - darkslateblue: '#483d8b', - darkslategray: '#2f4f4f', - darkslategrey: '#2f4f4f', - darkturquoise: '#00ced1', - darkviolet: '#9400d3', - deeppink: '#ff1493', - deepskyblue: '#00bfff', - dimgray: '#696969', - dimgrey: '#696969', - dodgerblue: '#1e90ff', - firebrick: '#b22222', - floralwhite: '#fffaf0', - forestgreen: '#228b22', - fuchsia: '#ff00ff', - gainsboro: '#dcdcdc', - ghostwhite: '#f8f8ff', - gold: '#ffd700', - goldenrod: '#daa520', - gray: '#808080', - green: '#008000', - greenyellow: '#adff2f', - grey: '#808080', - honeydew: '#f0fff0', - hotpink: '#ff69b4', - indianred: '#cd5c5c', - indigo: '#4b0082', - ivory: '#fffff0', - khaki: '#f0e68c', - lavender: '#e6e6fa', - lavenderblush: '#fff0f5', - lawngreen: '#7cfc00', - lemonchiffon: '#fffacd', - lightblue: '#add8e6', - lightcoral: '#f08080', - lightcyan: '#e0ffff', - lightgoldenrodyellow: '#fafad2', - lightgray: '#d3d3d3', - lightgreen: '#90ee90', - lightgrey: '#d3d3d3', - lightpink: '#ffb6c1', - lightsalmon: '#ffa07a', - lightseagreen: '#20b2aa', - lightskyblue: '#87cefa', - lightslategray: '#778899', - lightslategrey: '#778899', - lightsteelblue: '#b0c4de', - lightyellow: '#ffffe0', - lime: '#00ff00', - limegreen: '#32cd32', - linen: '#faf0e6', - magenta: '#ff00ff', - maroon: '#800000', - mediumaquamarine: '#66cdaa', - mediumblue: '#0000cd', - mediumorchid: '#ba55d3', - mediumpurple: '#9370db', - mediumseagreen: '#3cb371', - mediumslateblue: '#7b68ee', - mediumspringgreen: '#00fa9a', - mediumturquoise: '#48d1cc', - mediumvioletred: '#c71585', - midnightblue: '#191970', - mintcream: '#f5fffa', - mistyrose: '#ffe4e1', - moccasin: '#ffe4b5', - navajowhite: '#ffdead', - navy: '#000080', - oldlace: '#fdf5e6', - olive: '#808000', - olivedrab: '#6b8e23', - orange: '#ffa500', - orangered: '#ff4500', - orchid: '#da70d6', - palegoldenrod: '#eee8aa', - palegreen: '#98fb98', - paleturquoise: '#afeeee', - palevioletred: '#db7093', - papayawhip: '#ffefd5', - peachpuff: '#ffdab9', - peru: '#cd853f', - pink: '#ffc0cb', - plum: '#dda0dd', - powderblue: '#b0e0e6', - purple: '#800080', - red: '#ff0000', - rosybrown: '#bc8f8f', - royalblue: '#4169e1', - saddlebrown: '#8b4513', - salmon: '#fa8072', - sandybrown: '#f4a460', - seagreen: '#2e8b57', - seashell: '#fff5ee', - sienna: '#a0522d', - silver: '#c0c0c0', - skyblue: '#87ceeb', - slateblue: '#6a5acd', - slategray: '#708090', - slategrey: '#708090', - snow: '#fffafa', - springgreen: '#00ff7f', - steelblue: '#4682b4', - tan: '#d2b48c', - teal: '#008080', - thistle: '#d8bfd8', - tomato: '#ff6347', - turquoise: '#40e0d0', - violet: '#ee82ee', - wheat: '#f5deb3', - white: '#ffffff', - whitesmoke: '#f5f5f5', - yellow: '#ffff00', - yellowgreen: '#9acd32' -}; - -/** - * These regular expressions are used to build up the patterns for matching - * viable CSS color strings: fragmenting the regexes in this way increases the - * legibility and comprehensibility of the code. - * - * Note that RGB values of .9 are not parsed by IE, but are supported here for - * color string consistency. - */ -var WHITESPACE = /\s*/; // Match zero or more whitespace characters. -var INTEGER = /(\d{1,3})/; // Match integers: 79, 255, etc. -var DECIMAL = /((?:\d+(?:\.\d+)?)|(?:\.\d+))/; // Match 129.6, 79, .9, etc. -var PERCENT = new RegExp(DECIMAL.source + '%'); // Match 12.9%, 79%, .9%, etc. - -/** - * Full color string patterns. The capture groups are necessary. - */ -var colorPatterns = { - // Match colors in format #XXX, e.g. #416. - HEX3: /^#([a-f0-9])([a-f0-9])([a-f0-9])$/i, - - // Match colors in format #XXXXXX, e.g. #b4d455. - HEX6: /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i, - - // Match colors in format rgb(R, G, B), e.g. rgb(255, 0, 128). - RGB: new RegExp([ - '^rgb\\(', - INTEGER.source, - ',', - INTEGER.source, - ',', - INTEGER.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format rgb(R%, G%, B%), e.g. rgb(100%, 0%, 28.9%). - RGB_PERCENT: new RegExp([ - '^rgb\\(', - PERCENT.source, - ',', - PERCENT.source, - ',', - PERCENT.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format rgb(R, G, B, A), e.g. rgb(255, 0, 128, 0.25). - RGBA: new RegExp([ - '^rgba\\(', - INTEGER.source, - ',', - INTEGER.source, - ',', - INTEGER.source, - ',', - DECIMAL.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format rgb(R%, G%, B%, A), e.g. rgb(100%, 0%, 28.9%, 0.5). - RGBA_PERCENT: new RegExp([ - '^rgba\\(', - PERCENT.source, - ',', - PERCENT.source, - ',', - PERCENT.source, - ',', - DECIMAL.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format hsla(H, S%, L%), e.g. hsl(100, 40%, 28.9%). - HSL: new RegExp([ - '^hsl\\(', - INTEGER.source, - ',', - PERCENT.source, - ',', - PERCENT.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format hsla(H, S%, L%, A), e.g. hsla(100, 40%, 28.9%, 0.5). - HSLA: new RegExp([ - '^hsla\\(', - INTEGER.source, - ',', - PERCENT.source, - ',', - PERCENT.source, - ',', - DECIMAL.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format hsb(H, S%, B%), e.g. hsb(100, 40%, 28.9%). - HSB: new RegExp([ - '^hsb\\(', - INTEGER.source, - ',', - PERCENT.source, - ',', - PERCENT.source, - '\\)$' - ].join(WHITESPACE.source), 'i'), - - // Match colors in format hsba(H, S%, B%, A), e.g. hsba(100, 40%, 28.9%, 0.5). - HSBA: new RegExp([ - '^hsba\\(', - INTEGER.source, - ',', - PERCENT.source, - ',', - PERCENT.source, - ',', - DECIMAL.source, - '\\)$' - ].join(WHITESPACE.source), 'i') -}; - -/** - * For a number of different inputs, returns a color formatted as [r, g, b, a] - * arrays, with each component normalized between 0 and 1. - * - * @param {Array-like} args An 'array-like' object that represents a list of - * arguments - * @return {Array} a color formatted as [r, g, b, a] - * Example: - * input ==> output - * g ==> [g, g, g, 255] - * g,a ==> [g, g, g, a] - * r, g, b ==> [r, g, b, 255] - * r, g, b, a ==> [r, g, b, a] - * [g] ==> [g, g, g, 255] - * [g, a] ==> [g, g, g, a] - * [r, g, b] ==> [r, g, b, 255] - * [r, g, b, a] ==> [r, g, b, a] - * @example - * <div> - * <code> - * // todo - * </code> - * </div> - */ -p5.Color._parseInputs = function() { - var numArgs = arguments.length; - var mode = this._colorMode; - var maxes = this._colorMaxes; - var results = []; - - if (numArgs >= 3) { // Argument is a list of component values. - - results[0] = arguments[0] / maxes[mode][0]; - results[1] = arguments[1] / maxes[mode][1]; - results[2] = arguments[2] / maxes[mode][2]; - - // Alpha may be undefined, so default it to 100%. - if (typeof arguments[3] === 'number') { - results[3] = arguments[3] / maxes[mode][3]; - } else { - results[3] = 1; - } - - // Constrain components to the range [0,1]. - results = results.map(function(value) { - return Math.max(Math.min(value, 1), 0); - }); - - // Convert to RGBA and return. - if (mode === constants.HSL) { - return color_conversion._hslaToRGBA(results); - } else if (mode === constants.HSB) { - return color_conversion._hsbaToRGBA(results); - } else { - return results; - } - - } else if (numArgs === 1 && typeof arguments[0] === 'string') { - - var str = arguments[0].trim().toLowerCase(); - - // Return if string is a named colour. - if (namedColors[str]) { - return p5.Color._parseInputs.apply(this, [namedColors[str]]); - } - - // Try RGBA pattern matching. - if (colorPatterns.HEX3.test(str)) { // #rgb - results = colorPatterns.HEX3.exec(str).slice(1).map(function(color) { - return parseInt(color + color, 16) / 255; - }); - results[3] = 1; - return results; - } else if (colorPatterns.HEX6.test(str)) { // #rrggbb - results = colorPatterns.HEX6.exec(str).slice(1).map(function(color) { - return parseInt(color, 16) / 255; - }); - results[3] = 1; - return results; - } else if (colorPatterns.RGB.test(str)) { // rgb(R,G,B) - results = colorPatterns.RGB.exec(str).slice(1).map(function(color) { - return color / 255; - }); - results[3] = 1; - return results; - } else if (colorPatterns.RGB_PERCENT.test(str)) { // rgb(R%,G%,B%) - results = colorPatterns.RGB_PERCENT.exec(str).slice(1) - .map(function(color) { - return parseFloat(color) / 100; - }); - results[3] = 1; - return results; - } else if (colorPatterns.RGBA.test(str)) { // rgba(R,G,B,A) - results = colorPatterns.RGBA.exec(str).slice(1) - .map(function(color, idx) { - if (idx === 3) { - return parseFloat(color); - } - return color / 255; - }); - return results; - } else if (colorPatterns.RGBA_PERCENT.test(str)) { // rgba(R%,G%,B%,A%) - results = colorPatterns.RGBA_PERCENT.exec(str).slice(1) - .map(function(color, idx) { - if (idx === 3) { - return parseFloat(color); - } - return parseFloat(color) / 100; - }); - return results; - } - - // Try HSLA pattern matching. - if (colorPatterns.HSL.test(str)) { // hsl(H,S,L) - results = colorPatterns.HSL.exec(str).slice(1) - .map(function(color, idx) { - if (idx === 0) { - return parseInt(color, 10) / 360; - } - return parseInt(color, 10) / 100; - }); - results[3] = 1; - } else if (colorPatterns.HSLA.test(str)) { // hsla(H,S,L,A) - results = colorPatterns.HSLA.exec(str).slice(1) - .map(function(color, idx) { - if (idx === 0) { - return parseInt(color, 10) / 360; - } - else if (idx === 3) { - return parseFloat(color); - } - return parseInt(color, 10) / 100; - }); - } - if (results.length) { - return color_conversion._hslaToRGBA(results); - } - - // Try HSBA pattern matching. - if (colorPatterns.HSB.test(str)) { // hsb(H,S,B) - results = colorPatterns.HSB.exec(str).slice(1) - .map(function(color, idx) { - if (idx === 0) { - return parseInt(color, 10) / 360; - } - return parseInt(color, 10) / 100; - }); - results[3] = 1; - } else if (colorPatterns.HSBA.test(str)) { // hsba(H,S,B,A) - results = colorPatterns.HSBA.exec(str).slice(1) - .map(function(color, idx) { - if (idx === 0) { - return parseInt(color, 10) / 360; - } - else if (idx === 3) { - return parseFloat(color); - } - return parseInt(color, 10) / 100; - }); - } - if (results.length) { - return color_conversion._hsbaToRGBA(results); - } - - // Input did not match any CSS color pattern: default to white. - results = [1, 1, 1, 1]; - - } else if ((numArgs === 1 || numArgs === 2) && - typeof arguments[0] === 'number') { // 'Grayscale' mode. - - /** - * For HSB and HSL, interpret the gray level as a brightness/lightness - * value (they are equivalent when chroma is zero). For RGB, normalize the - * gray level according to the blue maximum. - */ - results[0] = arguments[0] / maxes[mode][2]; - results[1] = arguments[0] / maxes[mode][2]; - results[2] = arguments[0] / maxes[mode][2]; - - // Alpha may be undefined, so default it to 100%. - if (typeof arguments[1] === 'number') { - results[3] = arguments[1] / maxes[mode][3]; - } else { - results[3] = 1; - } - - // Constrain components to the range [0,1]. - results = results.map(function(value) { - return Math.max(Math.min(value, 1), 0); - }); - - } else { - throw new Error (arguments + 'is not a valid color representation.'); - } - - return results; -}; - -module.exports = p5.Color; - -},{"../core/constants":47,"../core/core":48,"./color_conversion":40}],43:[function(_dereq_,module,exports){ -/** - * @module Color - * @submodule Setting - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var constants = _dereq_('../core/constants'); -_dereq_('./p5.Color'); - -/** - * The background() function sets the color used for the background of the - * p5.js canvas. The default background is light gray. This function is - * typically used within draw() to clear the display window at the beginning - * of each frame, but it can be used inside setup() to set the background on - * the first frame of animation or if the background need only be set once. - * - * @method background - * @param {Number|String|p5.Color|p5.Image} v1 gray value, red or hue value - * (depending on the current - * color mode), color string, - * p5.Color, or p5.Image - * @param {Number} [v2] green or saturation value - * (depending on the current - * color mode) - * @param {Number} [v3] blue or brightness value - * (depending on the current - * color mode) - * @param {Number} [a] opacity of the background - * - * @example - * <div> - * <code> - * // Grayscale integer value - * background(51); - * </code> - * </div> - * - * <div> - * <code> - * // R, G & B integer values - * background(255, 204, 0); - * </code> - * </div> - * - * <div> - * <code> - * // H, S & B integer values - * colorMode(HSB); - * background(255, 204, 100); - * </code> - * </div> - * - * <div> - * <code> - * // Named SVG/CSS color string - * background('red'); - * </code> - * </div> - * - * <div> - * <code> - * // three-digit hexadecimal RGB notation - * background('#fae'); - * </code> - * </div> - * - * <div> - * <code> - * // six-digit hexadecimal RGB notation - * background('#222222'); - * </code> - * </div> - * - * <div> - * <code> - * // integer RGB notation - * background('rgb(0,255,0)'); - * </code> - * </div> - * - * <div> - * <code> - * // integer RGBA notation - * background('rgba(0,255,0, 0.25)'); - * </code> - * </div> - * - * <div> - * <code> - * // percentage RGB notation - * background('rgb(100%,0%,10%)'); - * </code> - * </div> - * - * <div> - * <code> - * // percentage RGBA notation - * background('rgba(100%,0%,100%,0.5)'); - * </code> - * </div> - * - * <div> - * <code> - * // p5 Color object - * background(color(0, 0, 255)); - * </code> - * </div> - */ -p5.prototype.background = function() { - if (arguments[0] instanceof p5.Image) { - this.image(arguments[0], 0, 0, this.width, this.height); - } else { - this._renderer.background.apply(this._renderer, arguments); - } - return this; -}; - -/** - * Clears the pixels within a buffer. This function only works on p5.Canvas - * objects created with the createCanvas() function; it won't work with the - * main display window. Unlike the main graphics context, pixels in - * additional graphics areas created with createGraphics() can be entirely - * or partially transparent. This function clears everything to make all of - * the pixels 100% transparent. - * - * @method clear - * @example - * <div> - * <code> - * // Clear the screen on mouse press. - * function setup() { - * createCanvas(100, 100); - * } - * - * function draw() { - * ellipse(mouseX, mouseY, 20, 20); - * } - * - * function mousePressed() { - * clear(); - * } - * </code> - * </div> - */ -p5.prototype.clear = function() { - this._renderer.clear(); - return this; -}; - -/** - * colorMode() changes the way p5.js interprets color data. By default, the - * parameters for fill(), stroke(), background(), and color() are defined by - * values between 0 and 255 using the RGB color model. This is equivalent to - * setting colorMode(RGB, 255). Setting colorMode(HSB) lets you use the HSB - * system instead. By default, this is colorMode(HSB, 360, 100, 100, 1). You - * can also use HSL. - * <br><br> - * Note: existing color objects remember the mode that they were created in, - * so you can change modes as you like without affecting their appearance. - * - * @method colorMode - * @param {Number|Constant} mode either RGB or HSB, corresponding to - * Red/Green/Blue and Hue/Saturation/Brightness - * (or Lightness) - * @param {Number|Constant} [max1] range for the red or hue depending on the - * current color mode, or range for all values - * @param {Number|Constant} [max2] range for the green or saturation depending - * on the current color mode - * @param {Number|Constant} [max3] range for the blue or brightness/lighntess - * depending on the current color mode - * @param {Number|Constant} [maxA] range for the alpha - * @example - * <div> - * <code> - * noStroke(); - * colorMode(RGB, 100); - * for (i = 0; i < 100; i++) { - * for (j = 0; j < 100; j++) { - * stroke(i, j, 0); - * point(i, j); - * } - * } - * </code> - * </div> - * - * <div> - * <code> - * noStroke(); - * colorMode(HSB, 100); - * for (i = 0; i < 100; i++) { - * for (j = 0; j < 100; j++) { - * stroke(i, j, 100); - * point(i, j); - * } - * } - * </code> - * </div> - * - * <div> - * <code> - * colorMode(RGB, 255); - * var c = color(127, 255, 0); - * - * colorMode(RGB, 1); - * var myColor = c._getRed(); - * text(myColor, 10, 10, 80, 80); - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * colorMode(RGB, 255, 255, 255, 1); - * background(255); - * - * strokeWeight(4); - * stroke(255, 0 , 10, 0.3); - * ellipse(40, 40, 50, 50); - * ellipse(50, 50, 40, 40); - * </code> - * </div> - */ -p5.prototype.colorMode = function() { - if (arguments[0] === constants.RGB || - arguments[0] === constants.HSB || - arguments[0] === constants.HSL) { - - // Set color mode. - this._renderer._colorMode = arguments[0]; - - // Set color maxes. - var maxes = this._renderer._colorMaxes[this._renderer._colorMode]; - if (arguments.length === 2) { - maxes[0] = arguments[1]; // Red - maxes[1] = arguments[1]; // Green - maxes[2] = arguments[1]; // Blue - maxes[3] = arguments[1]; // Alpha - } else if (arguments.length === 4) { - maxes[0] = arguments[1]; // Red - maxes[1] = arguments[2]; // Green - maxes[2] = arguments[3]; // Blue - } else if (arguments.length === 5) { - maxes[0] = arguments[1]; // Red - maxes[1] = arguments[2]; // Green - maxes[2] = arguments[3]; // Blue - maxes[3] = arguments[4]; // Alpha - } - } - - return this; -}; - -/** - * Sets the color used to fill shapes. For example, if you run - * fill(204, 102, 0), all subsequent shapes will be filled with orange. This - * color is either specified in terms of the RGB or HSB color depending on - * the current colorMode(). (The default color space is RGB, with each value - * in the range from 0 to 255). - * <br><br> - * If a single string argument is provided, RGB, RGBA and Hex CSS color strings - * and all named color strings are supported. A p5 Color object can also be - * provided to set the fill color. - * - * @method fill - * @param {Number|Array|String|p5.Color} v1 gray value, red or hue value - * (depending on the current color - * mode), or color Array, or CSS - * color string - * @param {Number} [v2] green or saturation value - * (depending on the current - * color mode) - * @param {Number} [v3] blue or brightness value - * (depending on the current - * color mode) - * @param {Number} [a] opacity of the background - * - * @example - * <div> - * <code> - * // Grayscale integer value - * fill(51); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // R, G & B integer values - * fill(255, 204, 0); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // H, S & B integer values - * colorMode(HSB); - * fill(255, 204, 100); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // Named SVG/CSS color string - * fill('red'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // three-digit hexadecimal RGB notation - * fill('#fae'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // six-digit hexadecimal RGB notation - * fill('#222222'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // integer RGB notation - * fill('rgb(0,255,0)'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // integer RGBA notation - * fill('rgba(0,255,0, 0.25)'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // percentage RGB notation - * fill('rgb(100%,0%,10%)'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // percentage RGBA notation - * fill('rgba(100%,0%,100%,0.5)'); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // p5 Color object - * fill(color(0, 0, 255)); - * rect(20, 20, 60, 60); - * </code> - * </div> - */ -p5.prototype.fill = function() { - this._renderer._setProperty('_fillSet', true); - this._renderer._setProperty('_doFill', true); - this._renderer.fill.apply(this._renderer, arguments); - return this; -}; - -/** - * Disables filling geometry. If both noStroke() and noFill() are called, - * nothing will be drawn to the screen. - * - * @method noFill - * @example - * <div> - * <code> - * rect(15, 10, 55, 55); - * noFill(); - * rect(20, 20, 60, 60); - * </code> - * </div> - */ -p5.prototype.noFill = function() { - this._renderer._setProperty('_doFill', false); - return this; -}; - -/** - * Disables drawing the stroke (outline). If both noStroke() and noFill() - * are called, nothing will be drawn to the screen. - * - * @method noStroke - * @example - * <div> - * <code> - * noStroke(); - * rect(20, 20, 60, 60); - * </code> - * </div> - */ -p5.prototype.noStroke = function() { - this._renderer._setProperty('_doStroke', false); - return this; -}; - -/** - * Sets the color used to draw lines and borders around shapes. This color - * is either specified in terms of the RGB or HSB color depending on the - * current colorMode() (the default color space is RGB, with each value in - * the range from 0 to 255). - * <br><br> - * If a single string argument is provided, RGB, RGBA and Hex CSS color - * strings and all named color strings are supported. A p5 Color object - * can also be provided to set the stroke color. - * - * @method stroke - * @param {Number|Array|String|p5.Color} v1 gray value, red or hue value - * (depending on the current color - * mode), or color Array, or CSS - * color string - * @param {Number} [v2] green or saturation value - * (depending on the current - * color mode) - * @param {Number} [v3] blue or brightness value - * (depending on the current - * color mode) - * @param {Number} [a] opacity of the background - * - * @example - * <div> - * <code> - * // Grayscale integer value - * strokeWeight(4); - * stroke(51); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // R, G & B integer values - * stroke(255, 204, 0); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // H, S & B integer values - * colorMode(HSB); - * strokeWeight(4); - * stroke(255, 204, 100); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // Named SVG/CSS color string - * stroke('red'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // three-digit hexadecimal RGB notation - * stroke('#fae'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // six-digit hexadecimal RGB notation - * stroke('#222222'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // integer RGB notation - * stroke('rgb(0,255,0)'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // integer RGBA notation - * stroke('rgba(0,255,0,0.25)'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // percentage RGB notation - * stroke('rgb(100%,0%,10%)'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // percentage RGBA notation - * stroke('rgba(100%,0%,100%,0.5)'); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - * - * <div> - * <code> - * // p5 Color object - * stroke(color(0, 0, 255)); - * strokeWeight(4); - * rect(20, 20, 60, 60); - * </code> - * </div> - */ -p5.prototype.stroke = function() { - this._renderer._setProperty('_strokeSet', true); - this._renderer._setProperty('_doStroke', true); - this._renderer.stroke.apply(this._renderer, arguments); - return this; -}; - -module.exports = p5; - -},{"../core/constants":47,"../core/core":48,"./p5.Color":42}],44:[function(_dereq_,module,exports){ -/** - * @module Shape - * @submodule 2D Primitives - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('./core'); -var constants = _dereq_('./constants'); - -_dereq_('./error_helpers'); - -/** - * Draw an arc to the screen. If called with only a, b, c, d, start, and - * stop, the arc will be drawn as an open pie. If mode is provided, the arc - * will be drawn either open, as a chord, or as a pie as specified. The - * origin may be changed with the ellipseMode() function.<br><br> - * Note that drawing a full circle (ex: 0 to TWO_PI) will appear blank - * because 0 and TWO_PI are the same position on the unit circle. The - * best way to handle this is by using the ellipse() function instead - * to create a closed ellipse, and to use the arc() function - * only to draw parts of an ellipse. - * - * @method arc - * @param {Number} a x-coordinate of the arc's ellipse - * @param {Number} b y-coordinate of the arc's ellipse - * @param {Number} c width of the arc's ellipse by default - * @param {Number} d height of the arc's ellipse by default - * @param {Number} start angle to start the arc, specified in radians - * @param {Number} stop angle to stop the arc, specified in radians - * @param {String} [mode] optional parameter to determine the way of drawing - * the arc - * @return {Object} the p5 object - * @example - * <div> - * <code> - * arc(50, 55, 50, 50, 0, HALF_PI); - * noFill(); - * arc(50, 55, 60, 60, HALF_PI, PI); - * arc(50, 55, 70, 70, PI, PI+QUARTER_PI); - * arc(50, 55, 80, 80, PI+QUARTER_PI, TWO_PI); - * </code> - * </div> - * - * <div> - * <code> - * arc(50, 50, 80, 80, 0, PI+QUARTER_PI, OPEN); - * </code> - * </div> - * - * <div> - * <code> - * arc(50, 50, 80, 80, 0, PI+QUARTER_PI, CHORD); - * </code> - * </div> - * - * <div> - * <code> - * arc(50, 50, 80, 80, 0, PI+QUARTER_PI, PIE); - * </code> - * </div> - */ -p5.prototype.arc = function(x, y, w, h, start, stop, mode) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'arc', - args, - [ - ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'], - [ 'Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'String' ] - ] - ); - - if (!this._renderer._doStroke && !this._renderer._doFill) { - return this; - } - if (this._angleMode === constants.DEGREES) { - start = this.radians(start); - stop = this.radians(stop); - } - - // Make all angles positive... - while (start < 0) { - start += constants.TWO_PI; - } - while (stop < 0) { - stop += constants.TWO_PI; - } - // ...and confine them to the interval [0,TWO_PI). - start %= constants.TWO_PI; - stop %= constants.TWO_PI; - - // Adjust angles to counter linear scaling. - if (start <= constants.HALF_PI) { - start = Math.atan(w / h * Math.tan(start)); - } else if (start > constants.HALF_PI && start <= 3 * constants.HALF_PI) { - start = Math.atan(w / h * Math.tan(start)) + constants.PI; - } else { - start = Math.atan(w / h * Math.tan(start)) + constants.TWO_PI; - } - if (stop <= constants.HALF_PI) { - stop = Math.atan(w / h * Math.tan(stop)); - } else if (stop > constants.HALF_PI && stop <= 3 * constants.HALF_PI) { - stop = Math.atan(w / h * Math.tan(stop)) + constants.PI; - } else { - stop = Math.atan(w / h * Math.tan(stop)) + constants.TWO_PI; - } - - // Exceed the interval if necessary in order to preserve the size and - // orientation of the arc. - if (start > stop) { - stop += constants.TWO_PI; - } - // p5 supports negative width and heights for ellipses - w = Math.abs(w); - h = Math.abs(h); - this._renderer.arc(x, y, w, h, start, stop, mode); - return this; -}; - -/** - * Draws an ellipse (oval) to the screen. An ellipse with equal width and - * height is a circle. By default, the first two parameters set the location, - * and the third and fourth parameters set the shape's width and height. The - * origin may be changed with the ellipseMode() function. - * - * @method ellipse - * @param {Number} a x-coordinate of the ellipse. - * @param {Number} b y-coordinate of the ellipse. - * @param {Number} c width of the ellipse. - * @param {Number} d height of the ellipse. - * @return {p5} the p5 object - * @example - * <div> - * <code> - * ellipse(56, 46, 55, 55); - * </code> - * </div> - */ -p5.prototype.ellipse = function(x, y, w, h) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'ellipse', - args, - ['Number', 'Number', 'Number', 'Number'] - ); - - if (!this._renderer._doStroke && !this._renderer._doFill) { - return this; - } - // p5 supports negative width and heights for ellipses - w = Math.abs(w); - h = Math.abs(h); - //@TODO add catch block here if this._renderer - //doesn't have the method implemented yet - this._renderer.ellipse(x, y, w, h); - return this; -}; -/** - * Draws a line (a direct path between two points) to the screen. The version - * of line() with four parameters draws the line in 2D. To color a line, use - * the stroke() function. A line cannot be filled, therefore the fill() - * function will not affect the color of a line. 2D lines are drawn with a - * width of one pixel by default, but this can be changed with the - * strokeWeight() function. - * - * @method line - * @param {Number} x1 the x-coordinate of the first point - * @param {Number} y1 the y-coordinate of the first point - * @param {Number} x2 the x-coordinate of the second point - * @param {Number} y2 the y-coordinate of the second point - * @return {p5} the p5 object - * @example - * <div> - * <code> - * line(30, 20, 85, 75); - * </code> - * </div> - * - * <div> - * <code> - * line(30, 20, 85, 20); - * stroke(126); - * line(85, 20, 85, 75); - * stroke(255); - * line(85, 75, 30, 75); - * </code> - * </div> - */ -////commented out original -// p5.prototype.line = function(x1, y1, x2, y2) { -// if (!this._renderer._doStroke) { -// return this; -// } -// if(this._renderer.isP3D){ -// } else { -// this._renderer.line(x1, y1, x2, y2); -// } -// }; -p5.prototype.line = function() { - if (!this._renderer._doStroke) { - return this; - } - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - //check whether we should draw a 3d line or 2d - if(this._renderer.isP3D){ - this._validateParameters( - 'line', - args, - [ - ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'] - ] - ); - this._renderer.line( - args[0], - args[1], - args[2], - args[3], - args[4], - args[5]); - } else { - this._validateParameters( - 'line', - args, - [ - ['Number', 'Number', 'Number', 'Number'], - ] - ); - this._renderer.line( - args[0], - args[1], - args[2], - args[3]); - } - return this; -}; - -/** - * Draws a point, a coordinate in space at the dimension of one pixel. - * The first parameter is the horizontal value for the point, the second - * value is the vertical value for the point. The color of the point is - * determined by the current stroke. - * - * @method point - * @param {Number} x the x-coordinate - * @param {Number} y the y-coordinate - * @return {p5} the p5 object - * @example - * <div> - * <code> - * point(30, 20); - * point(85, 20); - * point(85, 75); - * point(30, 75); - * </code> - * </div> - */ -p5.prototype.point = function() { - if (!this._renderer._doStroke) { - return this; - } - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - //check whether we should draw a 3d line or 2d - if(this._renderer.isP3D){ - this._validateParameters( - 'point', - args, - [ - ['Number', 'Number', 'Number'] - ] - ); - this._renderer.point( - args[0], - args[1], - args[2] - ); - } else { - this._validateParameters( - 'point', - args, - [ - ['Number', 'Number'] - ] - ); - this._renderer.point( - args[0], - args[1] - ); - } - return this; -}; - - -/** - * Draw a quad. A quad is a quadrilateral, a four sided polygon. It is - * similar to a rectangle, but the angles between its edges are not - * constrained to ninety degrees. The first pair of parameters (x1,y1) - * sets the first vertex and the subsequent pairs should proceed - * clockwise or counter-clockwise around the defined shape. - * - * @method quad - * @param {Number} x1 the x-coordinate of the first point - * @param {Number} y1 the y-coordinate of the first point - * @param {Number} x2 the x-coordinate of the second point - * @param {Number} y2 the y-coordinate of the second point - * @param {Number} x3 the x-coordinate of the third point - * @param {Number} y3 the y-coordinate of the third point - * @param {Number} x4 the x-coordinate of the fourth point - * @param {Number} y4 the y-coordinate of the fourth point - * @return {p5} the p5 object - * @example - * <div> - * <code> - * quad(38, 31, 86, 20, 69, 63, 30, 76); - * </code> - * </div> - */ -p5.prototype.quad = function() { - if (!this._renderer._doStroke && !this._renderer._doFill) { - return this; - } - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - if(this._renderer.isP3D){ - this._validateParameters( - 'quad', - args, - [ - [ 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number'] - ] - ); - this._renderer.quad( - args[0], - args[1], - args[2], - args[3], - args[4], - args[5], - args[6], - args[7], - args[8], - args[9], - args[10], - args[11] - ); - } else { - this._validateParameters( - 'quad', - args, - [ - [ 'Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', 'Number' ] - ] - ); - this._renderer.quad( - args[0], - args[1], - args[2], - args[3], - args[4], - args[5], - args[6], - args[7] - ); - } - return this; -}; - -/** -* Draws a rectangle to the screen. A rectangle is a four-sided shape with -* every angle at ninety degrees. By default, the first two parameters set -* the location of the upper-left corner, the third sets the width, and the -* fourth sets the height. The way these parameters are interpreted, however, -* may be changed with the rectMode() function. -* <br><br> -* The fifth, sixth, seventh and eighth parameters, if specified, -* determine corner radius for the top-right, top-left, lower-right and -* lower-left corners, respectively. An omitted corner radius parameter is set -* to the value of the previously specified radius value in the parameter list. -* -* @method rect -* @param {Number} x x-coordinate of the rectangle. -* @param {Number} y y-coordinate of the rectangle. -* @param {Number} w width of the rectangle. -* @param {Number} h height of the rectangle. -* @param {Number} [tl] optional radius of top-left corner. -* @param {Number} [tr] optional radius of top-right corner. -* @param {Number} [br] optional radius of bottom-right corner. -* @param {Number} [bl] optional radius of bottom-left corner. -* @return {p5} the p5 object. -* @example -* <div> -* <code> -* // Draw a rectangle at location (30, 20) with a width and height of 55. -* rect(30, 20, 55, 55); -* </code> -* </div> -* -* <div> -* <code> -* // Draw a rectangle with rounded corners, each having a radius of 20. -* rect(30, 20, 55, 55, 20); -* </code> -* </div> -* -* <div> -* <code> -* // Draw a rectangle with rounded corners having the following radii: -* // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5. -* rect(30, 20, 55, 55, 20, 15, 10, 5) -* </code> -* </div> -*/ -p5.prototype.rect = function (x, y, w, h, tl, tr, br, bl) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'rect', - args, - [ - ['Number', 'Number', 'Number', 'Number'], - ['Number', 'Number', 'Number', 'Number', 'Number'], - ['Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', 'Number'] - ] - ); - - if (!this._renderer._doStroke && !this._renderer._doFill) { - return; - } - this._renderer.rect(x, y, w, h, tl, tr, br, bl); - return this; -}; - -/** -* A triangle is a plane created by connecting three points. The first two -* arguments specify the first point, the middle two arguments specify the -* second point, and the last two arguments specify the third point. -* -* @method triangle -* @param {Number} x1 x-coordinate of the first point -* @param {Number} y1 y-coordinate of the first point -* @param {Number} x2 x-coordinate of the second point -* @param {Number} y2 y-coordinate of the second point -* @param {Number} x3 x-coordinate of the third point -* @param {Number} y3 y-coordinate of the third point -* @return {p5} the p5 object -* @example -* <div> -* <code> -* triangle(30, 75, 58, 20, 86, 75); -* </code> -* </div> -*/ -p5.prototype.triangle = function() { - - if (!this._renderer._doStroke && !this._renderer._doFill) { - return this; - } - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - if(this._renderer.isP3D){ - this._validateParameters( - 'triangle', - args, - [ - ['Number', 'Number', 'Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number'] - ] - ); - this._renderer.triangle( - args[0], - args[1], - args[2], - args[3], - args[4], - args[5], - args[6], - args[7], - args[8] - ); - } else { - this._validateParameters( - 'triangle', - args, - [ - ['Number', 'Number', 'Number', 'Number', 'Number', 'Number'] - ] - ); - this._renderer.triangle( - args[0], - args[1], - args[2], - args[3], - args[4], - args[5] - ); - } - return this; -}; - -module.exports = p5; - -},{"./constants":47,"./core":48,"./error_helpers":51}],45:[function(_dereq_,module,exports){ -/** - * @module Shape - * @submodule Attributes - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('./core'); -var constants = _dereq_('./constants'); - -/** - * Modifies the location from which ellipses are drawn by changing the way - * in which parameters given to ellipse() are interpreted. - * <br><br> - * The default mode is ellipseMode(CENTER), which interprets the first two - * parameters of ellipse() as the shape's center point, while the third and - * fourth parameters are its width and height. - * <br><br> - * ellipseMode(RADIUS) also uses the first two parameters of ellipse() as - * the shape's center point, but uses the third and fourth parameters to - * specify half of the shapes's width and height. - * <br><br> - * ellipseMode(CORNER) interprets the first two parameters of ellipse() as - * the upper-left corner of the shape, while the third and fourth parameters - * are its width and height. - * <br><br> - * ellipseMode(CORNERS) interprets the first two parameters of ellipse() as - * the location of one corner of the ellipse's bounding box, and the third - * and fourth parameters as the location of the opposite corner. - * <br><br> - * The parameter must be written in ALL CAPS because Javascript is a - * case-sensitive language. - * - * @method ellipseMode - * @param {Number/Constant} mode either CENTER, RADIUS, CORNER, or CORNERS - * @return {p5} the p5 object - * @example - * <div> - * <code> - * ellipseMode(RADIUS); // Set ellipseMode to RADIUS - * fill(255); // Set fill to white - * ellipse(50, 50, 30, 30); // Draw white ellipse using RADIUS mode - * - * ellipseMode(CENTER); // Set ellipseMode to CENTER - * fill(100); // Set fill to gray - * ellipse(50, 50, 30, 30); // Draw gray ellipse using CENTER mode - * </code> - * </div> - * - * <div> - * <code> - * ellipseMode(CORNER); // Set ellipseMode is CORNER - * fill(255); // Set fill to white - * ellipse(25, 25, 50, 50); // Draw white ellipse using CORNER mode - * - * ellipseMode(CORNERS); // Set ellipseMode to CORNERS - * fill(100); // Set fill to gray - * ellipse(25, 25, 50, 50); // Draw gray ellipse using CORNERS mode - * </code> - * </div> - */ -p5.prototype.ellipseMode = function(m) { - if (m === constants.CORNER || - m === constants.CORNERS || - m === constants.RADIUS || - m === constants.CENTER) { - this._renderer._ellipseMode = m; - } - return this; -}; - -/** - * Draws all geometry with jagged (aliased) edges. Note that smooth() is - * active by default, so it is necessary to call noSmooth() to disable - * smoothing of geometry, images, and fonts. - * - * @method noSmooth - * @return {p5} the p5 object - * @example - * <div> - * <code> - * background(0); - * noStroke(); - * smooth(); - * ellipse(30, 48, 36, 36); - * noSmooth(); - * ellipse(70, 48, 36, 36); - * </code> - * </div> - */ -p5.prototype.noSmooth = function() { - this._renderer.noSmooth(); - return this; -}; - -/** - * Modifies the location from which rectangles are drawn by changing the way - * in which parameters given to rect() are interpreted. - * <br><br> - * The default mode is rectMode(CORNER), which interprets the first two - * parameters of rect() as the upper-left corner of the shape, while the - * third and fourth parameters are its width and height. - * <br><br> - * rectMode(CORNERS) interprets the first two parameters of rect() as the - * location of one corner, and the third and fourth parameters as the - * location of the opposite corner. - * <br><br> - * rectMode(CENTER) interprets the first two parameters of rect() as the - * shape's center point, while the third and fourth parameters are its - * width and height. - * <br><br> - * rectMode(RADIUS) also uses the first two parameters of rect() as the - * shape's center point, but uses the third and fourth parameters to specify - * half of the shapes's width and height. - * <br><br> - * The parameter must be written in ALL CAPS because Javascript is a - * case-sensitive language. - * - * @method rectMode - * @param {Number/Constant} mode either CORNER, CORNERS, CENTER, or RADIUS - * @return {p5} the p5 object - * @example - * <div> - * <code> - * rectMode(CORNER); // Default rectMode is CORNER - * fill(255); // Set fill to white - * rect(25, 25, 50, 50); // Draw white rect using CORNER mode - * - * rectMode(CORNERS); // Set rectMode to CORNERS - * fill(100); // Set fill to gray - * rect(25, 25, 50, 50); // Draw gray rect using CORNERS mode - * </code> - * </div> - * - * <div> - * <code> - * rectMode(RADIUS); // Set rectMode to RADIUS - * fill(255); // Set fill to white - * rect(50, 50, 30, 30); // Draw white rect using RADIUS mode - * - * rectMode(CENTER); // Set rectMode to CENTER - * fill(100); // Set fill to gray - * rect(50, 50, 30, 30); // Draw gray rect using CENTER mode - * </code> - * </div> - */ -p5.prototype.rectMode = function(m) { - if (m === constants.CORNER || - m === constants.CORNERS || - m === constants.RADIUS || - m === constants.CENTER) { - this._renderer._rectMode = m; - } - return this; -}; - -/** - * Draws all geometry with smooth (anti-aliased) edges. smooth() will also - * improve image quality of resized images. Note that smooth() is active by - * default; noSmooth() can be used to disable smoothing of geometry, - * images, and fonts. - * - * @method smooth - * @return {p5} the p5 object - * @example - * <div> - * <code> - * background(0); - * noStroke(); - * smooth(); - * ellipse(30, 48, 36, 36); - * noSmooth(); - * ellipse(70, 48, 36, 36); - * </code> - * </div> - */ -p5.prototype.smooth = function() { - this._renderer.smooth(); - return this; -}; - -/** - * Sets the style for rendering line endings. These ends are either squared, - * extended, or rounded, each of which specified with the corresponding - * parameters: SQUARE, PROJECT, and ROUND. The default cap is ROUND. - * - * @method strokeCap - * @param {Number/Constant} cap either SQUARE, PROJECT, or ROUND - * @return {p5} the p5 object - * @example - * <div> - * <code> - * strokeWeight(12.0); - * strokeCap(ROUND); - * line(20, 30, 80, 30); - * strokeCap(SQUARE); - * line(20, 50, 80, 50); - * strokeCap(PROJECT); - * line(20, 70, 80, 70); - * </code> - * </div> - */ -p5.prototype.strokeCap = function(cap) { - if (cap === constants.ROUND || - cap === constants.SQUARE || - cap === constants.PROJECT) { - this._renderer.strokeCap(cap); - } - return this; -}; - -/** - * Sets the style of the joints which connect line segments. These joints - * are either mitered, beveled, or rounded and specified with the - * corresponding parameters MITER, BEVEL, and ROUND. The default joint is - * MITER. - * - * @method strokeJoin - * @param {Number/Constant} join either MITER, BEVEL, ROUND - * @return {p5} the p5 object - * @example - * <div> - * <code> - * noFill(); - * strokeWeight(10.0); - * strokeJoin(MITER); - * beginShape(); - * vertex(35, 20); - * vertex(65, 50); - * vertex(35, 80); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * strokeWeight(10.0); - * strokeJoin(BEVEL); - * beginShape(); - * vertex(35, 20); - * vertex(65, 50); - * vertex(35, 80); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * strokeWeight(10.0); - * strokeJoin(ROUND); - * beginShape(); - * vertex(35, 20); - * vertex(65, 50); - * vertex(35, 80); - * endShape(); - * </code> - * </div> - */ -p5.prototype.strokeJoin = function(join) { - if (join === constants.ROUND || - join === constants.BEVEL || - join === constants.MITER) { - this._renderer.strokeJoin(join); - } - return this; -}; - -/** - * Sets the width of the stroke used for lines, points, and the border - * around shapes. All widths are set in units of pixels. - * - * @method strokeWeight - * @param {Number} weight the weight (in pixels) of the stroke - * @return {p5} the p5 object - * @example - * <div> - * <code> - * strokeWeight(1); // Default - * line(20, 20, 80, 20); - * strokeWeight(4); // Thicker - * line(20, 40, 80, 40); - * strokeWeight(10); // Beastly - * line(20, 70, 80, 70); - * </code> - * </div> - */ -p5.prototype.strokeWeight = function(w) { - this._renderer.strokeWeight(w); - return this; -}; - -module.exports = p5; - -},{"./constants":47,"./core":48}],46:[function(_dereq_,module,exports){ -/** - * @requires constants - */ - -var constants = _dereq_('./constants'); - -module.exports = { - - modeAdjust: function(a, b, c, d, mode) { - if (mode === constants.CORNER) { - return { x: a, y: b, w: c, h: d }; - } else if (mode === constants.CORNERS) { - return { x: a, y: b, w: c-a, h: d-b }; - } else if (mode === constants.RADIUS) { - return { x: a-c, y: b-d, w: 2*c, h: 2*d }; - } else if (mode === constants.CENTER) { - return { x: a-c*0.5, y: b-d*0.5, w: c, h: d }; - } - }, - - arcModeAdjust: function(a, b, c, d, mode) { - if (mode === constants.CORNER) { - return { x: a+c*0.5, y: b+d*0.5, w: c, h: d }; - } else if (mode === constants.CORNERS) { - return { x: a, y: b, w: c+a, h: d+b }; - } else if (mode === constants.RADIUS) { - return { x: a, y: b, w: 2*c, h: 2*d }; - } else if (mode === constants.CENTER) { - return { x: a, y: b, w: c, h: d }; - } - } - -}; - - -},{"./constants":47}],47:[function(_dereq_,module,exports){ -/** - * @module Constants - * @submodule Constants - * @for p5 - */ - -var PI = Math.PI; - -module.exports = { - - // GRAPHICS RENDERER - P2D: 'p2d', - WEBGL: 'webgl', - - // ENVIRONMENT - ARROW: 'default', - CROSS: 'crosshair', - HAND: 'pointer', - MOVE: 'move', - TEXT: 'text', - WAIT: 'wait', - - // TRIGONOMETRY - - /** - * HALF_PI is a mathematical constant with the value - * 1.57079632679489661923. It is half the ratio of the - * circumference of a circle to its diameter. It is useful in - * combination with the trigonometric functions sin() and cos(). - * - * @property HALF_PI - * - * @example - * <div><code> - * arc(50, 50, 80, 80, 0, HALF_PI); - * </code></div> - * - */ - HALF_PI: PI / 2, - /** - * PI is a mathematical constant with the value - * 3.14159265358979323846. It is the ratio of the circumference - * of a circle to its diameter. It is useful in combination with - * the trigonometric functions sin() and cos(). - * - * @property PI - * - * @example - * <div><code> - * arc(50, 50, 80, 80, 0, PI); - * </code></div> - */ - PI: PI, - /** - * QUARTER_PI is a mathematical constant with the value 0.7853982. - * It is one quarter the ratio of the circumference of a circle to - * its diameter. It is useful in combination with the trigonometric - * functions sin() and cos(). - * - * @property QUARTER_PI - * - * @example - * <div><code> - * arc(50, 50, 80, 80, 0, QUARTER_PI); - * </code></div> - * - */ - QUARTER_PI: PI / 4, - /** - * TAU is an alias for TWO_PI, a mathematical constant with the - * value 6.28318530717958647693. It is twice the ratio of the - * circumference of a circle to its diameter. It is useful in - * combination with the trigonometric functions sin() and cos(). - * - * @property TAU - * - * @example - * <div><code> - * arc(50, 50, 80, 80, 0, TAU); - * </code></div> - * - */ - TAU: PI * 2, - /** - * TWO_PI is a mathematical constant with the value - * 6.28318530717958647693. It is twice the ratio of the - * circumference of a circle to its diameter. It is useful in - * combination with the trigonometric functions sin() and cos(). - * - * @property TWO_PI - * - * @example - * <div><code> - * arc(50, 50, 80, 80, 0, TWO_PI); - * </code></div> - * - */ - TWO_PI: PI * 2, - DEGREES: 'degrees', - RADIANS: 'radians', - - // SHAPE - CORNER: 'corner', - CORNERS: 'corners', - RADIUS: 'radius', - RIGHT: 'right', - LEFT: 'left', - CENTER: 'center', - TOP: 'top', - BOTTOM: 'bottom', - BASELINE: 'alphabetic', - POINTS: 'points', - LINES: 'lines', - TRIANGLES: 'triangles', - TRIANGLE_FAN: 'triangles_fan', - TRIANGLE_STRIP: 'triangles_strip', - QUADS: 'quads', - QUAD_STRIP: 'quad_strip', - CLOSE: 'close', - OPEN: 'open', - CHORD: 'chord', - PIE: 'pie', - PROJECT: 'square', // PEND: careful this is counterintuitive - SQUARE: 'butt', - ROUND: 'round', - BEVEL: 'bevel', - MITER: 'miter', - - // COLOR - RGB: 'rgb', - HSB: 'hsb', - HSL: 'hsl', - - // DOM EXTENSION - AUTO: 'auto', - - // INPUT - ALT: 18, - BACKSPACE: 8, - CONTROL: 17, - DELETE: 46, - DOWN_ARROW: 40, - ENTER: 13, - ESCAPE: 27, - LEFT_ARROW: 37, - OPTION: 18, - RETURN: 13, - RIGHT_ARROW: 39, - SHIFT: 16, - TAB: 9, - UP_ARROW: 38, - - // RENDERING - BLEND: 'normal', - ADD: 'lighter', - //ADD: 'add', // - //SUBTRACT: 'subtract', // - DARKEST: 'darken', - LIGHTEST: 'lighten', - DIFFERENCE: 'difference', - EXCLUSION: 'exclusion', - MULTIPLY: 'multiply', - SCREEN: 'screen', - REPLACE: 'source-over', - OVERLAY: 'overlay', - HARD_LIGHT: 'hard-light', - SOFT_LIGHT: 'soft-light', - DODGE: 'color-dodge', - BURN: 'color-burn', - - // FILTERS - THRESHOLD: 'threshold', - GRAY: 'gray', - OPAQUE: 'opaque', - INVERT: 'invert', - POSTERIZE: 'posterize', - DILATE: 'dilate', - ERODE: 'erode', - BLUR: 'blur', - - // TYPOGRAPHY - NORMAL: 'normal', - ITALIC: 'italic', - BOLD: 'bold', - - // TYPOGRAPHY-INTERNAL - _DEFAULT_TEXT_FILL: '#000000', - _DEFAULT_LEADMULT: 1.25, - _CTX_MIDDLE: 'middle', - - // VERTICES - LINEAR: 'linear', - QUADRATIC: 'quadratic', - BEZIER: 'bezier', - CURVE: 'curve', - - // DEFAULTS - _DEFAULT_STROKE: '#000000', - _DEFAULT_FILL: '#FFFFFF' - -}; - -},{}],48:[function(_dereq_,module,exports){ -/** - * @module Structure - * @submodule Structure - * @for p5 - * @requires constants - */ - -'use strict'; - -_dereq_('./shim'); - -// Core needs the PVariables object -var constants = _dereq_('./constants'); - -/** - * This is the p5 instance constructor. - * - * A p5 instance holds all the properties and methods related to - * a p5 sketch. It expects an incoming sketch closure and it can also - * take an optional node parameter for attaching the generated p5 canvas - * to a node. The sketch closure takes the newly created p5 instance as - * its sole argument and may optionally set preload(), setup(), and/or - * draw() properties on it for running a sketch. - * - * A p5 sketch can run in "global" or "instance" mode: - * "global" - all properties and methods are attached to the window - * "instance" - all properties and methods are bound to this p5 object - * - * @param {Function} sketch a closure that can set optional preload(), - * setup(), and/or draw() properties on the - * given p5 instance - * @param {HTMLElement|boolean} node element to attach canvas to, if a - * boolean is passed in use it as sync - * @param {boolean} [sync] start synchronously (optional) - * @return {p5} a p5 instance - */ -var p5 = function(sketch, node, sync) { - - if (arguments.length === 2 && typeof node === 'boolean') { - sync = node; - node = undefined; - } - - ////////////////////////////////////////////// - // PUBLIC p5 PROPERTIES AND METHODS - ////////////////////////////////////////////// - - - /** - * Called directly before setup(), the preload() function is used to handle - * asynchronous loading of external files. If a preload function is - * defined, setup() will wait until any load calls within have finished. - * Nothing besides load calls should be inside preload (loadImage, - * loadJSON, loadFont, loadStrings, etc). - * - * @method preload - * @example - * <div><code> - * var img; - * var c; - * function preload() { // preload() runs once - * img = loadImage('assets/laDefense.jpg'); - * } - * - * function setup() { // setup() waits until preload() is done - * img.loadPixels(); - * // get color of middle pixel - * c = img.get(img.width/2, img.height/2); - * } - * - * function draw() { - * background(c); - * image(img, 25, 25, 50, 50); - * } - * </code></div> - */ - - /** - * The setup() function is called once when the program starts. It's used to - * define initial environment properties such as screen size and background - * color and to load media such as images and fonts as the program starts. - * There can only be one setup() function for each program and it shouldn't - * be called again after its initial execution. - * <br><br> - * Note: Variables declared within setup() are not accessible within other - * functions, including draw(). - * - * @method setup - * @example - * <div><code> - * var a = 0; - * - * function setup() { - * background(0); - * noStroke(); - * fill(102); - * } - * - * function draw() { - * rect(a++%width, 10, 2, 80); - * } - * </code></div> - */ - - /** - * Called directly after setup(), the draw() function continuously executes - * the lines of code contained inside its block until the program is stopped - * or noLoop() is called. draw() is called automatically and should never be - * called explicitly. - * <br><br> - * It should always be controlled with noLoop(), redraw() and loop(). After - * noLoop() stops the code in draw() from executing, redraw() causes the - * code inside draw() to execute once, and loop() will cause the code - * inside draw() to resume executing continuously. - * <br><br> - * The number of times draw() executes in each second may be controlled with - * the frameRate() function. - * <br><br> - * There can only be one draw() function for each sketch, and draw() must - * exist if you want the code to run continuously, or to process events such - * as mousePressed(). Sometimes, you might have an empty call to draw() in - * your program, as shown in the above example. - * - * @method draw - * @example - * <div><code> - * var yPos = 0; - * function setup() { // setup() runs once - * frameRate(30); - * } - * function draw() { // draw() loops forever, until stopped - * background(204); - * yPos = yPos - 1; - * if (yPos < 0) { - * yPos = height; - * } - * line(0, yPos, width, yPos); - * } - * </code></div> - */ - - - ////////////////////////////////////////////// - // PRIVATE p5 PROPERTIES AND METHODS - ////////////////////////////////////////////// - - this._setupDone = false; - // for handling hidpi - this._pixelDensity = Math.ceil(window.devicePixelRatio) || 1; - this._userNode = node; - this._curElement = null; - this._elements = []; - this._requestAnimId = 0; - this._preloadCount = 0; - this._isGlobal = false; - this._loop = true; - this._styles = []; - this._defaultCanvasSize = { - width: 100, - height: 100 - }; - this._events = { // keep track of user-events for unregistering later - 'mousemove': null, - 'mousedown': null, - 'mouseup': null, - 'dragend': null, - 'dragover': null, - 'click': null, - 'mouseover': null, - 'mouseout': null, - 'keydown': null, - 'keyup': null, - 'keypress': null, - 'touchstart': null, - 'touchmove': null, - 'touchend': null, - 'resize': null, - 'blur': null - }; - - if (window.DeviceOrientationEvent) { - this._events.deviceorientation = null; - } - if (window.DeviceMotionEvent && !window._isNodeWebkit) { - this._events.devicemotion = null; - } - - this._events.wheel = null; - - - this._loadingScreenId = 'p5_loading'; - - this._start = function () { - // Find node if id given - if (this._userNode) { - if (typeof this._userNode === 'string') { - this._userNode = document.getElementById(this._userNode); - } - } - - // Always create a default canvas. - // Later on if the user calls createCanvas, this default one - // will be replaced - this.createCanvas( - this._defaultCanvasSize.width, - this._defaultCanvasSize.height, - 'p2d', - true - ); - - var userPreload = this.preload || window.preload; // look for "preload" - if (userPreload) { - - // Setup loading screen - // Set loading scfeen into dom if not present - // Otherwise displays and removes user provided loading screen - var loadingScreen = document.getElementById(this._loadingScreenId); - if(!loadingScreen){ - loadingScreen = document.createElement('div'); - loadingScreen.innerHTML = 'Loading...'; - loadingScreen.style.position = 'absolute'; - loadingScreen.id = this._loadingScreenId; - var node = this._userNode || document.body; - node.appendChild(loadingScreen); - } - // var methods = this._preloadMethods; - for (var method in this._preloadMethods){ - // default to p5 if no object defined - this._preloadMethods[method] = this._preloadMethods[method] || p5; - var obj = this._preloadMethods[method]; - //it's p5, check if it's global or instance - if (obj === p5.prototype || obj === p5){ - obj = this._isGlobal ? window : this; - } - this._registeredPreloadMethods[method] = obj[method]; - obj[method] = this._wrapPreload(obj, method); - } - - userPreload(); - this._runIfPreloadsAreDone(); - } else { - this._setup(); - this._runFrames(); - this._draw(); - } - }.bind(this); - - this._runIfPreloadsAreDone = function(){ - var context = this._isGlobal ? window : this; - if (context._preloadCount === 0) { - var loadingScreen = document.getElementById(context._loadingScreenId); - if (loadingScreen) { - loadingScreen.parentNode.removeChild(loadingScreen); - } - context._setup(); - context._runFrames(); - context._draw(); - } - }; - - this._decrementPreload = function(){ - var context = this._isGlobal ? window : this; - context._setProperty('_preloadCount', context._preloadCount - 1); - context._runIfPreloadsAreDone(); - }; - - this._wrapPreload = function(obj, fnName){ - return function(){ - //increment counter - this._incrementPreload(); - //call original function - var args = Array.prototype.slice.call(arguments); - args.push(this._decrementPreload.bind(this)); - return this._registeredPreloadMethods[fnName].apply(obj, args); - }.bind(this); - }; - - this._incrementPreload = function(){ - var context = this._isGlobal ? window : this; - context._setProperty('_preloadCount', context._preloadCount + 1); - }; - - this._setup = function() { - - // return preload functions to their normal vals if switched by preload - var context = this._isGlobal ? window : this; - if (typeof context.preload === 'function') { - for (var f in this._preloadMethods) { - context[f] = this._preloadMethods[f][f]; - if (context[f] && this) { - context[f] = context[f].bind(this); - } - } - } - - // Short-circuit on this, in case someone used the library in "global" - // mode earlier - if (typeof context.setup === 'function') { - context.setup(); - } - - // // unhide hidden canvas that was created - // this.canvas.style.visibility = ''; - // this.canvas.className = this.canvas.className.replace('p5_hidden', ''); - - // unhide any hidden canvases that were created - var reg = new RegExp(/(^|\s)p5_hidden(?!\S)/g); - var canvases = document.getElementsByClassName('p5_hidden'); - for (var i = 0; i < canvases.length; i++) { - var k = canvases[i]; - k.style.visibility = ''; - k.className = k.className.replace(reg, ''); - } - this._setupDone = true; - - }.bind(this); - - this._draw = function () { - var now = window.performance.now(); - var time_since_last = now - this._lastFrameTime; - var target_time_between_frames = 1000 / this._targetFrameRate; - - // only draw if we really need to; don't overextend the browser. - // draw if we're within 5ms of when our next frame should paint - // (this will prevent us from giving up opportunities to draw - // again when it's really about time for us to do so). fixes an - // issue where the frameRate is too low if our refresh loop isn't - // in sync with the browser. note that we have to draw once even - // if looping is off, so we bypass the time delay if that - // is the case. - var epsilon = 5; - if (!this._loop || - time_since_last >= target_time_between_frames - epsilon) { - - //mandatory update values(matrixs and stack) for 3d - if(this._renderer.isP3D){ - this._renderer._update(); - } - - this._setProperty('frameCount', this.frameCount + 1); - this._updateMouseCoords(); - this._updateTouchCoords(); - this.redraw(); - this._frameRate = 1000.0/(now - this._lastFrameTime); - this._lastFrameTime = now; - } - - // get notified the next time the browser gives us - // an opportunity to draw. - if (this._loop) { - this._requestAnimId = window.requestAnimationFrame(this._draw); - } - }.bind(this); - - this._runFrames = function() { - if (this._updateInterval) { - clearInterval(this._updateInterval); - } - }.bind(this); - - this._setProperty = function(prop, value) { - this[prop] = value; - if (this._isGlobal) { - window[prop] = value; - } - }.bind(this); - - /** - * Removes the entire p5 sketch. This will remove the canvas and any - * elements created by p5.js. It will also stop the draw loop and unbind - * any properties or methods from the window global scope. It will - * leave a variable p5 in case you wanted to create a new p5 sketch. - * If you like, you can set p5 = null to erase it. - * @method remove - * @example - * <div class='norender'><code> - * function draw() { - * ellipse(50, 50, 10, 10); - * } - * - * function mousePressed() { - * remove(); // remove whole sketch on mouse press - * } - * </code></div> - */ - this.remove = function() { - if (this._curElement) { - - // stop draw - this._loop = false; - if (this._requestAnimId) { - window.cancelAnimationFrame(this._requestAnimId); - } - - // unregister events sketch-wide - for (var ev in this._events) { - window.removeEventListener(ev, this._events[ev]); - } - - // remove DOM elements created by p5, and listeners - for (var i=0; i<this._elements.length; i++) { - var e = this._elements[i]; - if (e.elt.parentNode) { - e.elt.parentNode.removeChild(e.elt); - } - for (var elt_ev in e._events) { - e.elt.removeEventListener(elt_ev, e._events[elt_ev]); - } - } - - // call any registered remove functions - var self = this; - this._registeredMethods.remove.forEach(function (f) { - if (typeof(f) !== 'undefined') { - f.call(self); - } - }); - - // remove window bound properties and methods - if (this._isGlobal) { - for (var p in p5.prototype) { - try { - delete window[p]; - } catch (x) { - window[p] = undefined; - } - } - for (var p2 in this) { - if (this.hasOwnProperty(p2)) { - try { - delete window[p2]; - } catch (x) { - window[p2] = undefined; - } - } - } - } - } - // window.p5 = undefined; - }.bind(this); - - - // attach constants to p5 instance - for (var k in constants) { - p5.prototype[k] = constants[k]; - } - - // If the user has created a global setup or draw function, - // assume "global" mode and make everything global (i.e. on the window) - if (!sketch) { - this._isGlobal = true; - // Loop through methods on the prototype and attach them to the window - for (var p in p5.prototype) { - if(typeof p5.prototype[p] === 'function') { - var ev = p.substring(2); - if (!this._events.hasOwnProperty(ev)) { - window[p] = p5.prototype[p].bind(this); - } - } else { - window[p] = p5.prototype[p]; - } - } - // Attach its properties to the window - for (var p2 in this) { - if (this.hasOwnProperty(p2)) { - window[p2] = this[p2]; - } - } - - } else { - // Else, the user has passed in a sketch closure that may set - // user-provided 'setup', 'draw', etc. properties on this instance of p5 - sketch(this); - } - - // Bind events to window (not using container div bc key events don't work) - - for (var e in this._events) { - var f = this['_on'+e]; - if (f) { - var m = f.bind(this); - window.addEventListener(e, m); - this._events[e] = m; - } - } - - var focusHandler = function() { - this._setProperty('focused', true); - }.bind(this); - var blurHandler = function() { - this._setProperty('focused', false); - }.bind(this); - window.addEventListener('focus', focusHandler); - window.addEventListener('blur', blurHandler); - this.registerMethod('remove', function() { - window.removeEventListener('focus', focusHandler); - window.removeEventListener('blur', blurHandler); - }); - - // TODO: ??? - - if (sync) { - this._start(); - } else { - if (document.readyState === 'complete') { - this._start(); - } else { - window.addEventListener('load', this._start.bind(this), false); - } - } -}; - - -// functions that cause preload to wait -// more can be added by using registerPreloadMethod(func) -p5.prototype._preloadMethods = { - loadJSON: p5.prototype, - loadImage: p5.prototype, - loadStrings: p5.prototype, - loadXML: p5.prototype, - loadShape: p5.prototype, - loadTable: p5.prototype, - loadFont: p5.prototype -}; - -p5.prototype._registeredMethods = { pre: [], post: [], remove: [] }; - -p5.prototype._registeredPreloadMethods = {}; - -p5.prototype.registerPreloadMethod = function(fnString, obj) { - // obj = obj || p5.prototype; - if (!p5.prototype._preloadMethods.hasOwnProperty(fnString)) { - p5.prototype._preloadMethods[fnString] = obj; - } -}; - -p5.prototype.registerMethod = function(name, m) { - if (!p5.prototype._registeredMethods.hasOwnProperty(name)) { - p5.prototype._registeredMethods[name] = []; - } - p5.prototype._registeredMethods[name].push(m); -}; - -module.exports = p5; - -},{"./constants":47,"./shim":57}],49:[function(_dereq_,module,exports){ -/** - * @module Shape - * @submodule Curves - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('./core'); - -_dereq_('./error_helpers'); - -var bezierDetail = 20; -var curveDetail = 20; - -/** - * Draws a cubic Bezier curve on the screen. These curves are defined by a - * series of anchor and control points. The first two parameters specify - * the first anchor point and the last two parameters specify the other - * anchor point, which become the first and last points on the curve. The - * middle parameters specify the two control points which define the shape - * of the curve. Approximately speaking, control points "pull" the curve - * towards them.<br /><br />Bezier curves were developed by French - * automotive engineer Pierre Bezier, and are commonly used in computer - * graphics to define gently sloping curves. See also curve(). - * - * @method bezier - * @param {Number} x1 x-coordinate for the first anchor point - * @param {Number} y1 y-coordinate for the first anchor point - * @param {Number} x2 x-coordinate for the first control point - * @param {Number} y2 y-coordinate for the first control point - * @param {Number} x3 x-coordinate for the second control point - * @param {Number} y3 y-coordinate for the second control point - * @param {Number} x4 x-coordinate for the second anchor point - * @param {Number} y4 y-coordinate for the second anchor point - * @return {Object} the p5 object - * @example - * <div> - * <code> - * noFill(); - * stroke(255, 102, 0); - * line(85, 20, 10, 10); - * line(90, 90, 15, 80); - * stroke(0, 0, 0); - * bezier(85, 20, 10, 10, 90, 90, 15, 80); - * </code> - * </div> - */ -p5.prototype.bezier = function(x1, y1, x2, y2, x3, y3, x4, y4) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'bezier', - args, - [ 'Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', 'Number' ] - ); - - if (!this._renderer._doStroke) { - return this; - } - this._renderer.bezier(x1, y1, x2, y2, x3, y3, x4, y4); - return this; -}; - -/** - * Sets the resolution at which Beziers display. - * - * The default value is 20. - * - * @param {Number} detail resolution of the curves - * @return {Object} the p5 object - * @example - * <div> - * <code> - * background(204); - * bezierDetail(50); - * bezier(85, 20, 10, 10, 90, 90, 15, 80); - * </code> - * </div> - */ -p5.prototype.bezierDetail = function(d) { - bezierDetail = d; - return this; -}; - -/** - * Evaluates the Bezier at position t for points a, b, c, d. - * The parameters a and d are the first and last points - * on the curve, and b and c are the control points. - * The final parameter t varies between 0 and 1. - * This can be done once with the x coordinates and a second time - * with the y coordinates to get the location of a bezier curve at t. - * - * @method bezierPoint - * @param {Number} a coordinate of first point on the curve - * @param {Number} b coordinate of first control point - * @param {Number} c coordinate of second control point - * @param {Number} d coordinate of second point on the curve - * @param {Number} t value between 0 and 1 - * @return {Number} the value of the Bezier at position t - * @example - * <div> - * <code> - * noFill(); - * x1 = 85, x2 = 10, x3 = 90, x4 = 15; - * y1 = 20, y2 = 10, y3 = 90, y4 = 80; - * bezier(x1, y1, x2, y2, x3, y3, x4, y4); - * fill(255); - * steps = 10; - * for (i = 0; i <= steps; i++) { - * t = i / steps; - * x = bezierPoint(x1, x2, x3, x4, t); - * y = bezierPoint(y1, y2, y3, y4, t); - * ellipse(x, y, 5, 5); - * } - * </code> - * </div> - */ -p5.prototype.bezierPoint = function(a, b, c, d, t) { - var adjustedT = 1-t; - return Math.pow(adjustedT,3)*a + - 3*(Math.pow(adjustedT,2))*t*b + - 3*adjustedT*Math.pow(t,2)*c + - Math.pow(t,3)*d; -}; - -/** - * Evaluates the tangent to the Bezier at position t for points a, b, c, d. - * The parameters a and d are the first and last points - * on the curve, and b and c are the control points. - * The final parameter t varies between 0 and 1. - * - * @method bezierTangent - * @param {Number} a coordinate of first point on the curve - * @param {Number} b coordinate of first control point - * @param {Number} c coordinate of second control point - * @param {Number} d coordinate of second point on the curve - * @param {Number} t value between 0 and 1 - * @return {Number} the tangent at position t - * @example - * <div> - * <code> - * noFill(); - * bezier(85, 20, 10, 10, 90, 90, 15, 80); - * steps = 6; - * fill(255); - * for (i = 0; i <= steps; i++) { - * t = i / steps; - * // Get the location of the point - * x = bezierPoint(85, 10, 90, 15, t); - * y = bezierPoint(20, 10, 90, 80, t); - * // Get the tangent points - * tx = bezierTangent(85, 10, 90, 15, t); - * ty = bezierTangent(20, 10, 90, 80, t); - * // Calculate an angle from the tangent points - * a = atan2(ty, tx); - * a += PI; - * stroke(255, 102, 0); - * line(x, y, cos(a)*30 + x, sin(a)*30 + y); - * // The following line of code makes a line - * // inverse of the above line - * //line(x, y, cos(a)*-30 + x, sin(a)*-30 + y); - * stroke(0); - * ellipse(x, y, 5, 5); - * } - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * bezier(85, 20, 10, 10, 90, 90, 15, 80); - * stroke(255, 102, 0); - * steps = 16; - * for (i = 0; i <= steps; i++) { - * t = i / steps; - * x = bezierPoint(85, 10, 90, 15, t); - * y = bezierPoint(20, 10, 90, 80, t); - * tx = bezierTangent(85, 10, 90, 15, t); - * ty = bezierTangent(20, 10, 90, 80, t); - * a = atan2(ty, tx); - * a -= HALF_PI; - * line(x, y, cos(a)*8 + x, sin(a)*8 + y); - * } - * </code> - * </div> - */ -p5.prototype.bezierTangent = function(a, b, c, d, t) { - var adjustedT = 1-t; - return 3*d*Math.pow(t,2) - - 3*c*Math.pow(t,2) + - 6*c*adjustedT*t - - 6*b*adjustedT*t + - 3*b*Math.pow(adjustedT,2) - - 3*a*Math.pow(adjustedT,2); -}; - -/** - * Draws a curved line on the screen between two points, given as the - * middle four parameters. The first two parameters are a control point, as - * if the curve came from this point even though it's not drawn. The last - * two parameters similarly describe the other control point. <br /><br /> - * Longer curves can be created by putting a series of curve() functions - * together or using curveVertex(). An additional function called - * curveTightness() provides control for the visual quality of the curve. - * The curve() function is an implementation of Catmull-Rom splines. - * - * @method curve - * @param {Number} x1 x-coordinate for the beginning control point - * @param {Number} y1 y-coordinate for the beginning control point - * @param {Number} x2 x-coordinate for the first point - * @param {Number} y2 y-coordinate for the first point - * @param {Number} x3 x-coordinate for the second point - * @param {Number} y3 y-coordinate for the second point - * @param {Number} x4 x-coordinate for the ending control point - * @param {Number} y4 y-coordinate for the ending control point - * @return {Object} the p5 object - * @example - * <div> - * <code> - * noFill(); - * stroke(255, 102, 0); - * curve(5, 26, 5, 26, 73, 24, 73, 61); - * stroke(0); - * curve(5, 26, 73, 24, 73, 61, 15, 65); - * stroke(255, 102, 0); - * curve(73, 24, 73, 61, 15, 65, 15, 65); - * </code> - * </div> - * <div> - * <code> - * // Define the curve points as JavaScript objects - * p1 = {x: 5, y: 26}, p2 = {x: 73, y: 24} - * p3 = {x: 73, y: 61}, p4 = {x: 15, y: 65} - * noFill(); - * stroke(255, 102, 0); - * curve(p1.x, p1.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y) - * stroke(0); - * curve(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y) - * stroke(255, 102, 0); - * curve(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, p4.x, p4.y) - * </code> - * </div> - */ -p5.prototype.curve = function(x1, y1, x2, y2, x3, y3, x4, y4) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'curve', - args, - [ 'Number', 'Number', 'Number', 'Number', - 'Number', 'Number', 'Number', 'Number' ] - ); - - if (!this._renderer._doStroke) { - return; - } - this._renderer.curve(x1, y1, x2, y2, x3, y3, x4, y4); - return this; -}; - -/** - * Sets the resolution at which curves display. - * - * The default value is 20. - * - * @param {Number} resolution of the curves - * @return {Object} the p5 object - * @example - * <div> - * <code> - * background(204); - * curveDetail(20); - * curve(5, 26, 5, 26, 73, 24, 73, 61); - * </code> - * </div> - */ -p5.prototype.curveDetail = function(d) { - curveDetail = d; - return this; -}; - -/** - * Modifies the quality of forms created with curve() and curveVertex(). - * The parameter tightness determines how the curve fits to the vertex - * points. The value 0.0 is the default value for tightness (this value - * defines the curves to be Catmull-Rom splines) and the value 1.0 connects - * all the points with straight lines. Values within the range -5.0 and 5.0 - * will deform the curves but will leave them recognizable and as values - * increase in magnitude, they will continue to deform. - * - * @method curveTightness - * @param {Number} amount of deformation from the original vertices - * @return {Object} the p5 object - * @example - * <div> - * <code> - * // Move the mouse left and right to see the curve change - * - * function setup() { - * createCanvas(100, 100); - * noFill(); - * } - * - * function draw() { - * background(204); - * var t = map(mouseX, 0, width, -5, 5); - * curveTightness(t); - * beginShape(); - * curveVertex(10, 26); - * curveVertex(10, 26); - * curveVertex(83, 24); - * curveVertex(83, 61); - * curveVertex(25, 65); - * curveVertex(25, 65); - * endShape(); - * } - * </code> - * </div> - */ -p5.prototype.curveTightness = function (t) { - this._renderer._curveTightness = t; -}; - -/** - * Evaluates the curve at position t for points a, b, c, d. - * The parameter t varies between 0 and 1, a and d are points - * on the curve, and b and c are the control points. - * This can be done once with the x coordinates and a second time - * with the y coordinates to get the location of a curve at t. - * - * @method curvePoint - * @param {Number} a coordinate of first point on the curve - * @param {Number} b coordinate of first control point - * @param {Number} c coordinate of second control point - * @param {Number} d coordinate of second point on the curve - * @param {Number} t value between 0 and 1 - * @return {Number} bezier value at position t - * @example - * <div> - * <code> - * noFill(); - * curve(5, 26, 5, 26, 73, 24, 73, 61); - * curve(5, 26, 73, 24, 73, 61, 15, 65); - * fill(255); - * ellipseMode(CENTER); - * steps = 6; - * for (i = 0; i <= steps; i++) { - * t = i / steps; - * x = curvePoint(5, 5, 73, 73, t); - * y = curvePoint(26, 26, 24, 61, t); - * ellipse(x, y, 5, 5); - * x = curvePoint(5, 73, 73, 15, t); - * y = curvePoint(26, 24, 61, 65, t); - * ellipse(x, y, 5, 5); - * } - * </code> - * </div> - */ -p5.prototype.curvePoint = function(a, b, c, d, t) { - var t3 = t*t*t, - t2 = t*t, - f1 = -0.5 * t3 + t2 - 0.5 * t, - f2 = 1.5 * t3 - 2.5 * t2 + 1.0, - f3 = -1.5 * t3 + 2.0 * t2 + 0.5 * t, - f4 = 0.5 * t3 - 0.5 * t2; - return a*f1 + b*f2 + c*f3 + d*f4; -}; - -/** - * Evaluates the tangent to the curve at position t for points a, b, c, d. - * The parameter t varies between 0 and 1, a and d are points on the curve, - * and b and c are the control points. - * - * @method curveTangent - * @param {Number} a coordinate of first point on the curve - * @param {Number} b coordinate of first control point - * @param {Number} c coordinate of second control point - * @param {Number} d coordinate of second point on the curve - * @param {Number} t value between 0 and 1 - * @return {Number} the tangent at position t - * @example - * <div> - * <code> - * noFill(); - * curve(5, 26, 73, 24, 73, 61, 15, 65); - * steps = 6; - * for (i = 0; i <= steps; i++) { - * t = i / steps; - * x = curvePoint(5, 73, 73, 15, t); - * y = curvePoint(26, 24, 61, 65, t); - * //ellipse(x, y, 5, 5); - * tx = curveTangent(5, 73, 73, 15, t); - * ty = curveTangent(26, 24, 61, 65, t); - * a = atan2(ty, tx); - * a -= PI/2.0; - * line(x, y, cos(a)*8 + x, sin(a)*8 + y); - * } - * </code> - * </div> - */ -p5.prototype.curveTangent = function(a, b,c, d, t) { - var t2 = t*t, - f1 = (-3*t2)/2 + 2*t - 0.5, - f2 = (9*t2)/2 - 5*t, - f3 = (-9*t2)/2 + 4*t + 0.5, - f4 = (3*t2)/2 - t; - return a*f1 + b*f2 + c*f3 + d*f4; -}; - -module.exports = p5; - -},{"./core":48,"./error_helpers":51}],50:[function(_dereq_,module,exports){ -/** - * @module Environment - * @submodule Environment - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('./core'); -var C = _dereq_('./constants'); - -var standardCursors = [C.ARROW, C.CROSS, C.HAND, C.MOVE, C.TEXT, C.WAIT]; - -p5.prototype._frameRate = 0; -p5.prototype._lastFrameTime = window.performance.now(); -p5.prototype._targetFrameRate = 60; - - -if (window.console && console.log) { - /** - * The print() function writes to the console area of your browser. - * This function is often helpful for looking at the data a program is - * producing. This function creates a new line of text for each call to - * the function. Individual elements can be - * separated with quotes ("") and joined with the addition operator (+). - * <br><br> - * While print() is similar to console.log(), it does not directly map to - * it in order to simulate easier to understand behavior than - * console.log(). Due to this, it is slower. For fastest results, use - * console.log(). - * - * @method print - * @param {Any} contents any combination of Number, String, Object, Boolean, - * Array to print - * @example - * <div><code class='norender'> - * var x = 10; - * print("The value of x is " + x); - * // prints "The value of x is 10" - * </code></div> - */ - // Converts passed args into a string and then parses that string to - // simulate synchronous behavior. This is a hack and is gross. - // Since this will not work on all objects, particularly circular - // structures, simply console.log() on error. - p5.prototype.print = function(args) { - try { - var newArgs = JSON.parse(JSON.stringify(args)); - console.log(newArgs); - } catch(err) { - console.log(args); - } - }; -} else { - p5.prototype.print = function() {}; -} - -p5.prototype.println = p5.prototype.print; - -/** - * The system variable frameCount contains the number of frames that have - * been displayed since the program started. Inside setup() the value is 0, - * after the first iteration of draw it is 1, etc. - * - * @property frameCount - * @example - * <div><code> - * function setup() { - * frameRate(30); - * textSize(20); - * textSize(30); - * textAlign(CENTER); - * } - * - * function draw() { - * background(200); - * text(frameCount, width/2, height/2); - * } - * </code></div> - */ -p5.prototype.frameCount = 0; - -/** - * Confirms if the window a p5.js program is in is "focused," meaning that - * the sketch will accept mouse or keyboard input. This variable is - * "true" if the window is focused and "false" if not. - * - * @property focused - * @example - * <div><code> - * // To demonstrate, put two windows side by side. - * // Click on the window that the p5 sketch isn't in! - * function draw() { - * if (focused) { // or "if (focused === true)" - * noStroke(); - * fill(0, 200, 0); - * ellipse(25, 25, 50, 50); - * } else { - * stroke(200,0,0); - * line(0, 0, 100, 100); - * line(100, 0, 0, 100); - * } - * } - * - * </code></div> - */ -p5.prototype.focused = (document.hasFocus()); - -/** - * Sets the cursor to a predefined symbol or an image, or makes it visible - * if already hidden. If you are trying to set an image as the cursor, the - * recommended size is 16x16 or 32x32 pixels. It is not possible to load an - * image as the cursor if you are exporting your program for the Web, and not - * all MODES work with all browsers. The values for parameters x and y must - * be less than the dimensions of the image. - * - * @method cursor - * @param {Number/Constant} type either ARROW, CROSS, HAND, MOVE, TEXT, or - * WAIT, or path for image - * @param {Number} [x] the horizontal active spot of the cursor - * @param {Number} [y] the vertical active spot of the cursor - * @example - * <div><code> - * // Move the mouse left and right across the image - * // to see the cursor change from a cross to a hand - * function draw() { - * line(width/2, 0, width/2, height); - * if (mouseX < 50) { - * cursor(CROSS); - * } else { - * cursor(HAND); - * } - * } - * </code></div> - */ -p5.prototype.cursor = function(type, x, y) { - var cursor = 'auto'; - var canvas = this._curElement.elt; - if (standardCursors.indexOf(type) > -1) { - // Standard css cursor - cursor = type; - } else if (typeof type === 'string') { - var coords = ''; - if (x && y && (typeof x === 'number' && typeof y === 'number')) { - // Note that x and y values must be unit-less positive integers < 32 - // https://developer.mozilla.org/en-US/docs/Web/CSS/cursor - coords = x + ' ' + y; - } - if (type.substring(0, 6) !== 'http://') { - // Image (absolute url) - cursor = 'url(' + type + ') ' + coords + ', auto'; - } else if (/\.(cur|jpg|jpeg|gif|png|CUR|JPG|JPEG|GIF|PNG)$/.test(type)) { - // Image file (relative path) - Separated for performance reasons - cursor = 'url(' + type + ') ' + coords + ', auto'; - } else { - // Any valid string for the css cursor property - cursor = type; - } - } - canvas.style.cursor = cursor; -}; - -/** - * Specifies the number of frames to be displayed every second. For example, - * the function call frameRate(30) will attempt to refresh 30 times a second. - * If the processor is not fast enough to maintain the specified rate, the - * frame rate will not be achieved. Setting the frame rate within setup() is - * recommended. The default rate is 60 frames per second. This is the same as - * setFrameRate(val). - * <br><br> - * Calling frameRate() with no arguments returns the current framerate. This - * is the same as getFrameRate(). - * <br><br> - * Calling frameRate() with arguments that are not of the type numbers - * or are non positive also returns current framerate. - * - * @method frameRate - * @param {Number} [fps] number of frames to be displayed every second - * @return {Number} current frameRate - * @example - * - * <div><code> - * var rectX = 0; - * var fr = 30; //starting FPS - * var clr; - * - * function setup() { - * background(200); - * frameRate(fr); // Attempt to refresh at starting FPS - * clr = color(255,0,0); - * } - * - * function draw() { - * background(200); - * rectX = rectX += 1; // Move Rectangle - * - * if (rectX >= width) { // If you go off screen. - * if (fr == 30) { - * clr = color(0,0,255); - * fr = 10; - * frameRate(fr); // make frameRate 10 FPS - * } else { - * clr = color(255,0,0); - * fr = 30; - * frameRate(fr); // make frameRate 30 FPS - * } - * rectX = 0; - * } - * fill(clr); - * rect(rectX, 40, 20,20); - * } - * </div></code> - * - */ -p5.prototype.frameRate = function(fps) { - if (typeof fps !== 'number' || fps <= 0) { - return this._frameRate; - } else { - this._setProperty('_targetFrameRate', fps); - this._runFrames(); - return this; - } -}; -/** - * Returns the current framerate. - * - * @return {Number} current frameRate - */ -p5.prototype.getFrameRate = function() { - return this.frameRate(); -}; - -/** - * Specifies the number of frames to be displayed every second. For example, - * the function call frameRate(30) will attempt to refresh 30 times a second. - * If the processor is not fast enough to maintain the specified rate, the - * frame rate will not be achieved. Setting the frame rate within setup() is - * recommended. The default rate is 60 frames per second. - * - * Calling frameRate() with no arguments returns the current framerate. - * - * @param {Number} [fps] number of frames to be displayed every second - */ -p5.prototype.setFrameRate = function(fps) { - return this.frameRate(fps); -}; - -/** - * Hides the cursor from view. - * - * @method noCursor - * @example - * <div><code> - * function setup() { - * noCursor(); - * } - * - * function draw() { - * background(200); - * ellipse(mouseX, mouseY, 10, 10); - * } - * </code></div> - */ -p5.prototype.noCursor = function() { - this._curElement.elt.style.cursor = 'none'; -}; - - -/** - * System variable that stores the width of the entire screen display. This - * is used to run a full-screen program on any display size. - * - * @property displayWidth - * @example - * <div class="norender"><code> - * createCanvas(displayWidth, displayHeight); - * </code></div> - */ -p5.prototype.displayWidth = screen.width; - -/** - * System variable that stores the height of the entire screen display. This - * is used to run a full-screen program on any display size. - * - * @property displayHeight - * @example - * <div class="norender"><code> - * createCanvas(displayWidth, displayHeight); - * </code></div> - */ -p5.prototype.displayHeight = screen.height; - -/** - * System variable that stores the width of the inner window, it maps to - * window.innerWidth. - * - * @property windowWidth - * @example - * <div class="norender"><code> - * createCanvas(windowWidth, windowHeight); - * </code></div> - */ -p5.prototype.windowWidth = window.innerWidth; -/** - * System variable that stores the height of the inner window, it maps to - * window.innerHeight. - * - * @property windowHeight - * @example - * <div class="norender"><code> - * createCanvas(windowWidth, windowHeight); - * </code></div> - */ -p5.prototype.windowHeight = window.innerHeight; - -/** - * The windowResized() function is called once every time the browser window - * is resized. This is a good place to resize the canvas or do any other - * adjustements to accomodate the new window size. - * - * @method windowResized - * @example - * <div class="norender"><code> - * function setup() { - * createCanvas(windowWidth, windowHeight); - * } - * - * function draw() { - * background(0, 100, 200); - * } - * - * function windowResized() { - * resizeCanvas(windowWidth, windowHeight); - * } - * </code></div> - */ -p5.prototype._onresize = function(e){ - this._setProperty('windowWidth', window.innerWidth); - this._setProperty('windowHeight', window.innerHeight); - var context = this._isGlobal ? window : this; - var executeDefault; - if (typeof context.windowResized === 'function') { - executeDefault = context.windowResized(e); - if (executeDefault !== undefined && !executeDefault) { - e.preventDefault(); - } - } -}; - -/** - * System variable that stores the width of the drawing canvas. This value - * is set by the first parameter of the createCanvas() function. - * For example, the function call createCanvas(320, 240) sets the width - * variable to the value 320. The value of width defaults to 100 if - * createCanvas() is not used in a program. - * - * @property width - */ -p5.prototype.width = 0; - -/** - * System variable that stores the height of the drawing canvas. This value - * is set by the second parameter of the createCanvas() function. For - * example, the function call createCanvas(320, 240) sets the height - * variable to the value 240. The value of height defaults to 100 if - * createCanvas() is not used in a program. - * - * @property height - */ -p5.prototype.height = 0; - -/** - * If argument is given, sets the sketch to fullscreen or not based on the - * value of the argument. If no argument is given, returns the current - * fullscreen state. Note that due to browser restrictions this can only - * be called on user input, for example, on mouse press like the example - * below. - * - * @method fullscreen - * @param {Boolean} [val] whether the sketch should be in fullscreen mode - * or not - * @return {Boolean} current fullscreen state - * @example - * <div> - * <code> - * // Clicking in the box toggles fullscreen on and off. - * function setup() { - * background(200); - * } - * function mousePressed() { - * if (mouseX > 0 && mouseX < 100 && mouseY > 0 && mouseY < 100) { - * var fs = fullscreen(); - * fullscreen(!fs); - * } - * } - * </code> - * </div> - */ -p5.prototype.fullscreen = function(val) { - // no arguments, return fullscreen or not - if (typeof val === 'undefined') { - return document.fullscreenElement || - document.webkitFullscreenElement || - document.mozFullScreenElement || - document.msFullscreenElement; - } else { // otherwise set to fullscreen or not - if (val) { - launchFullscreen(document.documentElement); - } else { - exitFullscreen(); - } - } -}; - -/** - * Sets the pixel scaling for high pixel density displays. By default - * pixel density is set to match display density, call pixelDensity(1) - * to turn this off. Calling pixelDensity() with no arguments returns - * the current pixel density of the sketch. - * - * - * @method pixelDensity - * @param {Number} [val] whether or how much the sketch should scale - * @returns {Number} current pixel density of the sketch - * @example - * <div> - * <code> - * function setup() { - * pixelDensity(1); - * createCanvas(100, 100); - * background(200); - * ellipse(width/2, height/2, 50, 50); - * } - * </code> - * </div> - * <div> - * <code> - * function setup() { - * pixelDensity(3.0); - * createCanvas(100, 100); - * background(200); - * ellipse(width/2, height/2, 50, 50); - * } - * </code> - * </div> - */ -p5.prototype.pixelDensity = function(val) { - if (typeof val === 'number') { - this._pixelDensity = val; - } else { - return this._pixelDensity; - } - this.resizeCanvas(this.width, this.height, true); -}; - -/** - * Returns the pixel density of the current display the sketch is running on. - * - * @method displayDensity - * @returns {Number} current pixel density of the display - * @example - * <div> - * <code> - * function setup() { - * var density = displayDensity(); - * pixelDensity(density); - * createCanvas(100, 100); - * background(200); - * ellipse(width/2, height/2, 50, 50); - * } - * </code> - * </div> - */ -p5.prototype.displayDensity = function() { - return window.devicePixelRatio; -}; - -function launchFullscreen(element) { - var enabled = document.fullscreenEnabled || - document.webkitFullscreenEnabled || - document.mozFullScreenEnabled || - document.msFullscreenEnabled; - if (!enabled) { - throw new Error('Fullscreen not enabled in this browser.'); - } - if(element.requestFullscreen) { - element.requestFullscreen(); - } else if(element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if(element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else if(element.msRequestFullscreen) { - element.msRequestFullscreen(); - } -} - -function exitFullscreen() { - if(document.exitFullscreen) { - document.exitFullscreen(); - } else if(document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if(document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } -} - - -/** - * Gets the current URL. - * @method getURL - * @return {String} url - * @example - * <div> - * <code> - * var url; - * var x = 100; - * - * function setup() { - * fill(0); - * noStroke(); - * url = getURL(); - * } - * - * function draw() { - * background(200); - * text(url, x, height/2); - * x--; - * } - * </code> - * </div> - */ -p5.prototype.getURL = function() { - return location.href; -}; -/** - * Gets the current URL path as an array. - * @method getURLPath - * @return {Array} path components - * @example - * <div class='norender'><code> - * function setup() { - * var urlPath = getURLPath(); - * for (var i=0; i<urlPath.length; i++) { - * text(urlPath[i], 10, i*20+20); - * } - * } - * </code></div> - */ -p5.prototype.getURLPath = function() { - return location.pathname.split('/').filter(function(v){return v!=='';}); -}; -/** - * Gets the current URL params as an Object. - * @method getURLParams - * @return {Object} URL params - * @example - * <div class='norender'> - * <code> - * // Example: http://p5js.org?year=2014&month=May&day=15 - * - * function setup() { - * var params = getURLParams(); - * text(params.day, 10, 20); - * text(params.month, 10, 40); - * text(params.year, 10, 60); - * } - * </code> - * </div> - */ -p5.prototype.getURLParams = function() { - var re = /[?&]([^&=]+)(?:[&=])([^&=]+)/gim; - var m; - var v={}; - while ((m = re.exec(location.search)) != null) { - if (m.index === re.lastIndex) { - re.lastIndex++; - } - v[m[1]]=m[2]; - } - return v; -}; - -module.exports = p5; - -},{"./constants":47,"./core":48}],51:[function(_dereq_,module,exports){ -/** - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('./core'); -var doFriendlyWelcome = false; // TEMP until we get it all working LM - -// -- Borrowed from jQuery 1.11.3 -- -var class2type = {}; -var toString = class2type.toString; -var names = ['Boolean', 'Number', 'String', 'Function', - 'Array', 'Date', 'RegExp', 'Object', 'Error']; -for (var n=0; n<names.length; n++) { - class2type[ '[object ' + names[n] + ']' ] = names[n].toLowerCase(); -} -var getType = function( obj ) { - if ( obj == null ) { - return obj + ''; - } - return typeof obj === 'object' || typeof obj === 'function' ? - class2type[ toString.call(obj) ] || 'object' : - typeof obj; -}; -var isArray = Array.isArray || function( obj ) { - return getType(obj) === 'array'; -}; -var isNumeric =function( obj ) { - // parseFloat NaNs numeric-cast false positives (null|true|false|"") - // ...but misinterprets leading-number strings, particularly hex literals - // subtraction forces infinities to NaN - // adding 1 corrects loss of precision from parseFloat (#15100) - return !isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0; -}; -// -- End borrow -- - -/** - * Checks the definition type against the argument type - * If any of these passes (in order), it matches: - * - * - p5.* definitions are checked with instanceof - * - Booleans are let through (everything is truthy or falsey) - * - Lowercase of the definition is checked against the js type - * - Number types are checked to see if they are numerically castable - */ -var numberTypes = ['Number', 'Integer', 'Number/Constant']; -function typeMatches(defType, argType, arg) { - if(defType.match(/^p5\./)) { - var parts = defType.split('.'); - return arg instanceof p5[parts[1]]; - } - return defType === 'Boolean' || // Anything is truthy, cover in Debug Guide - (defType.toLowerCase() === argType) || - (numberTypes.indexOf(defType) > -1 && isNumeric(arg)); -} - -/** - * Prints out a fancy, colorful message to the console log - * - * @param {String} message the words to be said - * @param {String} func the name of the function to link - * @param {Integer/Color String} color CSS color string or error type - * - * @return console logs - */ -// Wrong number of params, undefined param, wrong type -var PARAM_COUNT = 0; -var EMPTY_VAR = 1; -var WRONG_TYPE = 2; -var FILE_LOAD = 3; -// p5.js blue, p5.js orange, auto dark green; fallback p5.js darkened magenta -// See testColors below for all the color codes and names -var typeColors = ['#2D7BB6', '#EE9900', '#4DB200', '#C83C00']; -function report(message, func, color) { - if(doFriendlyWelcome){ - friendlyWelcome(); - doFriendlyWelcome =false; - } - if ('undefined' === getType(color)) { - color = '#B40033'; // dark magenta - } else if (getType(color) === 'number') { // Type to color - color = typeColors[color]; - } - // LM TEMP commenting this out until we get the whole system working - // if (func.substring(0,4) === 'load'){ - // console.log( - // '%c> p5.js says: '+message+'%c'+ - // '[https://github.com/processing/p5.js/wiki/Local-server]', - // 'background-color:' + color + ';color:#FFF;', - // 'background-color:transparent;color:' + color +';', - // 'background-color:' + color + ';color:#FFF;', - // 'background-color:transparent;color:' + color +';' - // ); - // } - // else{ - // console.log( - // '%c> p5.js says: '+message+'%c [http://p5js.org/reference/#p5/'+func+ - // ']', 'background-color:' + color + ';color:#FFF;', - // 'background-color:transparent;color:' + color +';' - // ); - // } -} - -/** - * Validate all the parameters of a function for number and type - * NOTE THIS FUNCTION IS TEMPORARILY DISABLED UNTIL FURTHER WORK - * AND UPDATES ARE IMPLEMENTED. -LMCCART - * - * @param {String} func name of function we're checking - * @param {Array} args pass of the JS default arguments array - * @param {Array} types List of types accepted ['Number', 'String, ...] OR - * a list of lists for each format: [ - * ['String', 'Number', 'Number'], - * ['String', 'Number', 'Number', 'Number', 'Number' - * ] - * - * @return console logs - */ -p5.prototype._validateParameters = function(func, args, types) { - if (!isArray(types[0])) { - types = [types]; - } - // Check number of parameters - // Example: "You wrote ellipse(X,X,X). ellipse was expecting 4 - // parameters. Try ellipse(X,X,X,X)." - var diff = Math.abs(args.length-types[0].length); - var message, tindex = 0; - for (var i=1, len=types.length; i<len; i++) { - var d = Math.abs(args.length-types[i].length); - if (d <= diff) { - tindex = i; - diff = d; - } - } - var symbol = 'X'; // Parameter placeholder - if(diff > 0) { - message = 'You wrote ' + func + '('; - // Concat an appropriate number of placeholders for call - if (args.length > 0) { - message += symbol + Array(args.length).join(',' + symbol); - } - message += '). ' + func + ' was expecting ' + types[tindex].length + - ' parameters. Try ' + func + '('; - // Concat an appropriate number of placeholders for definition - if (types[tindex].length > 0) { - message += symbol + Array(types[tindex].length).join(',' + symbol); - } - message += ').'; - // If multiple definitions - if (types.length > 1) { - message += ' ' + func + ' takes different numbers of parameters ' + - 'depending on what you want to do. Click this link to learn more: '; - } - report(message, func, PARAM_COUNT); - } - // Type checking - // Example: "It looks like ellipse received an empty variable in spot #2." - // Example: "ellipse was expecting a number for parameter #1, - // received "foo" instead." - for (var format=0; format<types.length; format++) { - for (var p=0; p < types[format].length && p < args.length; p++) { - var defType = types[format][p]; - var argType = getType(args[p]); - if ('undefined' === argType || null === argType) { - report('It looks like ' + func + - ' received an empty variable in spot #' + (p+1) + - '. If not intentional, this is often a problem with scope: ' + - '[link to scope].', func, EMPTY_VAR); - } else if (defType !== '*' && !typeMatches(defType, argType, args[p])) { - message = func + ' was expecting a ' + defType.toLowerCase() + - ' for parameter #' + (p+1) + ', received '; - // Wrap strings in quotes - message += 'string' === argType ? '"' + args[p] + '"' : args[p]; - message += ' instead.'; - // If multiple definitions - if (types.length > 1) { - message += ' ' + func + ' takes different numbers of parameters ' + - 'depending on what you want to do. ' + - 'Click this link to learn more:'; - } - report(message, func, WRONG_TYPE); - } - } - } -}; -/* - * NOTE THIS FUNCTION IS TEMPORARILY DISABLED UNTIL FURTHER WORK - * AND UPDATES ARE IMPLEMENTED. -LMCCART - */ -p5.prototype._validateParameters = function() { - return true; -}; - -var errorCases = { - '0': { - fileType: 'image', - method: 'loadImage', - message: ' hosting the image online,' - }, - '1': { - fileType: 'XML file', - method: 'loadXML' - }, - '2': { - fileType: 'table file', - method: 'loadTable' - }, - '3': { - fileType: 'text file', - method: 'loadStrings' - } -}; -p5._friendlyFileLoadError = function (errorType, filePath) { - var errorInfo = errorCases[ errorType ]; - var message = 'It looks like there was a problem' + - ' loading your ' + errorInfo.fileType + '.' + - ' Try checking if the file path%c [' + filePath + '] %cis correct,' + - (errorInfo.message || '') + ' or running a local server.'; - report(message, errorInfo.method, FILE_LOAD); -}; - -function friendlyWelcome() { - // p5.js brand - magenta: #ED225D - var astrixBgColor = 'transparent'; - var astrixTxtColor = '#ED225D'; - var welcomeBgColor = '#ED225D'; - var welcomeTextColor = 'white'; - console.log( - '%c _ \n'+ - ' /\\| |/\\ \n'+ - ' \\ ` \' / \n'+ - ' / , . \\ \n'+ - ' \\/|_|\\/ '+ - '\n\n%c> p5.js says: Welcome! '+ - 'This is your friendly debugger. ' + - 'To turn me off switch to using “p5.min.js”.', - 'background-color:'+astrixBgColor+';color:' + astrixTxtColor +';', - 'background-color:'+welcomeBgColor+';color:' + welcomeTextColor +';' - ); -} - -/** - * Prints out all the colors in the color pallete with white text. - * For color blindness testing. - */ -/* function testColors() { - var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer'; - report(str, 'println', '#ED225D'); // p5.js magenta - report(str, 'println', '#2D7BB6'); // p5.js blue - report(str, 'println', '#EE9900'); // p5.js orange - report(str, 'println', '#A67F59'); // p5.js light brown - report(str, 'println', '#704F21'); // p5.js gold - report(str, 'println', '#1CC581'); // auto cyan - report(str, 'println', '#FF6625'); // auto orange - report(str, 'println', '#79EB22'); // auto green - report(str, 'println', '#B40033'); // p5.js darkened magenta - report(str, 'println', '#084B7F'); // p5.js darkened blue - report(str, 'println', '#945F00'); // p5.js darkened orange - report(str, 'println', '#6B441D'); // p5.js darkened brown - report(str, 'println', '#2E1B00'); // p5.js darkened gold - report(str, 'println', '#008851'); // auto dark cyan - report(str, 'println', '#C83C00'); // auto dark orange - report(str, 'println', '#4DB200'); // auto dark green -} */ - -// This is a lazily-defined list of p5 symbols that may be -// misused by beginners at top-level code, outside of setup/draw. We'd like -// to detect these errors and help the user by suggesting they move them -// into setup/draw. -// -// For more details, see https://github.com/processing/p5.js/issues/1121. -var misusedAtTopLevelCode = null; -var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' + - 'Frequently-Asked-Questions' + - '#why-cant-i-assign-variables-using-p5-functions-and-' + - 'variables-before-setup'; - -function defineMisusedAtTopLevelCode() { - var uniqueNamesFound = {}; - - var getSymbols = function(obj) { - return Object.getOwnPropertyNames(obj).filter(function(name) { - if (name[0] === '_') { - return false; - } - if (name in uniqueNamesFound) { - return false; - } - - uniqueNamesFound[name] = true; - - return true; - }).map(function(name) { - var type; - - if (typeof(obj[name]) === 'function') { - type = 'function'; - } else if (name === name.toUpperCase()) { - type = 'constant'; - } else { - type = 'variable'; - } - - return {name: name, type: type}; - }); - }; - - misusedAtTopLevelCode = [].concat( - getSymbols(p5.prototype), - // At present, p5 only adds its constants to p5.prototype during - // construction, which may not have happened at the time a - // ReferenceError is thrown, so we'll manually add them to our list. - getSymbols(_dereq_('./constants')) - ); - - // This will ultimately ensure that we report the most specific error - // possible to the user, e.g. advising them about HALF_PI instead of PI - // when their code misuses the former. - misusedAtTopLevelCode.sort(function(a, b) { - return b.name.length - a.name.length; - }); -} - -function helpForMisusedAtTopLevelCode(e, log) { - if (!log) { - log = console.log.bind(console); - } - - if (!misusedAtTopLevelCode) { - defineMisusedAtTopLevelCode(); - } - - // If we find that we're logging lots of false positives, we can - // uncomment the following code to avoid displaying anything if the - // user's code isn't likely to be using p5's global mode. (Note that - // setup/draw are more likely to be defined due to JS function hoisting.) - // - //if (!('setup' in window || 'draw' in window)) { - // return; - //} - - misusedAtTopLevelCode.some(function(symbol) { - // Note that while just checking for the occurrence of the - // symbol name in the error message could result in false positives, - // a more rigorous test is difficult because different browsers - // log different messages, and the format of those messages may - // change over time. - // - // For example, if the user uses 'PI' in their code, it may result - // in any one of the following messages: - // - // * 'PI' is undefined (Microsoft Edge) - // * ReferenceError: PI is undefined (Firefox) - // * Uncaught ReferenceError: PI is not defined (Chrome) - - if (e.message && e.message.indexOf(symbol.name) !== -1) { - log('%cDid you just try to use p5.js\'s ' + symbol.name + - (symbol.type === 'function' ? '() ' : ' ') + symbol.type + - '? If so, you may want to ' + - 'move it into your sketch\'s setup() function.\n\n' + - 'For more details, see: ' + FAQ_URL, - 'color: #B40033' /* Dark magenta */); - return true; - } - }); -} - -// Exposing this primarily for unit testing. -p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode; - -if (document.readyState !== 'complete') { - window.addEventListener('error', helpForMisusedAtTopLevelCode, false); - - // Our job is only to catch ReferenceErrors that are thrown when - // global (non-instance mode) p5 APIs are used at the top-level - // scope of a file, so we'll unbind our error listener now to make - // sure we don't log false positives later. - window.addEventListener('load', function() { - window.removeEventListener('error', helpForMisusedAtTopLevelCode, false); - }); -} - -module.exports = p5; - -},{"./constants":47,"./core":48}],52:[function(_dereq_,module,exports){ -/** - * @module DOM - * @submodule DOM - * @for p5.Element - */ - -var p5 = _dereq_('./core'); - -/** - * Base class for all elements added to a sketch, including canvas, - * graphics buffers, and other HTML elements. Methods in blue are - * included in the core functionality, methods in brown are added - * with the <a href="http://p5js.org/libraries/">p5.dom library</a>. - * It is not called directly, but p5.Element - * objects are created by calling createCanvas, createGraphics, - * or in the p5.dom library, createDiv, createImg, createInput, etc. - * - * @class p5.Element - * @constructor - * @param {String} elt DOM node that is wrapped - * @param {Object} [pInst] pointer to p5 instance - */ -p5.Element = function(elt, pInst) { - /** - * Underlying HTML element. All normal HTML methods can be called on this. - * - * @property elt - */ - this.elt = elt; - this._pInst = pInst; - this._events = {}; - this.width = this.elt.offsetWidth; - this.height = this.elt.offsetHeight; -}; - -/** - * - * Attaches the element to the parent specified. A way of setting - * the container for the element. Accepts either a string ID, DOM - * node, or p5.Element. If no arguments given, parent node is returned. - * - * @method parent - * @param {String|Object} parent the ID, DOM node, or p5.Element - * of desired parent element - * @return {p5.Element} - * @example - * <div class="norender"><code> - * // in the html file: - * <div id="myContainer"></div> - * // in the js file: - * var cnv = createCanvas(100, 100); - * cnv.parent("myContainer"); - * </code></div> - * <div class='norender'><code> - * var div0 = createDiv('this is the parent'); - * var div1 = createDiv('this is the child'); - * div1.parent(div0); // use p5.Element - * </code></div> - * <div class='norender'><code> - * var div0 = createDiv('this is the parent'); - * div0.id('apples'); - * var div1 = createDiv('this is the child'); - * div1.parent('apples'); // use id - * </code></div> - * <div class='norender'><code> - * var elt = document.getElementById('myParentDiv'); - * var div1 = createDiv('this is the child'); - * div1.parent(elt); // use element from page - * </code></div> - */ -p5.Element.prototype.parent = function(p) { - if (arguments.length === 0){ - return this.elt.parentNode; - } else { - if (typeof p === 'string') { - if (p[0] === '#') { - p = p.substring(1); - } - p = document.getElementById(p); - } else if (p instanceof p5.Element) { - p = p.elt; - } - p.appendChild(this.elt); - return this; - } -}; - -/** - * - * Sets the ID of the element - * - * @method id - * @param {String} id ID of the element - * @return {p5.Element} - */ -p5.Element.prototype.id = function(id) { - if (arguments.length === 0) { - return this.elt.id; - } else { - this.elt.id = id; - this.width = this.elt.offsetWidth; - this.height = this.elt.offsetHeight; - return this; - } -}; - -/** - * - * Adds given class to the element - * - * @method class - * @param {String} class class to add - * @return {p5.Element} - */ -p5.Element.prototype.class = function(c) { - if (arguments.length === 0) { - return this.elt.className; - } else { - this.elt.className = c; - this.width = this.elt.offsetWidth; - this.height = this.elt.offsetHeight; - return this; - } -}; - -/** - * The .mousePressed() function is called once after every time a - * mouse button is pressed over the element. This can be used to - * attach element specific event listeners. - * - * @method mousePressed - * @param {Function} fxn function to be fired when mouse is - * pressed over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mousePressed(changeGray); // attach listener for - * // canvas click only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires with any click anywhere - * function mousePressed() { - * d = d + 10; - * } - * - * // this function fires only when cnv is clicked - * function changeGray() { - * g = random(0, 255); - * } - * </code></div> - * - */ -p5.Element.prototype.mousePressed = function (fxn) { - attachListener('mousedown', fxn, this); - attachListener('touchstart', fxn, this); - return this; -}; - -/** - * The .mouseWheel() function is called once after every time a - * mouse wheel is scrolled over the element. This can be used to - * attach element specific event listeners.<br><br> - * The event.wheelDelta or event.detail property returns negative values if - * the mouse wheel if rotated up or away from the user and positive in the - * other direction. On OS X with "natural" scrolling enabled, the values are - * opposite. - * - * @method mouseWheel - * @param {Function} fxn function to be fired when mouse wheel is - * scrolled over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mouseWheel(changeSize); // attach listener for - * // activity on canvas only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires with mousewheel movement - * // anywhere on screen - * function mouseWheel() { - * g = g + 10; - * } - * - * // this function fires with mousewheel movement - * // over canvas only - * function changeSize() { - * if (event.wheelDelta > 0) { - * d = d + 10; - * } else { - * d = d - 10; - * } - * } - * </code></div> - * - */ -p5.Element.prototype.mouseWheel = function (fxn) { - attachListener('wheel', fxn, this); - return this; -}; - -/** - * The .mouseReleased() function is called once after every time a - * mouse button is released over the element. This can be used to - * attach element specific event listeners. - * - * @method mouseReleased - * @param {Function} fxn function to be fired when mouse is - * released over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mouseReleased(changeGray); // attach listener for - * // activity on canvas only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires after the mouse has been - * // released - * function mouseReleased() { - * d = d + 10; - * } - * - * // this function fires after the mouse has been - * // released while on canvas - * function changeGray() { - * g = random(0, 255); - * } - * </code></div> - * - */ -p5.Element.prototype.mouseReleased = function (fxn) { - attachListener('mouseup', fxn, this); - attachListener('touchend', fxn, this); - return this; -}; - - -/** - * The .mouseClicked() function is called once after a mouse button is - * pressed and released over the element. This can be used to - * attach element specific event listeners. - * - * @method mouseClicked - * @param {Function} fxn function to be fired when mouse is - * clicked over the element. - * @return {p5.Element} - * @example - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mouseClicked(changeGray); // attach listener for - * // activity on canvas only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires after the mouse has been - * // clicked anywhere - * function mouseClicked() { - * d = d + 10; - * } - * - * // this function fires after the mouse has been - * // clicked on canvas - * function changeGray() { - * g = random(0, 255); - * } - * </code></div> - * - */ -p5.Element.prototype.mouseClicked = function (fxn) { - attachListener('click', fxn, this); - return this; -}; - -/** - * The .mouseMoved() function is called once every time a - * mouse moves over the element. This can be used to attach an - * element specific event listener. - * - * @method mouseMoved - * @param {Function} fxn function to be fired when mouse is - * moved over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d = 30; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mouseMoved(changeSize); // attach listener for - * // activity on canvas only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * fill(200); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires when mouse moves anywhere on - * // page - * function mouseMoved() { - * g = g + 5; - * if (g > 255) { - * g = 0; - * } - * } - * - * // this function fires when mouse moves over canvas - * function changeSize() { - * d = d + 2; - * if (d > 100) { - * d = 0; - * } - * } - * </code></div> - * - */ -p5.Element.prototype.mouseMoved = function (fxn) { - attachListener('mousemove', fxn, this); - attachListener('touchmove', fxn, this); - return this; -}; - -/** - * The .mouseOver() function is called once after every time a - * mouse moves onto the element. This can be used to attach an - * element specific event listener. - * - * @method mouseOver - * @param {Function} fxn function to be fired when mouse is - * moved over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mouseOver(changeGray); - * d = 10; - * } - * - * function draw() { - * ellipse(width/2, height/2, d, d); - * } - * - * function changeGray() { - * d = d + 10; - * if (d > 100) { - * d = 0; - * } - * } - * </code></div> - * - */ -p5.Element.prototype.mouseOver = function (fxn) { - attachListener('mouseover', fxn, this); - return this; -}; - - -/** - * The .changed() function is called when the value of an - * element is changed. - * This can be used to attach an element specific event listener. - * - * @method changed - * @param {Function} fxn function to be fired when the value of an - * element changes. - * @return {p5.Element} - * @example - * <div><code> - * var sel; - * - * function setup() { - * textAlign(CENTER); - * background(200); - * sel = createSelect(); - * sel.position(10, 10); - * sel.option('pear'); - * sel.option('kiwi'); - * sel.option('grape'); - * sel.changed(mySelectEvent); - * } - * - * function mySelectEvent() { - * var item = sel.value(); - * background(200); - * text("it's a "+item+"!", 50, 50); - * } - * </code></div> - * <div><code> - * var checkbox; - * var cnv; - * - * function setup() { - * checkbox = createCheckbox(" fill"); - * checkbox.changed(changeFill); - * cnv = createCanvas(100, 100); - * cnv.position(0, 30); - * noFill(); - * } - * - * function draw() { - * background(200); - * ellipse(50, 50, 50, 50); - * } - * - * function changeFill() { - * if (checkbox.checked()) { - * fill(0); - * } else { - * noFill(); - * } - * } - * </code></div> - */ -p5.Element.prototype.changed = function (fxn) { - attachListener('change', fxn, this); - return this; -}; - -/** - * The .input() function is called when any user input is - * detected with an element. The input event is often used - * to detect keystrokes in a input element, or changes on a - * slider element. This can be used to attach an element specific - * event listener. - * - * @method input - * @param {Function} fxn function to be fired on user input. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * // Open your console to see the output - * function setup() { - * var inp = createInput(''); - * inp.input(myInputEvent); - * } - * - * function myInputEvent() { - * console.log('you are typing: ', this.value()); - * } - * </code></div> - * - */ -p5.Element.prototype.input = function (fxn) { - attachListener('input', fxn, this); - return this; -}; - -/** - * The .mouseOut() function is called once after every time a - * mouse moves off the element. This can be used to attach an - * element specific event listener. - * - * @method mouseOut - * @param {Function} fxn function to be fired when mouse is - * moved off the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.mouseOut(changeGray); - * d = 10; - * } - * - * function draw() { - * ellipse(width/2, height/2, d, d); - * } - * - * function changeGray() { - * d = d + 10; - * if (d > 100) { - * d = 0; - * } - * } - * </code></div> - * - */ -p5.Element.prototype.mouseOut = function (fxn) { - attachListener('mouseout', fxn, this); - return this; -}; - -/** - * The .touchStarted() function is called once after every time a touch is - * registered. This can be used to attach element specific event listeners. - * - * @method touchStarted - * @param {Function} fxn function to be fired when touch is - * started over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.touchStarted(changeGray); // attach listener for - * // canvas click only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires with any touch anywhere - * function touchStarted() { - * d = d + 10; - * } - * - * // this function fires only when cnv is clicked - * function changeGray() { - * g = random(0, 255); - * } - * </code></div> - * - */ -p5.Element.prototype.touchStarted = function (fxn) { - attachListener('touchstart', fxn, this); - attachListener('mousedown', fxn, this); - return this; -}; - -/** - * The .touchMoved() function is called once after every time a touch move is - * registered. This can be used to attach element specific event listeners. - * - * @method touchMoved - * @param {Function} fxn function to be fired when touch is moved - * over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.touchMoved(changeGray); // attach listener for - * // canvas click only - * g = 100; - * } - * - * function draw() { - * background(g); - * } - * - * // this function fires only when cnv is clicked - * function changeGray() { - * g = random(0, 255); - * } - * </code></div> - * - */ -p5.Element.prototype.touchMoved = function (fxn) { - attachListener('touchmove', fxn, this); - attachListener('mousemove', fxn, this); - return this; -}; - -/** - * The .touchEnded() function is called once after every time a touch is - * registered. This can be used to attach element specific event listeners. - * - * @method touchEnded - * @param {Function} fxn function to be fired when touch is - * ended over the element. - * @return {p5.Element} - * @example - * <div class='norender'><code> - * var cnv; - * var d; - * var g; - * function setup() { - * cnv = createCanvas(100, 100); - * cnv.touchEnded(changeGray); // attach listener for - * // canvas click only - * d = 10; - * g = 100; - * } - * - * function draw() { - * background(g); - * ellipse(width/2, height/2, d, d); - * } - * - * // this function fires with any touch anywhere - * function touchEnded() { - * d = d + 10; - * } - * - * // this function fires only when cnv is clicked - * function changeGray() { - * g = random(0, 255); - * } - * </code></div> - * - */ -p5.Element.prototype.touchEnded = function (fxn) { - attachListener('touchend', fxn, this); - attachListener('mouseup', fxn, this); - return this; -}; - - - -/** - * The .dragOver() function is called once after every time a - * file is dragged over the element. This can be used to attach an - * element specific event listener. - * - * @method dragOver - * @param {Function} fxn function to be fired when mouse is - * dragged over the element. - * @return {p5.Element} - */ -p5.Element.prototype.dragOver = function (fxn) { - attachListener('dragover', fxn, this); - return this; -}; - -/** - * The .dragLeave() function is called once after every time a - * dragged file leaves the element area. This can be used to attach an - * element specific event listener. - * - * @method dragLeave - * @param {Function} fxn function to be fired when mouse is - * dragged over the element. - * @return {p5.Element} - */ -p5.Element.prototype.dragLeave = function (fxn) { - attachListener('dragleave', fxn, this); - return this; -}; - -/** - * The .drop() function is called for each file dropped on the element. - * It requires a callback that is passed a p5.File object. You can - * optionally pass two callbacks, the first one (required) is triggered - * for each file dropped when the file is loaded. The second (optional) - * is triggered just once when a file (or files) are dropped. - * - * @method drop - * @param {Function} callback triggered when files are dropped. - * @param {Function} callback to receive loaded file. - * @return {p5.Element} - */ -p5.Element.prototype.drop = function (callback, fxn) { - // Make a file loader callback and trigger user's callback - function makeLoader(theFile) { - // Making a p5.File object - var p5file = new p5.File(theFile); - return function(e) { - p5file.data = e.target.result; - callback(p5file); - }; - } - - // Is the file stuff supported? - if (window.File && window.FileReader && window.FileList && window.Blob) { - - // If you want to be able to drop you've got to turn off - // a lot of default behavior - attachListener('dragover',function(evt) { - evt.stopPropagation(); - evt.preventDefault(); - },this); - - // If this is a drag area we need to turn off the default behavior - attachListener('dragleave',function(evt) { - evt.stopPropagation(); - evt.preventDefault(); - },this); - - // If just one argument it's the callback for the files - if (arguments.length > 1) { - attachListener('drop', fxn, this); - } - - // Deal with the files - attachListener('drop', function(evt) { - - evt.stopPropagation(); - evt.preventDefault(); - - // A FileList - var files = evt.dataTransfer.files; - - // Load each one and trigger the callback - for (var i = 0; i < files.length; i++) { - var f = files[i]; - var reader = new FileReader(); - reader.onload = makeLoader(f); - - - // Text or data? - // This should likely be improved - if (f.type.indexOf('text') > -1) { - reader.readAsText(f); - } else { - reader.readAsDataURL(f); - } - } - }, this); - } else { - console.log('The File APIs are not fully supported in this browser.'); - } - - return this; -}; - - - - -function attachListener(ev, fxn, ctx) { - // LM removing, not sure why we had this? - // var _this = ctx; - // var f = function (e) { fxn(e, _this); }; - var f = fxn.bind(ctx); - ctx.elt.addEventListener(ev, f, false); - ctx._events[ev] = f; -} - -/** - * Helper fxn for sharing pixel methods - * - */ -p5.Element.prototype._setProperty = function (prop, value) { - this[prop] = value; -}; - - -module.exports = p5.Element; - -},{"./core":48}],53:[function(_dereq_,module,exports){ -/** - * @module Rendering - * @submodule Rendering - * @for p5 - */ - -var p5 = _dereq_('./core'); -var constants = _dereq_('./constants'); - -/** - * Thin wrapper around a renderer, to be used for creating a - * graphics buffer object. Use this class if you need - * to draw into an off-screen graphics buffer. The two parameters define the - * width and height in pixels. The fields and methods for this class are - * extensive, but mirror the normal drawing API for p5. - * - * @class p5.Graphics - * @constructor - * @extends p5.Element - * @param {String} elt DOM node that is wrapped - * @param {Object} [pInst] pointer to p5 instance - * @param {Boolean} whether we're using it as main canvas - */ -p5.Graphics = function(w, h, renderer, pInst) { - - var r = renderer || constants.P2D; - - var c = document.createElement('canvas'); - var node = this._userNode || document.body; - node.appendChild(c); - - p5.Element.call(this, c, pInst, false); - this._styles = []; - this.width = w; - this.height = h; - this._pixelDensity = pInst._pixelDensity; - - if (r === constants.WEBGL) { - this._renderer = new p5.Renderer3D(c, pInst, false); - } else { - this._renderer = new p5.Renderer2D(c, pInst, false); - } - - this._renderer.resize(w, h); - this._renderer._applyDefaults(); - - pInst._elements.push(this); - - // bind methods and props of p5 to the new object - for (var p in p5.prototype) { - if (!this[p]) { - if (typeof p5.prototype[p] === 'function') { - this[p] = p5.prototype[p].bind(this); - } else { - this[p] = p5.prototype[p]; - } - } - } - - return this; -}; - -p5.Graphics.prototype = Object.create(p5.Element.prototype); - -module.exports = p5.Graphics; - -},{"./constants":47,"./core":48}],54:[function(_dereq_,module,exports){ -/** - * @module Rendering - * @submodule Rendering - * @for p5 - */ - -var p5 = _dereq_('./core'); -var constants = _dereq_('../core/constants'); - -/** - * Main graphics and rendering context, as well as the base API - * implementation for p5.js "core". To be used as the superclass for - * Renderer2D and Renderer3D classes, respecitvely. - * - * @class p5.Renderer - * @constructor - * @extends p5.Element - * @param {String} elt DOM node that is wrapped - * @param {Object} [pInst] pointer to p5 instance - * @param {Boolean} whether we're using it as main canvas - */ -p5.Renderer = function(elt, pInst, isMainCanvas) { - p5.Element.call(this, elt, pInst); - this.canvas = elt; - this._pInst = pInst; - if (isMainCanvas) { - this._isMainCanvas = true; - // for pixel method sharing with pimage - this._pInst._setProperty('_curElement', this); - this._pInst._setProperty('canvas', this.canvas); - this._pInst._setProperty('width', this.width); - this._pInst._setProperty('height', this.height); - } else { // hide if offscreen buffer by default - this.canvas.style.display = 'none'; - this._styles = []; // non-main elt styles stored in p5.Renderer - } - - - this._textSize = 12; - this._textLeading = 15; - this._textFont = 'sans-serif'; - this._textStyle = constants.NORMAL; - this._textAscent = null; - this._textDescent = null; - - - this._rectMode = constants.CORNER; - this._ellipseMode = constants.CENTER; - this._curveTightness = 0; - this._imageMode = constants.CORNER; - - this._tint = null; - this._doStroke = true; - this._doFill = true; - this._strokeSet = false; - this._fillSet = false; - this._colorMode = constants.RGB; - this._colorMaxes = { - rgb: [255, 255, 255, 255], - hsb: [360, 100, 100, 1], - hsl: [360, 100, 100, 1] - }; - -}; - -p5.Renderer.prototype = Object.create(p5.Element.prototype); - - - - -/** - * Resize our canvas element. - */ -p5.Renderer.prototype.resize = function(w, h) { - this.width = w; - this.height = h; - this.elt.width = w * this._pInst._pixelDensity; - this.elt.height = h * this._pInst._pixelDensity; - this.elt.style.width = w +'px'; - this.elt.style.height = h + 'px'; - if (this._isMainCanvas) { - this._pInst._setProperty('width', this.width); - this._pInst._setProperty('height', this.height); - } -}; - -p5.Renderer.prototype.textLeading = function(l) { - - if (arguments.length && arguments[0]) { - - this._setProperty('_textLeading', l); - return this; - } - - return this._textLeading; -}; - -p5.Renderer.prototype.textSize = function(s) { - - if (arguments.length && arguments[0]) { - - this._setProperty('_textSize', s); - this._setProperty('_textLeading', s * constants._DEFAULT_LEADMULT); - return this._applyTextProperties(); - } - - return this._textSize; -}; - -p5.Renderer.prototype.textStyle = function(s) { - - if (arguments.length && arguments[0]) { - - if (s === constants.NORMAL || - s === constants.ITALIC || - s === constants.BOLD) { - this._setProperty('_textStyle', s); - } - - return this._applyTextProperties(); - } - - return this._textStyle; -}; - -p5.Renderer.prototype.textAscent = function() { - if (this._textAscent === null) { - this._updateTextMetrics(); - } - return this._textAscent; -}; - -p5.Renderer.prototype.textDescent = function() { - - if (this._textDescent === null) { - this._updateTextMetrics(); - } - return this._textDescent; -}; - -/** - * Helper fxn to check font type (system or otf) - */ -p5.Renderer.prototype._isOpenType = function(f) { - - f = f || this._textFont; - return (typeof f === 'object' && f.font && f.font.supported); -}; - -p5.Renderer.prototype._updateTextMetrics = function() { - - if (this._isOpenType()) { - - this._setProperty('_textAscent', this._textFont._textAscent()); - this._setProperty('_textDescent', this._textFont._textDescent()); - return this; - } - - // Adapted from http://stackoverflow.com/a/25355178 - var text = document.createElement('span'); - text.style.fontFamily = this._textFont; - text.style.fontSize = this._textSize + 'px'; - text.innerHTML = 'ABCjgq|'; - - var block = document.createElement('div'); - block.style.display = 'inline-block'; - block.style.width = '1px'; - block.style.height = '0px'; - - var container = document.createElement('div'); - container.appendChild(text); - container.appendChild(block); - - container.style.height = '0px'; - container.style.overflow = 'hidden'; - document.body.appendChild(container); - - block.style.verticalAlign = 'baseline'; - var blockOffset = calculateOffset(block); - var textOffset = calculateOffset(text); - var ascent = blockOffset[1] - textOffset[1]; - - block.style.verticalAlign = 'bottom'; - blockOffset = calculateOffset(block); - textOffset = calculateOffset(text); - var height = blockOffset[1] - textOffset[1]; - var descent = height - ascent; - - document.body.removeChild(container); - - this._setProperty('_textAscent', ascent); - this._setProperty('_textDescent', descent); - - return this; -}; - -/** - * Helper fxn to measure ascent and descent. - * Adapted from http://stackoverflow.com/a/25355178 - */ -function calculateOffset(object) { - var currentLeft = 0, - currentTop = 0; - if (object.offsetParent) { - do { - currentLeft += object.offsetLeft; - currentTop += object.offsetTop; - } while (object = object.offsetParent); - } else { - currentLeft += object.offsetLeft; - currentTop += object.offsetTop; - } - return [currentLeft, currentTop]; -} - -module.exports = p5.Renderer; - -},{"../core/constants":47,"./core":48}],55:[function(_dereq_,module,exports){ - -var p5 = _dereq_('./core'); -var canvas = _dereq_('./canvas'); -var constants = _dereq_('./constants'); -var filters = _dereq_('../image/filters'); - -_dereq_('./p5.Renderer'); - -/** - * p5.Renderer2D - * The 2D graphics canvas renderer class. - * extends p5.Renderer - */ -var styleEmpty = 'rgba(0,0,0,0)'; -// var alphaThreshold = 0.00125; // minimum visible - -p5.Renderer2D = function(elt, pInst, isMainCanvas){ - p5.Renderer.call(this, elt, pInst, isMainCanvas); - this.drawingContext = this.canvas.getContext('2d'); - this._pInst._setProperty('drawingContext', this.drawingContext); - return this; -}; - -p5.Renderer2D.prototype = Object.create(p5.Renderer.prototype); - -p5.Renderer2D.prototype._applyDefaults = function() { - this.drawingContext.fillStyle = constants._DEFAULT_FILL; - this.drawingContext.strokeStyle = constants._DEFAULT_STROKE; - this.drawingContext.lineCap = constants.ROUND; - this.drawingContext.font = 'normal 12px sans-serif'; -}; - -p5.Renderer2D.prototype.resize = function(w,h) { - p5.Renderer.prototype.resize.call(this, w,h); - this.drawingContext.scale(this._pInst._pixelDensity, - this._pInst._pixelDensity); -}; - -////////////////////////////////////////////// -// COLOR | Setting -////////////////////////////////////////////// - -p5.Renderer2D.prototype.background = function() { - this.drawingContext.save(); - this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); - this.drawingContext.scale(this._pInst._pixelDensity, - this._pInst._pixelDensity); - - if (arguments[0] instanceof p5.Image) { - this._pInst.image(arguments[0], 0, 0, this.width, this.height); - } else { - var curFill = this.drawingContext.fillStyle; - // create background rect - var color = this._pInst.color.apply(this, arguments); - var newFill = color.toString(); - this.drawingContext.fillStyle = newFill; - this.drawingContext.fillRect(0, 0, this.width, this.height); - // reset fill - this.drawingContext.fillStyle = curFill; - } - this.drawingContext.restore(); -}; - -p5.Renderer2D.prototype.clear = function() { - this.drawingContext.clearRect(0, 0, this.width, this.height); -}; - -p5.Renderer2D.prototype.fill = function() { - - var ctx = this.drawingContext; - var color = this._pInst.color.apply(this, arguments); - ctx.fillStyle = color.toString(); -}; - -p5.Renderer2D.prototype.stroke = function() { - var ctx = this.drawingContext; - var color = this._pInst.color.apply(this, arguments); - ctx.strokeStyle = color.toString(); -}; - -////////////////////////////////////////////// -// IMAGE | Loading & Displaying -////////////////////////////////////////////// - -p5.Renderer2D.prototype.image = - function (img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) { - var cnv; - try { - if (this._tint) { - if (p5.MediaElement && img instanceof p5.MediaElement) { - img.loadPixels(); - } - if (img.canvas) { - cnv = this._getTintedImageCanvas(img); - } - } - if (!cnv) { - cnv = img.canvas || img.elt; - } - this.drawingContext.drawImage(cnv, sx, sy, sWidth, sHeight, dx, dy, - dWidth, dHeight); - } catch (e) { - if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { - throw e; - } - } -}; - -p5.Renderer2D.prototype._getTintedImageCanvas = function (img) { - if (!img.canvas) { - return img; - } - var pixels = filters._toPixels(img.canvas); - var tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = img.canvas.width; - tmpCanvas.height = img.canvas.height; - var tmpCtx = tmpCanvas.getContext('2d'); - var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height); - var newPixels = id.data; - for (var i = 0; i < pixels.length; i += 4) { - var r = pixels[i]; - var g = pixels[i + 1]; - var b = pixels[i + 2]; - var a = pixels[i + 3]; - newPixels[i] = r * this._tint[0] / 255; - newPixels[i + 1] = g * this._tint[1] / 255; - newPixels[i + 2] = b * this._tint[2] / 255; - newPixels[i + 3] = a * this._tint[3] / 255; - } - tmpCtx.putImageData(id, 0, 0); - return tmpCanvas; -}; - - -////////////////////////////////////////////// -// IMAGE | Pixels -////////////////////////////////////////////// - -p5.Renderer2D.prototype.blendMode = function(mode) { - this.drawingContext.globalCompositeOperation = mode; -}; -p5.Renderer2D.prototype.blend = function() { - var currBlend = this.drawingContext.globalCompositeOperation; - var blendMode = arguments[arguments.length - 1]; - - var copyArgs = Array.prototype.slice.call( - arguments, - 0, - arguments.length - 1 - ); - - this.drawingContext.globalCompositeOperation = blendMode; - this._pInst.copy.apply(this._pInst, copyArgs); - this.drawingContext.globalCompositeOperation = currBlend; -}; - -p5.Renderer2D.prototype.copy = function () { - var srcImage, sx, sy, sw, sh, dx, dy, dw, dh; - if (arguments.length === 9) { - srcImage = arguments[0]; - sx = arguments[1]; - sy = arguments[2]; - sw = arguments[3]; - sh = arguments[4]; - dx = arguments[5]; - dy = arguments[6]; - dw = arguments[7]; - dh = arguments[8]; - } else if (arguments.length === 8) { - srcImage = this._pInst; - sx = arguments[0]; - sy = arguments[1]; - sw = arguments[2]; - sh = arguments[3]; - dx = arguments[4]; - dy = arguments[5]; - dw = arguments[6]; - dh = arguments[7]; - } else { - throw new Error('Signature not supported'); - } - p5.Renderer2D._copyHelper(srcImage, sx, sy, sw, sh, dx, dy, dw, dh); -}; - -p5.Renderer2D._copyHelper = -function (srcImage, sx, sy, sw, sh, dx, dy, dw, dh) { - var s = srcImage.canvas.width / srcImage.width; - this.drawingContext.drawImage(srcImage.canvas, - s * sx, s * sy, s * sw, s * sh, dx, dy, dw, dh); -}; - -p5.Renderer2D.prototype.get = function(x, y, w, h) { - if (x === undefined && y === undefined && - w === undefined && h === undefined){ - x = 0; - y = 0; - w = this.width; - h = this.height; - } else if (w === undefined && h === undefined) { - w = 1; - h = 1; - } - - // if the section does not overlap the canvas - if(x + w < 0 || y + h < 0 || x > this.width || y > this.height){ - return [0, 0, 0, 255]; - } - - var ctx = this._pInst || this; - - var pd = ctx._pixelDensity; - - this.loadPixels.call(ctx); - - // round down to get integer numbers - x = Math.floor(x); - y = Math.floor(y); - - if (w === 1 && h === 1){ - - return [ - ctx.pixels[pd*4*(y*this.width+x)], - ctx.pixels[pd*(4*(y*this.width+x)+1)], - ctx.pixels[pd*(4*(y*this.width+x)+2)], - ctx.pixels[pd*(4*(y*this.width+x)+3)] - ]; - } else { - var sx = x * pd; - var sy = y * pd; - //auto constrain the width and height to - //dimensions of the source image - var dw = Math.min(w, ctx.width); - var dh = Math.min(h, ctx.height); - var sw = dw * pd; - var sh = dh * pd; - - var region = new p5.Image(dw, dh); - region.canvas.getContext('2d').drawImage(this.canvas, sx, sy, sw, sh, - 0, 0, dw, dh); - - return region; - } -}; - -p5.Renderer2D.prototype.loadPixels = function () { - var pd = this._pixelDensity || this._pInst._pixelDensity; - var w = this.width * pd; - var h = this.height * pd; - var imageData = this.drawingContext.getImageData(0, 0, w, h); - // @todo this should actually set pixels per object, so diff buffers can - // have diff pixel arrays. - if (this._pInst) { - this._pInst._setProperty('imageData', imageData); - this._pInst._setProperty('pixels', imageData.data); - } else { // if called by p5.Image - this._setProperty('imageData', imageData); - this._setProperty('pixels', imageData.data); - } -}; - -p5.Renderer2D.prototype.set = function (x, y, imgOrCol) { - // round down to get integer numbers - x = Math.floor(x); - y = Math.floor(y); - if (imgOrCol instanceof p5.Image) { - this.drawingContext.save(); - this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); - this.drawingContext.scale(this._pInst._pixelDensity, - this._pInst._pixelDensity); - this.drawingContext.drawImage(imgOrCol.canvas, x, y); - this.loadPixels.call(this._pInst); - this.drawingContext.restore(); - } else { - var ctx = this._pInst || this; - var r = 0, g = 0, b = 0, a = 0; - var idx = 4*((y * ctx._pixelDensity) * - (this.width * ctx._pixelDensity) + (x * ctx._pixelDensity)); - if (!ctx.imageData) { - ctx.loadPixels.call(ctx); - } - if (typeof imgOrCol === 'number') { - if (idx < ctx.pixels.length) { - r = imgOrCol; - g = imgOrCol; - b = imgOrCol; - a = 255; - //this.updatePixels.call(this); - } - } - else if (imgOrCol instanceof Array) { - if (imgOrCol.length < 4) { - throw new Error('pixel array must be of the form [R, G, B, A]'); - } - if (idx < ctx.pixels.length) { - r = imgOrCol[0]; - g = imgOrCol[1]; - b = imgOrCol[2]; - a = imgOrCol[3]; - //this.updatePixels.call(this); - } - } else if (imgOrCol instanceof p5.Color) { - if (idx < ctx.pixels.length) { - r = imgOrCol.levels[0]; - g = imgOrCol.levels[1]; - b = imgOrCol.levels[2]; - a = imgOrCol.levels[3]; - //this.updatePixels.call(this); - } - } - // loop over pixelDensity * pixelDensity - for (var i = 0; i < ctx._pixelDensity; i++) { - for (var j = 0; j < ctx._pixelDensity; j++) { - // loop over - idx = 4*((y * ctx._pixelDensity + j) * this.width * - ctx._pixelDensity + (x * ctx._pixelDensity + i)); - ctx.pixels[idx] = r; - ctx.pixels[idx+1] = g; - ctx.pixels[idx+2] = b; - ctx.pixels[idx+3] = a; - } - } - } -}; - -p5.Renderer2D.prototype.updatePixels = function (x, y, w, h) { - var pd = this._pixelDensity || this._pInst._pixelDensity; - if (x === undefined && - y === undefined && - w === undefined && - h === undefined) { - x = 0; - y = 0; - w = this.width; - h = this.height; - } - w *= pd; - h *= pd; - - if (this._pInst) { - this.drawingContext.putImageData(this._pInst.imageData, x, y, 0, 0, w, h); - } else { - this.drawingContext.putImageData(this.imageData, x, y, 0, 0, w, h); - } -}; - -////////////////////////////////////////////// -// SHAPE | 2D Primitives -////////////////////////////////////////////// - -/** - * Generate a cubic Bezier representing an arc on the unit circle of total - * angle `size` radians, beginning `start` radians above the x-axis. Up to - * four of these curves are combined to make a full arc. - * - * See www.joecridge.me/bezier.pdf for an explanation of the method. - */ -p5.Renderer2D.prototype._acuteArcToBezier = - function _acuteArcToBezier(start, size) { - // Evauate constants. - var alpha = size / 2.0, - cos_alpha = Math.cos(alpha), - sin_alpha = Math.sin(alpha), - cot_alpha = 1.0 / Math.tan(alpha), - phi = start + alpha, // This is how far the arc needs to be rotated. - cos_phi = Math.cos(phi), - sin_phi = Math.sin(phi), - lambda = (4.0 - cos_alpha) / 3.0, - mu = sin_alpha + (cos_alpha - lambda) * cot_alpha; - - // Return rotated waypoints. - return { - ax: Math.cos(start), - ay: Math.sin(start), - bx: lambda * cos_phi + mu * sin_phi, - by: lambda * sin_phi - mu * cos_phi, - cx: lambda * cos_phi - mu * sin_phi, - cy: lambda * sin_phi + mu * cos_phi, - dx: Math.cos(start + size), - dy: Math.sin(start + size) - }; -}; - -p5.Renderer2D.prototype.arc = - function(x, y, w, h, start, stop, mode) { - var ctx = this.drawingContext; - var vals = canvas.arcModeAdjust(x, y, w, h, this._ellipseMode); - var rx = vals.w / 2.0; - var ry = vals.h / 2.0; - var epsilon = 0.00001; // Smallest visible angle on displays up to 4K. - var arcToDraw = 0; - var curves = []; - - // Create curves - while(stop - start > epsilon) { - arcToDraw = Math.min(stop - start, constants.HALF_PI); - curves.push(this._acuteArcToBezier(start, arcToDraw)); - start += arcToDraw; - } - - // Fill curves - if (this._doFill) { - ctx.beginPath(); - curves.forEach(function (curve, index) { - if (index === 0) { - ctx.moveTo(vals.x + curve.ax * rx, vals.y + curve.ay * ry); - } - ctx.bezierCurveTo(vals.x + curve.bx * rx, vals.y + curve.by * ry, - vals.x + curve.cx * rx, vals.y + curve.cy * ry, - vals.x + curve.dx * rx, vals.y + curve.dy * ry); - }); - if (mode === constants.PIE || mode == null) { - ctx.lineTo(vals.x, vals.y); - } - ctx.closePath(); - ctx.fill(); - } - - // Stroke curves - if (this._doStroke) { - ctx.beginPath(); - curves.forEach(function (curve, index) { - if (index === 0) { - ctx.moveTo(vals.x + curve.ax * rx, vals.y + curve.ay * ry); - } - ctx.bezierCurveTo(vals.x + curve.bx * rx, vals.y + curve.by * ry, - vals.x + curve.cx * rx, vals.y + curve.cy * ry, - vals.x + curve.dx * rx, vals.y + curve.dy * ry); - }); - if (mode === constants.PIE) { - ctx.lineTo(vals.x, vals.y); - ctx.closePath(); - } else if (mode === constants.CHORD) { - ctx.closePath(); - } - ctx.stroke(); - } - return this; -}; - -p5.Renderer2D.prototype.ellipse = function(x, y, w, h) { - var ctx = this.drawingContext; - var doFill = this._doFill, doStroke = this._doStroke; - if (doFill && !doStroke) { - if(ctx.fillStyle === styleEmpty) { - return this; - } - } else if (!doFill && doStroke) { - if(ctx.strokeStyle === styleEmpty) { - return this; - } - } - var vals = canvas.modeAdjust(x, y, w, h, this._ellipseMode); - var kappa = 0.5522847498, - ox = (vals.w / 2) * kappa, // control point offset horizontal - oy = (vals.h / 2) * kappa, // control point offset vertical - xe = vals.x + vals.w, // x-end - ye = vals.y + vals.h, // y-end - xm = vals.x + vals.w / 2, // x-middle - ym = vals.y + vals.h / 2; // y-middle - ctx.beginPath(); - ctx.moveTo(vals.x, ym); - ctx.bezierCurveTo(vals.x, ym - oy, xm - ox, vals.y, xm, vals.y); - ctx.bezierCurveTo(xm + ox, vals.y, xe, ym - oy, xe, ym); - ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - ctx.bezierCurveTo(xm - ox, ye, vals.x, ym + oy, vals.x, ym); - ctx.closePath(); - if (doFill) { - ctx.fill(); - } - if (doStroke) { - ctx.stroke(); - } -}; - -p5.Renderer2D.prototype.line = function(x1, y1, x2, y2) { - var ctx = this.drawingContext; - if (!this._doStroke) { - return this; - } else if(ctx.strokeStyle === styleEmpty){ - return this; - } - // Translate the line by (0.5, 0.5) to draw it crisp - if (ctx.lineWidth % 2 === 1) { - ctx.translate(0.5, 0.5); - } - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.stroke(); - if (ctx.lineWidth % 2 === 1) { - ctx.translate(-0.5, -0.5); - } - return this; -}; - -p5.Renderer2D.prototype.point = function(x, y) { - var ctx = this.drawingContext; - var s = ctx.strokeStyle; - var f = ctx.fillStyle; - if (!this._doStroke) { - return this; - } else if(ctx.strokeStyle === styleEmpty){ - return this; - } - x = Math.round(x); - y = Math.round(y); - ctx.fillStyle = s; - if (ctx.lineWidth > 1) { - ctx.beginPath(); - ctx.arc( - x, - y, - ctx.lineWidth / 2, - 0, - constants.TWO_PI, - false - ); - ctx.fill(); - } else { - ctx.fillRect(x, y, 1, 1); - } - ctx.fillStyle = f; -}; - -p5.Renderer2D.prototype.quad = - function(x1, y1, x2, y2, x3, y3, x4, y4) { - var ctx = this.drawingContext; - var doFill = this._doFill, doStroke = this._doStroke; - if (doFill && !doStroke) { - if(ctx.fillStyle === styleEmpty) { - return this; - } - } else if (!doFill && doStroke) { - if(ctx.strokeStyle === styleEmpty) { - return this; - } - } - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.lineTo(x3, y3); - ctx.lineTo(x4, y4); - ctx.closePath(); - if (doFill) { - ctx.fill(); - } - if (doStroke) { - ctx.stroke(); - } - return this; -}; - -p5.Renderer2D.prototype.rect = function(x, y, w, h, tl, tr, br, bl) { - var ctx = this.drawingContext; - var doFill = this._doFill, doStroke = this._doStroke; - if (doFill && !doStroke) { - if(ctx.fillStyle === styleEmpty) { - return this; - } - } else if (!doFill && doStroke) { - if(ctx.strokeStyle === styleEmpty) { - return this; - } - } - var vals = canvas.modeAdjust(x, y, w, h, this._rectMode); - // Translate the line by (0.5, 0.5) to draw a crisp rectangle border - if (this._doStroke && ctx.lineWidth % 2 === 1) { - ctx.translate(0.5, 0.5); - } - ctx.beginPath(); - - if (typeof tl === 'undefined') { - // No rounded corners - ctx.rect(vals.x, vals.y, vals.w, vals.h); - } else { - // At least one rounded corner - // Set defaults when not specified - if (typeof tr === 'undefined') { tr = tl; } - if (typeof br === 'undefined') { br = tr; } - if (typeof bl === 'undefined') { bl = br; } - - // Cache and compute several values - var _x = vals.x; - var _y = vals.y; - var _w = vals.w; - var _h = vals.h; - var hw = _w / 2; - var hh = _h / 2; - - // Clip radii - if (_w < 2 * tl) { tl = hw; } - if (_h < 2 * tl) { tl = hh; } - if (_w < 2 * tr) { tr = hw; } - if (_h < 2 * tr) { tr = hh; } - if (_w < 2 * br) { br = hw; } - if (_h < 2 * br) { br = hh; } - if (_w < 2 * bl) { bl = hw; } - if (_h < 2 * bl) { bl = hh; } - - // Draw shape - ctx.beginPath(); - ctx.moveTo(_x + tl, _y); - ctx.arcTo(_x + _w, _y, _x + _w, _y + _h, tr); - ctx.arcTo(_x + _w, _y + _h, _x, _y + _h, br); - ctx.arcTo(_x, _y + _h, _x, _y, bl); - ctx.arcTo(_x, _y, _x + _w, _y, tl); - ctx.closePath(); - } - if (this._doFill) { - ctx.fill(); - } - if (this._doStroke) { - ctx.stroke(); - } - if (this._doStroke && ctx.lineWidth % 2 === 1) { - ctx.translate(-0.5, -0.5); - } - return this; -}; - -p5.Renderer2D.prototype.triangle = function(x1, y1, x2, y2, x3, y3) { - var ctx = this.drawingContext; - var doFill = this._doFill, doStroke = this._doStroke; - if (doFill && !doStroke) { - if(ctx.fillStyle === styleEmpty) { - return this; - } - } else if (!doFill && doStroke) { - if(ctx.strokeStyle === styleEmpty) { - return this; - } - } - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.lineTo(x3, y3); - ctx.closePath(); - if (doFill) { - ctx.fill(); - } - if (doStroke) { - ctx.stroke(); - } -}; - -p5.Renderer2D.prototype.endShape = -function (mode, vertices, isCurve, isBezier, - isQuadratic, isContour, shapeKind) { - if (vertices.length === 0) { - return this; - } - if (!this._doStroke && !this._doFill) { - return this; - } - var closeShape = mode === constants.CLOSE; - var v; - if (closeShape && !isContour) { - vertices.push(vertices[0]); - } - var i, j; - var numVerts = vertices.length; - if (isCurve && (shapeKind === constants.POLYGON || shapeKind === null)) { - if (numVerts > 3) { - var b = [], s = 1 - this._curveTightness; - this.drawingContext.beginPath(); - this.drawingContext.moveTo(vertices[1][0], vertices[1][1]); - for (i = 1; i + 2 < numVerts; i++) { - v = vertices[i]; - b[0] = [ - v[0], - v[1] - ]; - b[1] = [ - v[0] + (s * vertices[i + 1][0] - s * vertices[i - 1][0]) / 6, - v[1] + (s * vertices[i + 1][1] - s * vertices[i - 1][1]) / 6 - ]; - b[2] = [ - vertices[i + 1][0] + - (s * vertices[i][0]-s * vertices[i + 2][0]) / 6, - vertices[i + 1][1]+(s * vertices[i][1] - s*vertices[i + 2][1]) / 6 - ]; - b[3] = [ - vertices[i + 1][0], - vertices[i + 1][1] - ]; - this.drawingContext.bezierCurveTo(b[1][0],b[1][1], - b[2][0],b[2][1],b[3][0],b[3][1]); - } - if (closeShape) { - this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); - } - this._doFillStrokeClose(); - } - } else if (isBezier&&(shapeKind===constants.POLYGON ||shapeKind === null)) { - this.drawingContext.beginPath(); - for (i = 0; i < numVerts; i++) { - if (vertices[i].isVert) { - if (vertices[i].moveTo) { - this.drawingContext.moveTo(vertices[i][0], vertices[i][1]); - } else { - this.drawingContext.lineTo(vertices[i][0], vertices[i][1]); - } - } else { - this.drawingContext.bezierCurveTo(vertices[i][0], vertices[i][1], - vertices[i][2], vertices[i][3], vertices[i][4], vertices[i][5]); - } - } - this._doFillStrokeClose(); - } else if (isQuadratic && - (shapeKind === constants.POLYGON || shapeKind === null)) { - this.drawingContext.beginPath(); - for (i = 0; i < numVerts; i++) { - if (vertices[i].isVert) { - if (vertices[i].moveTo) { - this.drawingContext.moveTo([0], vertices[i][1]); - } else { - this.drawingContext.lineTo(vertices[i][0], vertices[i][1]); - } - } else { - this.drawingContext.quadraticCurveTo(vertices[i][0], vertices[i][1], - vertices[i][2], vertices[i][3]); - } - } - this._doFillStrokeClose(); - } else { - if (shapeKind === constants.POINTS) { - for (i = 0; i < numVerts; i++) { - v = vertices[i]; - if (this._doStroke) { - this._pInst.stroke(v[6]); - } - this._pInst.point(v[0], v[1]); - } - } else if (shapeKind === constants.LINES) { - for (i = 0; i + 1 < numVerts; i += 2) { - v = vertices[i]; - if (this._doStroke) { - this._pInst.stroke(vertices[i + 1][6]); - } - this._pInst.line(v[0], v[1], vertices[i + 1][0], vertices[i + 1][1]); - } - } else if (shapeKind === constants.TRIANGLES) { - for (i = 0; i + 2 < numVerts; i += 3) { - v = vertices[i]; - this.drawingContext.beginPath(); - this.drawingContext.moveTo(v[0], v[1]); - this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); - this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]); - this.drawingContext.lineTo(v[0], v[1]); - if (this._doFill) { - this._pInst.fill(vertices[i + 2][5]); - this.drawingContext.fill(); - } - if (this._doStroke) { - this._pInst.stroke(vertices[i + 2][6]); - this.drawingContext.stroke(); - } - this.drawingContext.closePath(); - } - } else if (shapeKind === constants.TRIANGLE_STRIP) { - for (i = 0; i + 1 < numVerts; i++) { - v = vertices[i]; - this.drawingContext.beginPath(); - this.drawingContext.moveTo(vertices[i + 1][0], vertices[i + 1][1]); - this.drawingContext.lineTo(v[0], v[1]); - if (this._doStroke) { - this._pInst.stroke(vertices[i + 1][6]); - } - if (this._doFill) { - this._pInst.fill(vertices[i + 1][5]); - } - if (i + 2 < numVerts) { - this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]); - if (this._doStroke) { - this._pInst.stroke(vertices[i + 2][6]); - } - if (this._doFill) { - this._pInst.fill(vertices[i + 2][5]); - } - } - this._doFillStrokeClose(); - } - } else if (shapeKind === constants.TRIANGLE_FAN) { - if (numVerts > 2) { - this.drawingContext.beginPath(); - this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); - this.drawingContext.lineTo(vertices[1][0], vertices[1][1]); - this.drawingContext.lineTo(vertices[2][0], vertices[2][1]); - if (this._doFill) { - this._pInst.fill(vertices[2][5]); - } - if (this._doStroke) { - this._pInst.stroke(vertices[2][6]); - } - this._doFillStrokeClose(); - for (i = 3; i < numVerts; i++) { - v = vertices[i]; - this.drawingContext.beginPath(); - this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); - this.drawingContext.lineTo(vertices[i - 1][0], vertices[i - 1][1]); - this.drawingContext.lineTo(v[0], v[1]); - if (this._doFill) { - this._pInst.fill(v[5]); - } - if (this._doStroke) { - this._pInst.stroke(v[6]); - } - this._doFillStrokeClose(); - } - } - } else if (shapeKind === constants.QUADS) { - for (i = 0; i + 3 < numVerts; i += 4) { - v = vertices[i]; - this.drawingContext.beginPath(); - this.drawingContext.moveTo(v[0], v[1]); - for (j = 1; j < 4; j++) { - this.drawingContext.lineTo(vertices[i + j][0], vertices[i + j][1]); - } - this.drawingContext.lineTo(v[0], v[1]); - if (this._doFill) { - this._pInst.fill(vertices[i + 3][5]); - } - if (this._doStroke) { - this._pInst.stroke(vertices[i + 3][6]); - } - this._doFillStrokeClose(); - } - } else if (shapeKind === constants.QUAD_STRIP) { - if (numVerts > 3) { - for (i = 0; i + 1 < numVerts; i += 2) { - v = vertices[i]; - this.drawingContext.beginPath(); - if (i + 3 < numVerts) { - this.drawingContext.moveTo(vertices[i + 2][0], vertices[i+2][1]); - this.drawingContext.lineTo(v[0], v[1]); - this.drawingContext.lineTo(vertices[i + 1][0], vertices[i+1][1]); - this.drawingContext.lineTo(vertices[i + 3][0], vertices[i+3][1]); - if (this._doFill) { - this._pInst.fill(vertices[i + 3][5]); - } - if (this._doStroke) { - this._pInst.stroke(vertices[i + 3][6]); - } - } else { - this.drawingContext.moveTo(v[0], v[1]); - this.drawingContext.lineTo(vertices[i + 1][0], vertices[i+1][1]); - } - this._doFillStrokeClose(); - } - } - } else { - this.drawingContext.beginPath(); - this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); - for (i = 1; i < numVerts; i++) { - v = vertices[i]; - if (v.isVert) { - if (v.moveTo) { - this.drawingContext.moveTo(v[0], v[1]); - } else { - this.drawingContext.lineTo(v[0], v[1]); - } - } - } - this._doFillStrokeClose(); - } - } - isCurve = false; - isBezier = false; - isQuadratic = false; - isContour = false; - if (closeShape) { - vertices.pop(); - } - return this; -}; -////////////////////////////////////////////// -// SHAPE | Attributes -////////////////////////////////////////////// - -p5.Renderer2D.prototype.noSmooth = function() { - if ('imageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.imageSmoothingEnabled = false; - } - else if ('mozImageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.mozImageSmoothingEnabled = false; - } - else if ('webkitImageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.webkitImageSmoothingEnabled = false; - } - else if ('msImageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.msImageSmoothingEnabled = false; - } - return this; -}; - -p5.Renderer2D.prototype.smooth = function() { - if ('imageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.imageSmoothingEnabled = true; - } - else if ('mozImageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.mozImageSmoothingEnabled = true; - } - else if ('webkitImageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.webkitImageSmoothingEnabled = true; - } - else if ('msImageSmoothingEnabled' in this.drawingContext) { - this.drawingContext.msImageSmoothingEnabled = true; - } - return this; -}; - -p5.Renderer2D.prototype.strokeCap = function(cap) { - if (cap === constants.ROUND || - cap === constants.SQUARE || - cap === constants.PROJECT) { - this.drawingContext.lineCap = cap; - } - return this; -}; - -p5.Renderer2D.prototype.strokeJoin = function(join) { - if (join === constants.ROUND || - join === constants.BEVEL || - join === constants.MITER) { - this.drawingContext.lineJoin = join; - } - return this; -}; - -p5.Renderer2D.prototype.strokeWeight = function(w) { - if (typeof w === 'undefined' || w === 0) { - // hack because lineWidth 0 doesn't work - this.drawingContext.lineWidth = 0.0001; - } else { - this.drawingContext.lineWidth = w; - } - return this; -}; - -p5.Renderer2D.prototype._getFill = function(){ - return this.drawingContext.fillStyle; -}; - -p5.Renderer2D.prototype._getStroke = function(){ - return this.drawingContext.strokeStyle; -}; - -////////////////////////////////////////////// -// SHAPE | Curves -////////////////////////////////////////////// -p5.Renderer2D.prototype.bezier = function (x1, y1, x2, y2, x3, y3, x4, y4) { - this._pInst.beginShape(); - this._pInst.vertex(x1, y1); - this._pInst.bezierVertex(x2, y2, x3, y3, x4, y4); - this._pInst.endShape(); - return this; -}; - -p5.Renderer2D.prototype.curve = function (x1, y1, x2, y2, x3, y3, x4, y4) { - this._pInst.beginShape(); - this._pInst.curveVertex(x1, y1); - this._pInst.curveVertex(x2, y2); - this._pInst.curveVertex(x3, y3); - this._pInst.curveVertex(x4, y4); - this._pInst.endShape(); - return this; -}; - -////////////////////////////////////////////// -// SHAPE | Vertex -////////////////////////////////////////////// - -p5.Renderer2D.prototype._doFillStrokeClose = function () { - if (this._doFill) { - this.drawingContext.fill(); - } - if (this._doStroke) { - this.drawingContext.stroke(); - } - this.drawingContext.closePath(); -}; - -////////////////////////////////////////////// -// TRANSFORM -////////////////////////////////////////////// - -p5.Renderer2D.prototype.applyMatrix = -function(n00, n01, n02, n10, n11, n12) { - this.drawingContext.transform(n00, n01, n02, n10, n11, n12); -}; - -p5.Renderer2D.prototype.resetMatrix = function() { - this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); - this.drawingContext.scale(this._pInst._pixelDensity, - this._pInst._pixelDensity); - return this; -}; - -p5.Renderer2D.prototype.rotate = function(r) { - this.drawingContext.rotate(r); -}; - -p5.Renderer2D.prototype.scale = function(x,y) { - this.drawingContext.scale(x, y); - return this; -}; - -p5.Renderer2D.prototype.shearX = function(angle) { - if (this._pInst._angleMode === constants.DEGREES) { - angle = this._pInst.radians(angle); - } - this.drawingContext.transform(1, 0, this._pInst.tan(angle), 1, 0, 0); - return this; -}; - -p5.Renderer2D.prototype.shearY = function(angle) { - if (this._pInst._angleMode === constants.DEGREES) { - angle = this._pInst.radians(angle); - } - this.drawingContext.transform(1, this._pInst.tan(angle), 0, 1, 0, 0); - return this; -}; - -p5.Renderer2D.prototype.translate = function(x, y) { - this.drawingContext.translate(x, y); - return this; -}; - -////////////////////////////////////////////// -// TYPOGRAPHY -// -////////////////////////////////////////////// - -p5.Renderer2D.prototype.text = function (str, x, y, maxWidth, maxHeight) { - - var p = this._pInst, cars, n, ii, jj, line, testLine, - testWidth, words, totalHeight, baselineHacked, - finalMaxHeight = Number.MAX_VALUE; - - // baselineHacked: (HACK) - // A temporary fix to conform to Processing's implementation - // of BASELINE vertical alignment in a bounding box - - if (!(this._doFill || this._doStroke)) { - return; - } - - if (typeof str !== 'string') { - str = str.toString(); - } - - str = str.replace(/(\t)/g, ' '); - cars = str.split('\n'); - - if (typeof maxWidth !== 'undefined') { - - totalHeight = 0; - for (ii = 0; ii < cars.length; ii++) { - line = ''; - words = cars[ii].split(' '); - for (n = 0; n < words.length; n++) { - testLine = line + words[n] + ' '; - testWidth = this.textWidth(testLine); - if (testWidth > maxWidth) { - line = words[n] + ' '; - totalHeight += p.textLeading(); - } else { - line = testLine; - } - } - } - - if (this._rectMode === constants.CENTER) { - - x -= maxWidth / 2; - y -= maxHeight / 2; - } - - switch (this.drawingContext.textAlign) { - - case constants.CENTER: - x += maxWidth / 2; - break; - case constants.RIGHT: - x += maxWidth; - break; - } - - if (typeof maxHeight !== 'undefined') { - - switch (this.drawingContext.textBaseline) { - case constants.BOTTOM: - y += (maxHeight - totalHeight); - break; - case constants._CTX_MIDDLE: - y += (maxHeight - totalHeight) / 2; - break; - case constants.BASELINE: - baselineHacked = true; - this.drawingContext.textBaseline = constants.TOP; - break; - } - - // remember the max-allowed y-position for any line (fix to #928) - finalMaxHeight = (y + maxHeight) - p.textAscent(); - } - - for (ii = 0; ii < cars.length; ii++) { - - line = ''; - words = cars[ii].split(' '); - for (n = 0; n < words.length; n++) { - testLine = line + words[n] + ' '; - testWidth = this.textWidth(testLine); - if (testWidth > maxWidth && line.length > 0) { - this._renderText(p, line, x, y, finalMaxHeight); - line = words[n] + ' '; - y += p.textLeading(); - } else { - line = testLine; - } - } - - this._renderText(p, line, x, y, finalMaxHeight); - y += p.textLeading(); - } - } - else { - for (jj = 0; jj < cars.length; jj++) { - - this._renderText(p, cars[jj], x, y, finalMaxHeight); - y += p.textLeading(); - } - } - - if (baselineHacked) { - this.drawingContext.textBaseline = constants.BASELINE; - } - - return p; -}; - -p5.Renderer2D.prototype._renderText = function(p, line, x, y, maxY) { - - if (y >= maxY) { - return; // don't render lines beyond our maxY position - } - - p.push(); // fix to #803 - - if (!this._isOpenType()) { // a system/browser font - - // no stroke unless specified by user - if (this._doStroke && this._strokeSet) { - - this.drawingContext.strokeText(line, x, y); - } - - if (this._doFill) { - - // if fill hasn't been set by user, use default text fill - this.drawingContext.fillStyle = this._fillSet ? - this.drawingContext.fillStyle : constants._DEFAULT_TEXT_FILL; - - this.drawingContext.fillText(line, x, y); - } - } - else { // an opentype font, let it handle the rendering - - this._textFont._renderPath(line, x, y, { renderer: this }); - } - - p.pop(); - - return p; -}; - -p5.Renderer2D.prototype.textWidth = function(s) { - - if (this._isOpenType()) { - - return this._textFont._textWidth(s); - } - - return this.drawingContext.measureText(s).width; -}; - -p5.Renderer2D.prototype.textAlign = function(h, v) { - - if (arguments.length) { - - if (h === constants.LEFT || - h === constants.RIGHT || - h === constants.CENTER) { - - this.drawingContext.textAlign = h; - } - - if (v === constants.TOP || - v === constants.BOTTOM || - v === constants.CENTER || - v === constants.BASELINE) { - - if (v === constants.CENTER) { - this.drawingContext.textBaseline = constants._CTX_MIDDLE; - } else { - this.drawingContext.textBaseline = v; - } - } - - return this._pInst; - - } else { - - var valign = this.drawingContext.textBaseline; - - if (valign === constants._CTX_MIDDLE) { - - valign = constants.CENTER; - } - - return { - - horizontal: this.drawingContext.textAlign, - vertical: valign - }; - } -}; - -p5.Renderer2D.prototype._applyTextProperties = function() { - - var font, p = this._pInst; - - this._setProperty('_textAscent', null); - this._setProperty('_textDescent', null); - - font = this._textFont; - - if (this._isOpenType()) { - - font = this._textFont.font.familyName; - this._setProperty('_textStyle', this._textFont.font.styleName); - } - - this.drawingContext.font = this._textStyle + ' ' + - this._textSize + 'px ' + font; - - return p; -}; - - -////////////////////////////////////////////// -// STRUCTURE -////////////////////////////////////////////// - -p5.Renderer2D.prototype.push = function() { - this.drawingContext.save(); -}; - -p5.Renderer2D.prototype.pop = function() { - this.drawingContext.restore(); -}; - -module.exports = p5.Renderer2D; - -},{"../image/filters":65,"./canvas":46,"./constants":47,"./core":48,"./p5.Renderer":54}],56:[function(_dereq_,module,exports){ -/** - * @module Rendering - * @submodule Rendering - * @for p5 - */ - -var p5 = _dereq_('./core'); -var constants = _dereq_('./constants'); -_dereq_('./p5.Graphics'); -_dereq_('./p5.Renderer2D'); -_dereq_('../3d/p5.Renderer3D'); -var defaultId = 'defaultCanvas0'; // this gets set again in createCanvas - -/** - * Creates a canvas element in the document, and sets the dimensions of it - * in pixels. This method should be called only once at the start of setup. - * Calling createCanvas more than once in a sketch will result in very - * unpredicable behavior. If you want more than one drawing canvas - * you could use createGraphics (hidden by default but it can be shown). - * <br><br> - * The system variables width and height are set by the parameters passed - * to this function. If createCanvas() is not used, the window will be - * given a default size of 100x100 pixels. - * - * @method createCanvas - * @param {Number} w width of the canvas - * @param {Number} h height of the canvas - * @param {String} [renderer] 'p2d' | 'webgl' - * @return {Object} canvas generated - * @example - * <div> - * <code> - * function setup() { - * createCanvas(100, 50); - * background(153); - * line(0, 0, width, height); - * } - * </code> - * </div> - */ - -p5.prototype.createCanvas = function(w, h, renderer) { - //optional: renderer, otherwise defaults to p2d - var r = renderer || constants.P2D; - var isDefault, c; - - //4th arg (isDefault) used when called onLoad, - //otherwise hidden to the public api - if(arguments[3]){ - isDefault = - (typeof arguments[3] === 'boolean') ? arguments[3] : false; - } - - if(r === constants.WEBGL){ - c = document.getElementById(defaultId); - if(c){ //if defaultCanvas already exists - c.parentNode.removeChild(c); //replace the existing defaultCanvas - } - c = document.createElement('canvas'); - c.id = defaultId; - } - else { - if (isDefault) { - c = document.createElement('canvas'); - var i = 0; - while (document.getElementById('defaultCanvas'+i)) { - i++; - } - defaultId = 'defaultCanvas'+i; - c.id = defaultId; - } else { // resize the default canvas if new one is created - c = this.canvas; - } - } - - // set to invisible if still in setup (to prevent flashing with manipulate) - if (!this._setupDone) { - c.className += ' p5_hidden'; // tag to show later - c.style.visibility='hidden'; - } - - if (this._userNode) { // user input node case - this._userNode.appendChild(c); - } else { - document.body.appendChild(c); - } - - - - // Init our graphics renderer - //webgl mode - if (r === constants.WEBGL) { - this._setProperty('_renderer', new p5.Renderer3D(c, this, true)); - this._isdefaultGraphics = true; - } - //P2D mode - else { - if (!this._isdefaultGraphics) { - this._setProperty('_renderer', new p5.Renderer2D(c, this, true)); - this._isdefaultGraphics = true; - } - } - this._renderer.resize(w, h); - this._renderer._applyDefaults(); - if (isDefault) { // only push once - this._elements.push(this._renderer); - } - return this._renderer; -}; - -/** - * Resizes the canvas to given width and height. The canvas will be cleared - * and draw will be called immediately, allowing the sketch to re-render itself - * in the resized canvas. - * @method resizeCanvas - * @example - * <div class="norender"><code> - * function setup() { - * createCanvas(windowWidth, windowHeight); - * } - * - * function draw() { - * background(0, 100, 200); - * } - * - * function windowResized() { - * resizeCanvas(windowWidth, windowHeight); - * } - * </code></div> - */ -p5.prototype.resizeCanvas = function (w, h, noRedraw) { - if (this._renderer) { - - // save canvas properties - var props = {}; - for (var key in this.drawingContext) { - var val = this.drawingContext[key]; - if (typeof val !== 'object' && typeof val !== 'function') { - props[key] = val; - } - } - this._renderer.resize(w, h); - // reset canvas properties - for (var savedKey in props) { - this.drawingContext[savedKey] = props[savedKey]; - } - if (!noRedraw) { - this.redraw(); - } - } -}; - - -/** - * Removes the default canvas for a p5 sketch that doesn't - * require a canvas - * @method noCanvas - * @example - * <div> - * <code> - * function setup() { - * noCanvas(); - * } - * </code> - * </div> - */ -p5.prototype.noCanvas = function() { - if (this.canvas) { - this.canvas.parentNode.removeChild(this.canvas); - } -}; - -/** - * Creates and returns a new p5.Renderer object. Use this class if you need - * to draw into an off-screen graphics buffer. The two parameters define the - * width and height in pixels. - * - * @method createGraphics - * @param {Number} w width of the offscreen graphics buffer - * @param {Number} h height of the offscreen graphics buffer - * @param {String} renderer either 'p2d' or 'webgl'. - * undefined defaults to p2d - * @return {Object} offscreen graphics buffer - * @example - * <div> - * <code> - * var pg; - * function setup() { - * createCanvas(100, 100); - * pg = createGraphics(100, 100); - * } - * function draw() { - * background(200); - * pg.background(100); - * pg.noStroke(); - * pg.ellipse(pg.width/2, pg.height/2, 50, 50); - * image(pg, 50, 50); - * image(pg, 0, 0, 50, 50); - * } - * </code> - * </div> - */ -p5.prototype.createGraphics = function(w, h, renderer){ - return new p5.Graphics(w, h, renderer, this); -}; - -/** - * Blends the pixels in the display window according to the defined mode. - * There is a choice of the following modes to blend the source pixels (A) - * with the ones of pixels already in the display window (B): - * <ul> - * <li><code>BLEND</code> - linear interpolation of colours: C = - * A*factor + B. This is the default blending mode.</li> - * <li><code>ADD</code> - sum of A and B</li> - * <li><code>DARKEST</code> - only the darkest colour succeeds: C = - * min(A*factor, B).</li> - * <li><code>LIGHTEST</code> - only the lightest colour succeeds: C = - * max(A*factor, B).</li> - * <li><code>DIFFERENCE</code> - subtract colors from underlying image.</li> - * <li><code>EXCLUSION</code> - similar to <code>DIFFERENCE</code>, but less - * extreme.</li> - * <li><code>MULTIPLY</code> - multiply the colors, result will always be - * darker.</li> - * <li><code>SCREEN</code> - opposite multiply, uses inverse values of the - * colors.</li> - * <li><code>REPLACE</code> - the pixels entirely replace the others and - * don't utilize alpha (transparency) values.</li> - * <li><code>OVERLAY</code> - mix of <code>MULTIPLY</code> and <code>SCREEN - * </code>. Multiplies dark values, and screens light values.</li> - * <li><code>HARD_LIGHT</code> - <code>SCREEN</code> when greater than 50% - * gray, <code>MULTIPLY</code> when lower.</li> - * <li><code>SOFT_LIGHT</code> - mix of <code>DARKEST</code> and - * <code>LIGHTEST</code>. Works like <code>OVERLAY</code>, but not as harsh. - * </li> - * <li><code>DODGE</code> - lightens light tones and increases contrast, - * ignores darks.</li> - * <li><code>BURN</code> - darker areas are applied, increasing contrast, - * ignores lights.</li> - * </ul> - * - * @method blendMode - * @param {String/Constant} mode blend mode to set for canvas - * @example - * <div> - * <code> - * blendMode(LIGHTEST); - * strokeWeight(30); - * stroke(80, 150, 255); - * line(25, 25, 75, 75); - * stroke(255, 50, 50); - * line(75, 25, 25, 75); - * </code> - * </div> - * <div> - * <code> - * blendMode(MULTIPLY); - * strokeWeight(30); - * stroke(80, 150, 255); - * line(25, 25, 75, 75); - * stroke(255, 50, 50); - * line(75, 25, 25, 75); - * </code> - * </div> - */ -p5.prototype.blendMode = function(mode) { - if (mode === constants.BLEND || mode === constants.DARKEST || - mode === constants.LIGHTEST || mode === constants.DIFFERENCE || - mode === constants.MULTIPLY || mode === constants.EXCLUSION || - mode === constants.SCREEN || mode === constants.REPLACE || - mode === constants.OVERLAY || mode === constants.HARD_LIGHT || - mode === constants.SOFT_LIGHT || mode === constants.DODGE || - mode === constants.BURN || mode === constants.ADD || - mode === constants.NORMAL) { - this._renderer.blendMode(mode); - } else { - throw new Error('Mode '+mode+' not recognized.'); - } -}; - -module.exports = p5; - -},{"../3d/p5.Renderer3D":36,"./constants":47,"./core":48,"./p5.Graphics":53,"./p5.Renderer2D":55}],57:[function(_dereq_,module,exports){ - -// requestAnim shim layer by Paul Irish -window.requestAnimationFrame = (function(){ - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(callback, element){ - // should '60' here be framerate? - window.setTimeout(callback, 1000 / 60); - }; -})(); - -// use window.performance() to get max fast and accurate time in milliseconds -window.performance = window.performance || {}; -window.performance.now = (function(){ - var load_date = Date.now(); - return window.performance.now || - window.performance.mozNow || - window.performance.msNow || - window.performance.oNow || - window.performance.webkitNow || - function () { - return Date.now() - load_date; - }; -})(); - -/* -// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ -// http://my.opera.com/emoller/blog/2011/12/20/ -// requestanimationframe-for-smart-er-animating -// requestAnimationFrame polyfill by Erik Möller -// fixes from Paul Irish and Tino Zijdel -(function() { - var lastTime = 0; - var vendors = ['ms', 'moz', 'webkit', 'o']; - for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - window.requestAnimationFrame = - window[vendors[x]+'RequestAnimationFrame']; - window.cancelAnimationFrame = - window[vendors[x]+'CancelAnimationFrame'] || - window[vendors[x]+'CancelRequestAnimationFrame']; - } - - if (!window.requestAnimationFrame) { - window.requestAnimationFrame = function(callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = window.setTimeout(function() - { callback(currTime + timeToCall); }, timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - } - - if (!window.cancelAnimationFrame) { - window.cancelAnimationFrame = function(id) { - clearTimeout(id); - }; - } -}()); -*/ - -/** - * shim for Uint8ClampedArray.slice - * (allows arrayCopy to work with pixels[]) - * with thanks to http://halfpapstudios.com/blog/tag/html5-canvas/ - * Enumerable set to false to protect for...in from - * Uint8ClampedArray.prototype pollution. - */ -(function () { - 'use strict'; - if (typeof Uint8ClampedArray !== 'undefined' && - !Uint8ClampedArray.prototype.slice) { - Object.defineProperty(Uint8ClampedArray.prototype, 'slice', { - value: Array.prototype.slice, - writable: true, configurable: true, enumerable: false - }); - } -}()); - -},{}],58:[function(_dereq_,module,exports){ -/** - * @module Structure - * @submodule Structure - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('./core'); - -p5.prototype.exit = function() { - throw 'exit() not implemented, see remove()'; -}; -/** - * Stops p5.js from continuously executing the code within draw(). - * If loop() is called, the code in draw() begins to run continuously again. - * If using noLoop() in setup(), it should be the last line inside the block. - * <br><br> - * When noLoop() is used, it's not possible to manipulate or access the - * screen inside event handling functions such as mousePressed() or - * keyPressed(). Instead, use those functions to call redraw() or loop(), - * which will run draw(), which can update the screen properly. This means - * that when noLoop() has been called, no drawing can happen, and functions - * like saveFrame() or loadPixels() may not be used. - * <br><br> - * Note that if the sketch is resized, redraw() will be called to update - * the sketch, even after noLoop() has been specified. Otherwise, the sketch - * would enter an odd state until loop() was called. - * - * @method noLoop - * @example - * <div><code> - * function setup() { - * createCanvas(100, 100); - * background(200); - * noLoop(); - * } - - * function draw() { - * line(10, 10, 90, 90); - * } - * </code></div> - * - * <div><code> - * var x = 0; - * function setup() { - * createCanvas(100, 100); - * } - * - * function draw() { - * background(204); - * x = x + 0.1; - * if (x > width) { - * x = 0; - * } - * line(x, 0, x, height); - * } - * - * function mousePressed() { - * noLoop(); - * } - * - * function mouseReleased() { - * loop(); - * } - * </code></div> - */ -p5.prototype.noLoop = function() { - this._loop = false; -}; -/** - * By default, p5.js loops through draw() continuously, executing the code - * within it. However, the draw() loop may be stopped by calling noLoop(). - * In that case, the draw() loop can be resumed with loop(). - * - * @method loop - * @example - * <div><code> - * var x = 0; - * function setup() { - * createCanvas(100, 100); - * noLoop(); - * } - * - * function draw() { - * background(204); - * x = x + 0.1; - * if (x > width) { - * x = 0; - * } - * line(x, 0, x, height); - * } - * - * function mousePressed() { - * loop(); - * } - * - * function mouseReleased() { - * noLoop(); - * } - * </code></div> - */ - -p5.prototype.loop = function() { - this._loop = true; - this._draw(); -}; - -/** - * The push() function saves the current drawing style settings and - * transformations, while pop() restores these settings. Note that these - * functions are always used together. They allow you to change the style - * and transformation settings and later return to what you had. When a new - * state is started with push(), it builds on the current style and transform - * information. The push() and pop() functions can be embedded to provide - * more control. (See the second example for a demonstration.) - * <br><br> - * push() stores information related to the current transformation state - * and style settings controlled by the following functions: fill(), - * stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(), - * imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(), - * textFont(), textMode(), textSize(), textLeading(). - * - * @method push - * @example - * <div> - * <code> - * ellipse(0, 50, 33, 33); // Left circle - * - * push(); // Start a new drawing state - * strokeWeight(10); - * fill(204, 153, 0); - * translate(50, 0); - * ellipse(0, 50, 33, 33); // Middle circle - * pop(); // Restore original state - * - * ellipse(100, 50, 33, 33); // Right circle - * </code> - * </div> - * <div> - * <code> - * ellipse(0, 50, 33, 33); // Left circle - * - * push(); // Start a new drawing state - * strokeWeight(10); - * fill(204, 153, 0); - * ellipse(33, 50, 33, 33); // Left-middle circle - * - * push(); // Start another new drawing state - * stroke(0, 102, 153); - * ellipse(66, 50, 33, 33); // Right-middle circle - * pop(); // Restore previous state - * - * pop(); // Restore original state - * - * ellipse(100, 50, 33, 33); // Right circle - * </code> - * </div> - */ -p5.prototype.push = function () { - this._renderer.push(); - this._styles.push({ - _doStroke: this._renderer._doStroke, - _doFill: this._renderer._doFill, - _tint: this._renderer._tint, - _imageMode: this._renderer._imageMode, - _rectMode: this._renderer._rectMode, - _ellipseMode: this._renderer._ellipseMode, - _colorMode: this._renderer._colorMode, - _textFont: this._renderer._textFont, - _textLeading: this._renderer._textLeading, - _textSize: this._renderer._textSize, - _textStyle: this._renderer._textStyle - }); -}; - -/** - * The push() function saves the current drawing style settings and - * transformations, while pop() restores these settings. Note that these - * functions are always used together. They allow you to change the style - * and transformation settings and later return to what you had. When a new - * state is started with push(), it builds on the current style and transform - * information. The push() and pop() functions can be embedded to provide - * more control. (See the second example for a demonstration.) - * <br><br> - * push() stores information related to the current transformation state - * and style settings controlled by the following functions: fill(), - * stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(), - * imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(), - * textFont(), textMode(), textSize(), textLeading(). - * - * @method pop - * @example - * <div> - * <code> - * ellipse(0, 50, 33, 33); // Left circle - * - * push(); // Start a new drawing state - * translate(50, 0); - * strokeWeight(10); - * fill(204, 153, 0); - * ellipse(0, 50, 33, 33); // Middle circle - * pop(); // Restore original state - * - * ellipse(100, 50, 33, 33); // Right circle - * </code> - * </div> - * <div> - * <code> - * ellipse(0, 50, 33, 33); // Left circle - * - * push(); // Start a new drawing state - * strokeWeight(10); - * fill(204, 153, 0); - * ellipse(33, 50, 33, 33); // Left-middle circle - * - * push(); // Start another new drawing state - * stroke(0, 102, 153); - * ellipse(66, 50, 33, 33); // Right-middle circle - * pop(); // Restore previous state - * - * pop(); // Restore original state - * - * ellipse(100, 50, 33, 33); // Right circle - * </code> - * </div> - */ -p5.prototype.pop = function () { - this._renderer.pop(); - var lastS = this._styles.pop(); - for(var prop in lastS){ - this._renderer[prop] = lastS[prop]; - } -}; - -p5.prototype.pushStyle = function() { - throw new Error('pushStyle() not used, see push()'); -}; - -p5.prototype.popStyle = function() { - throw new Error('popStyle() not used, see pop()'); -}; - -/** - * - * Executes the code within draw() one time. This functions allows the - * program to update the display window only when necessary, for example - * when an event registered by mousePressed() or keyPressed() occurs. - * <br><br> - * In structuring a program, it only makes sense to call redraw() within - * events such as mousePressed(). This is because redraw() does not run - * draw() immediately (it only sets a flag that indicates an update is - * needed). - * <br><br> - * The redraw() function does not work properly when called inside draw(). - * To enable/disable animations, use loop() and noLoop(). - * - * @method redraw - * @example - * <div><code> - * var x = 0; - * - * function setup() { - * createCanvas(100, 100); - * noLoop(); - * } - * - * function draw() { - * background(204); - * line(x, 0, x, height); - * } - * - * function mousePressed() { - * x += 1; - * redraw(); - * } - * </code></div> - */ -p5.prototype.redraw = function () { - var userSetup = this.setup || window.setup; - var userDraw = this.draw || window.draw; - if (typeof userDraw === 'function') { - this.push(); - if (typeof userSetup === 'undefined') { - this.scale(this._pixelDensity, this._pixelDensity); - } - var self = this; - this._registeredMethods.pre.forEach(function (f) { - f.call(self); - }); - userDraw(); - this._registeredMethods.post.forEach(function (f) { - f.call(self); - }); - this.pop(); - } -}; - -p5.prototype.size = function() { - var s = 'size() is not a valid p5 function, to set the size of the '; - s += 'drawing canvas, please use createCanvas() instead'; - throw s; -}; - - -module.exports = p5; - -},{"./core":48}],59:[function(_dereq_,module,exports){ -/** - * @module Transform - * @submodule Transform - * @for p5 - * @requires core - * @requires constants - */ - - -'use strict'; - -var p5 = _dereq_('./core'); -var constants = _dereq_('./constants'); - -/** - * Multiplies the current matrix by the one specified through the parameters. - * This is very slow because it will try to calculate the inverse of the - * transform, so avoid it whenever possible. - * - * @method applyMatrix - * @param {Number} n00 numbers which define the 3x2 matrix to be multiplied - * @param {Number} n01 numbers which define the 3x2 matrix to be multiplied - * @param {Number} n02 numbers which define the 3x2 matrix to be multiplied - * @param {Number} n10 numbers which define the 3x2 matrix to be multiplied - * @param {Number} n11 numbers which define the 3x2 matrix to be multiplied - * @param {Number} n12 numbers which define the 3x2 matrix to be multiplied - * @return {p5} the p5 object - * @example - * <div> - * <code> - * // Example in the works. - * </code> - * </div> - */ -p5.prototype.applyMatrix = function(n00, n01, n02, n10, n11, n12) { - this._renderer.applyMatrix(n00, n01, n02, n10, n11, n12); - return this; -}; - -p5.prototype.popMatrix = function() { - throw new Error('popMatrix() not used, see pop()'); -}; - -p5.prototype.printMatrix = function() { - throw new Error('printMatrix() not implemented'); -}; - -p5.prototype.pushMatrix = function() { - throw new Error('pushMatrix() not used, see push()'); -}; - -/** - * Replaces the current matrix with the identity matrix. - * - * @method resetMatrix - * @return {p5} the p5 object - * @example - * <div> - * <code> - * // Example in the works. - * </code> - * </div> - */ -p5.prototype.resetMatrix = function() { - this._renderer.resetMatrix(); - return this; -}; - -/** - * Rotates a shape the amount specified by the angle parameter. This - * function accounts for angleMode, so angles can be entered in either - * RADIANS or DEGREES. - * <br><br> - * Objects are always rotated around their relative position to the - * origin and positive numbers rotate objects in a clockwise direction. - * Transformations apply to everything that happens after and subsequent - * calls to the function accumulates the effect. For example, calling - * rotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI). - * All tranformations are reset when draw() begins again. - * <br><br> - * Technically, rotate() multiplies the current transformation matrix - * by a rotation matrix. This function can be further controlled by - * the push() and pop(). - * - * @method rotate - * @param {Number} angle the angle of rotation, specified in radians - * or degrees, depending on current angleMode - * @return {p5} the p5 object - * @example - * <div> - * <code> - * translate(width/2, height/2); - * rotate(PI/3.0); - * rect(-26, -26, 52, 52); - * </code> - * </div> - */ -p5.prototype.rotate = function() { - var r = arguments[0]; - if (this._angleMode === constants.DEGREES) { - r = this.radians(r); - } - //in webgl mode - if(arguments.length > 1){ - this._renderer.rotate(r, arguments[1]); - } - else { - this._renderer.rotate(r); - } - return this; -}; - -/** - * [rotateX description] - * @param {[type]} rad [description] - * @return {[type]} [description] - */ -p5.prototype.rotateX = function(rad) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - if (this._renderer.isP3D) { - this._validateParameters( - 'rotateX', - args, - [ - ['Number'] - ] - ); - this._renderer.rotateX(rad); - } else { - throw 'not supported in p2d. Please use webgl mode'; - } - return this; -}; - -/** - * [rotateY description] - * @param {[type]} rad [description] - * @return {[type]} [description] - */ -p5.prototype.rotateY = function(rad) { - if (this._renderer.isP3D) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'rotateY', - args, - [ - ['Number'] - ] - ); - this._renderer.rotateY(rad); - } else { - throw 'not supported in p2d. Please use webgl mode'; - } - return this; -}; - -/** - * [rotateZ description] - * @param {[type]} rad [description] - * @return {[type]} [description] - */ -p5.prototype.rotateZ = function(rad) { - if (this._renderer.isP3D) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'rotateZ', - args, - [ - ['Number'] - ] - ); - this._renderer.rotateZ(rad); - } else { - throw 'not supported in p2d. Please use webgl mode'; - } - return this; -}; - -/** - * Increases or decreases the size of a shape by expanding and contracting - * vertices. Objects always scale from their relative origin to the - * coordinate system. Scale values are specified as decimal percentages. - * For example, the function call scale(2.0) increases the dimension of a - * shape by 200%. - * <br><br> - * Transformations apply to everything that happens after and subsequent - * calls to the function multiply the effect. For example, calling scale(2.0) - * and then scale(1.5) is the same as scale(3.0). If scale() is called - * within draw(), the transformation is reset when the loop begins again. - * <br><br> - * Using this fuction with the z parameter requires using P3D as a - * parameter for size(), as shown in the third example above. This function - * can be further controlled with push() and pop(). - * - * @method scale - * @param {Number | p5.Vector | Array} s - * percent to scale the object, or percentage to - * scale the object in the x-axis if multiple arguments - * are given - * @param {Number} [y] percent to scale the object in the y-axis - * @param {Number} [z] percent to scale the object in the z-axis (webgl only) - * @return {p5} the p5 object - * @example - * <div> - * <code> - * translate(width/2, height/2); - * rotate(PI/3.0); - * rect(-26, -26, 52, 52); - * </code> - * </div> - * - * <div> - * <code> - * rect(30, 20, 50, 50); - * scale(0.5, 1.3); - * rect(30, 20, 50, 50); - * </code> - * </div> - */ -p5.prototype.scale = function() { - var x,y,z; - var args = new Array(arguments.length); - for(var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - if(args[0] instanceof p5.Vector){ - x = args[0].x; - y = args[0].y; - z = args[0].z; - } - else if(args[0] instanceof Array){ - x = args[0][0]; - y = args[0][1]; - z = args[0][2] || 1; - } - else { - if(args.length === 1){ - x = y = z = args[0]; - } - else { - x = args[0]; - y = args[1]; - z = args[2] || 1; - } - } - - if(this._renderer.isP3D){ - this._renderer.scale.call(this._renderer, x,y,z); - } - else { - this._renderer.scale.call(this._renderer, x,y); - } - return this; -}; - -/** - * Shears a shape around the x-axis the amount specified by the angle - * parameter. Angles should be specified in the current angleMode. - * Objects are always sheared around their relative position to the origin - * and positive numbers shear objects in a clockwise direction. - * <br><br> - * Transformations apply to everything that happens after and subsequent - * calls to the function accumulates the effect. For example, calling - * shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI). - * If shearX() is called within the draw(), the transformation is reset when - * the loop begins again. - * <br><br> - * Technically, shearX() multiplies the current transformation matrix by a - * rotation matrix. This function can be further controlled by the - * push() and pop() functions. - * - * @method shearX - * @param {Number} angle angle of shear specified in radians or degrees, - * depending on current angleMode - * @return {p5} the p5 object - * @example - * <div> - * <code> - * translate(width/4, height/4); - * shearX(PI/4.0); - * rect(0, 0, 30, 30); - * </code> - * </div> - */ -p5.prototype.shearX = function(angle) { - if (this._angleMode === constants.DEGREES) { - angle = this.radians(angle); - } - this._renderer.shearX(angle); - return this; -}; - -/** - * Shears a shape around the y-axis the amount specified by the angle - * parameter. Angles should be specified in the current angleMode. Objects - * are always sheared around their relative position to the origin and - * positive numbers shear objects in a clockwise direction. - * <br><br> - * Transformations apply to everything that happens after and subsequent - * calls to the function accumulates the effect. For example, calling - * shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If - * shearY() is called within the draw(), the transformation is reset when - * the loop begins again. - * <br><br> - * Technically, shearY() multiplies the current transformation matrix by a - * rotation matrix. This function can be further controlled by the - * push() and pop() functions. - * - * @method shearY - * @param {Number} angle angle of shear specified in radians or degrees, - * depending on current angleMode - * @return {p5} the p5 object - * @example - * <div> - * <code> - * translate(width/4, height/4); - * shearY(PI/4.0); - * rect(0, 0, 30, 30); - * </code> - * </div> - */ -p5.prototype.shearY = function(angle) { - if (this._angleMode === constants.DEGREES) { - angle = this.radians(angle); - } - this._renderer.shearY(angle); - return this; -}; - -/** - * Specifies an amount to displace objects within the display window. - * The x parameter specifies left/right translation, the y parameter - * specifies up/down translation. - * <br><br> - * Transformations are cumulative and apply to everything that happens after - * and subsequent calls to the function accumulates the effect. For example, - * calling translate(50, 0) and then translate(20, 0) is the same as - * translate(70, 0). If translate() is called within draw(), the - * transformation is reset when the loop begins again. This function can be - * further controlled by using push() and pop(). - * - * @method translate - * @param {Number} x left/right translation - * @param {Number} y up/down translation - * @return {p5} the p5 object - * @example - * <div> - * <code> - * translate(30, 20); - * rect(0, 0, 55, 55); - * </code> - * </div> - * - * <div> - * <code> - * rect(0, 0, 55, 55); // Draw rect at original 0,0 - * translate(30, 20); - * rect(0, 0, 55, 55); // Draw rect at new 0,0 - * translate(14, 14); - * rect(0, 0, 55, 55); // Draw rect at new 0,0 - * </code> - * </div> - */ -p5.prototype.translate = function(x, y, z) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - - if (this._renderer.isP3D) { - this._validateParameters( - 'translate', - args, - [ - //p3d - ['Number', 'Number', 'Number'] - ] - ); - this._renderer.translate(x, y, z); - } else { - this._validateParameters( - 'translate', - args, - [ - //p2d - ['Number', 'Number'] - ] - ); - this._renderer.translate(x, y); - } - return this; -}; - -module.exports = p5; - -},{"./constants":47,"./core":48}],60:[function(_dereq_,module,exports){ -/** - * @module Shape - * @submodule Vertex - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('./core'); -var constants = _dereq_('./constants'); -var shapeKind = null; -var vertices = []; -var contourVertices = []; -var isBezier = false; -var isCurve = false; -var isQuadratic = false; -var isContour = false; - -/** - * Use the beginContour() and endContour() functions to create negative - * shapes within shapes such as the center of the letter 'O'. beginContour() - * begins recording vertices for the shape and endContour() stops recording. - * The vertices that define a negative shape must "wind" in the opposite - * direction from the exterior shape. First draw vertices for the exterior - * clockwise order, then for internal shapes, draw vertices - * shape in counter-clockwise. - * <br><br> - * These functions can only be used within a beginShape()/endShape() pair and - * transformations such as translate(), rotate(), and scale() do not work - * within a beginContour()/endContour() pair. It is also not possible to use - * other shapes, such as ellipse() or rect() within. - * - * @method beginContour - * @return {Object} the p5 object - * @example - * <div> - * <code> - * translate(50, 50); - * stroke(255, 0, 0); - * beginShape(); - * // Exterior part of shape, clockwise winding - * vertex(-40, -40); - * vertex(40, -40); - * vertex(40, 40); - * vertex(-40, 40); - * // Interior part of shape, counter-clockwise winding - * beginContour(); - * vertex(-20, -20); - * vertex(-20, 20); - * vertex(20, 20); - * vertex(20, -20); - * endContour(); - * endShape(CLOSE); - * </code> - * </div> - */ -p5.prototype.beginContour = function() { - contourVertices = []; - isContour = true; - return this; -}; - -/** - * Using the beginShape() and endShape() functions allow creating more - * complex forms. beginShape() begins recording vertices for a shape and - * endShape() stops recording. The value of the kind parameter tells it which - * types of shapes to create from the provided vertices. With no mode - * specified, the shape can be any irregular polygon. - * <br><br> - * The parameters available for beginShape() are POINTS, LINES, TRIANGLES, - * TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the - * beginShape() function, a series of vertex() commands must follow. To stop - * drawing the shape, call endShape(). Each shape will be outlined with the - * current stroke color and filled with the fill color. - * <br><br> - * Transformations such as translate(), rotate(), and scale() do not work - * within beginShape(). It is also not possible to use other shapes, such as - * ellipse() or rect() within beginShape(). - * - * @method beginShape - * @param {Number/Constant} kind either POINTS, LINES, TRIANGLES, - * TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, - * or QUAD_STRIP - * @return {Object} the p5 object - * @example - * <div> - * <code> - * beginShape(); - * vertex(30, 20); - * vertex(85, 20); - * vertex(85, 75); - * vertex(30, 75); - * endShape(CLOSE); - * </code> - * </div> - * - * <div> - * <code> - * // currently not working - * beginShape(POINTS); - * vertex(30, 20); - * vertex(85, 20); - * vertex(85, 75); - * vertex(30, 75); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(LINES); - * vertex(30, 20); - * vertex(85, 20); - * vertex(85, 75); - * vertex(30, 75); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * beginShape(); - * vertex(30, 20); - * vertex(85, 20); - * vertex(85, 75); - * vertex(30, 75); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * beginShape(); - * vertex(30, 20); - * vertex(85, 20); - * vertex(85, 75); - * vertex(30, 75); - * endShape(CLOSE); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(TRIANGLES); - * vertex(30, 75); - * vertex(40, 20); - * vertex(50, 75); - * vertex(60, 20); - * vertex(70, 75); - * vertex(80, 20); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(TRIANGLE_STRIP); - * vertex(30, 75); - * vertex(40, 20); - * vertex(50, 75); - * vertex(60, 20); - * vertex(70, 75); - * vertex(80, 20); - * vertex(90, 75); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(TRIANGLE_FAN); - * vertex(57.5, 50); - * vertex(57.5, 15); - * vertex(92, 50); - * vertex(57.5, 85); - * vertex(22, 50); - * vertex(57.5, 15); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(QUADS); - * vertex(30, 20); - * vertex(30, 75); - * vertex(50, 75); - * vertex(50, 20); - * vertex(65, 20); - * vertex(65, 75); - * vertex(85, 75); - * vertex(85, 20); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(QUAD_STRIP); - * vertex(30, 20); - * vertex(30, 75); - * vertex(50, 20); - * vertex(50, 75); - * vertex(65, 20); - * vertex(65, 75); - * vertex(85, 20); - * vertex(85, 75); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(); - * vertex(20, 20); - * vertex(40, 20); - * vertex(40, 40); - * vertex(60, 40); - * vertex(60, 60); - * vertex(20, 60); - * endShape(CLOSE); - * </code> - * </div> - */ -p5.prototype.beginShape = function(kind) { - if (kind === constants.POINTS || - kind === constants.LINES || - kind === constants.TRIANGLES || - kind === constants.TRIANGLE_FAN || - kind === constants.TRIANGLE_STRIP || - kind === constants.QUADS || - kind === constants.QUAD_STRIP) { - shapeKind = kind; - } else { - shapeKind = null; - } - if(this._renderer.isP3D){ - this._renderer.beginShape(kind); - } else { - vertices = []; - contourVertices = []; - } - return this; -}; - -/** - * Specifies vertex coordinates for Bezier curves. Each call to - * bezierVertex() defines the position of two control points and - * one anchor point of a Bezier curve, adding a new segment to a - * line or shape. - * <br><br> - * The first time bezierVertex() is used within a - * beginShape() call, it must be prefaced with a call to vertex() - * to set the first anchor point. This function must be used between - * beginShape() and endShape() and only when there is no MODE - * parameter specified to beginShape(). - * - * @method bezierVertex - * @param {Number} x2 x-coordinate for the first control point - * @param {Number} y2 y-coordinate for the first control point - * @param {Number} x3 x-coordinate for the second control point - * @param {Number} y3 y-coordinate for the second control point - * @param {Number} x4 x-coordinate for the anchor point - * @param {Number} y4 y-coordinate for the anchor point - * @return {Object} the p5 object - * @example - * <div> - * <code> - * noFill(); - * beginShape(); - * vertex(30, 20); - * bezierVertex(80, 0, 80, 75, 30, 75); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * beginShape(); - * vertex(30, 20); - * bezierVertex(80, 0, 80, 75, 30, 75); - * bezierVertex(50, 80, 60, 25, 30, 20); - * endShape(); - * </code> - * </div> - */ -p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) { - if (vertices.length === 0) { - throw 'vertex() must be used once before calling bezierVertex()'; - } else { - isBezier = true; - var vert = []; - for (var i = 0; i < arguments.length; i++) { - vert[i] = arguments[i]; - } - vert.isVert = false; - if (isContour) { - contourVertices.push(vert); - } else { - vertices.push(vert); - } - } - return this; -}; - -/** - * Specifies vertex coordinates for curves. This function may only - * be used between beginShape() and endShape() and only when there - * is no MODE parameter specified to beginShape(). - * <br><br> - * The first and last points in a series of curveVertex() lines will be used to - * guide the beginning and end of a the curve. A minimum of four - * points is required to draw a tiny curve between the second and - * third points. Adding a fifth point with curveVertex() will draw - * the curve between the second, third, and fourth points. The - * curveVertex() function is an implementation of Catmull-Rom - * splines. - * - * @method curveVertex - * @param {Number} x x-coordinate of the vertex - * @param {Number} y y-coordinate of the vertex - * @return {Object} the p5 object - * @example - * <div> - * <code> - * noFill(); - * beginShape(); - * curveVertex(84, 91); - * curveVertex(84, 91); - * curveVertex(68, 19); - * curveVertex(21, 17); - * curveVertex(32, 100); - * curveVertex(32, 100); - * endShape(); - * </code> - * </div> - */ -p5.prototype.curveVertex = function(x,y) { - isCurve = true; - this.vertex(x, y); - return this; -}; - -/** - * Use the beginContour() and endContour() functions to create negative - * shapes within shapes such as the center of the letter 'O'. beginContour() - * begins recording vertices for the shape and endContour() stops recording. - * The vertices that define a negative shape must "wind" in the opposite - * direction from the exterior shape. First draw vertices for the exterior - * clockwise order, then for internal shapes, draw vertices - * shape in counter-clockwise. - * <br><br> - * These functions can only be used within a beginShape()/endShape() pair and - * transformations such as translate(), rotate(), and scale() do not work - * within a beginContour()/endContour() pair. It is also not possible to use - * other shapes, such as ellipse() or rect() within. - * - * @method endContour - * @return {Object} the p5 object - * @example - * <div> - * <code> - * translate(50, 50); - * stroke(255, 0, 0); - * beginShape(); - * // Exterior part of shape, clockwise winding - * vertex(-40, -40); - * vertex(40, -40); - * vertex(40, 40); - * vertex(-40, 40); - * // Interior part of shape, counter-clockwise winding - * beginContour(); - * vertex(-20, -20); - * vertex(-20, 20); - * vertex(20, 20); - * vertex(20, -20); - * endContour(); - * endShape(CLOSE); - * </code> - * </div> - */ -p5.prototype.endContour = function() { - var vert = contourVertices[0].slice(); // copy all data - vert.isVert = contourVertices[0].isVert; - vert.moveTo = false; - contourVertices.push(vert); - - vertices.push(vertices[0]); - for (var i = 0; i < contourVertices.length; i++) { - vertices.push(contourVertices[i]); - } - return this; -}; - -/** - * The endShape() function is the companion to beginShape() and may only be - * called after beginShape(). When endshape() is called, all of image data - * defined since the previous call to beginShape() is written into the image - * buffer. The constant CLOSE as the value for the MODE parameter to close - * the shape (to connect the beginning and the end). - * - * @method endShape - * @param {Number/Constant} mode use CLOSE to close the shape - * @return {Object} the p5 object - * @example - * <div> - * <code> - * noFill(); - * - * beginShape(); - * vertex(20, 20); - * vertex(45, 20); - * vertex(45, 80); - * endShape(CLOSE); - * - * beginShape(); - * vertex(50, 20); - * vertex(75, 20); - * vertex(75, 80); - * endShape(); - * </code> - * </div> - */ -p5.prototype.endShape = function(mode) { - if(this._renderer.isP3D){ - this._renderer.endShape(); - }else{ - if (vertices.length === 0) { return this; } - if (!this._renderer._doStroke && !this._renderer._doFill) { return this; } - - var closeShape = mode === constants.CLOSE; - - // if the shape is closed, the first element is also the last element - if (closeShape && !isContour) { - vertices.push(vertices[0]); - } - - this._renderer.endShape(mode, vertices, isCurve, isBezier, - isQuadratic, isContour, shapeKind); - - // Reset some settings - isCurve = false; - isBezier = false; - isQuadratic = false; - isContour = false; - - // If the shape is closed, the first element was added as last element. - // We must remove it again to prevent the list of vertices from growing - // over successive calls to endShape(CLOSE) - if (closeShape) { - vertices.pop(); - } - } - return this; -}; - -/** - * Specifies vertex coordinates for quadratic Bezier curves. Each call to - * quadraticVertex() defines the position of one control points and one - * anchor point of a Bezier curve, adding a new segment to a line or shape. - * The first time quadraticVertex() is used within a beginShape() call, it - * must be prefaced with a call to vertex() to set the first anchor point. - * This function must be used between beginShape() and endShape() and only - * when there is no MODE parameter specified to beginShape(). - * - * @method quadraticVertex - * @param {Number} cx x-coordinate for the control point - * @param {Number} cy y-coordinate for the control point - * @param {Number} x3 x-coordinate for the anchor point - * @param {Number} y3 y-coordinate for the anchor point - * @return {Object} the p5 object - * @example - * <div> - * <code> - * noFill(); - * strokeWeight(4); - * beginShape(); - * vertex(20, 20); - * quadraticVertex(80, 20, 50, 50); - * endShape(); - * </code> - * </div> - * - * <div> - * <code> - * noFill(); - * strokeWeight(4); - * beginShape(); - * vertex(20, 20); - * quadraticVertex(80, 20, 50, 50); - * quadraticVertex(20, 80, 80, 80); - * vertex(80, 60); - * endShape(); - * </code> - * </div> - */ -p5.prototype.quadraticVertex = function(cx, cy, x3, y3) { - //if we're drawing a contour, put the points into an - // array for inside drawing - if(this._contourInited) { - var pt = {}; - pt.x = cx; - pt.y = cy; - pt.x3 = x3; - pt.y3 = y3; - pt.type = constants.QUADRATIC; - this._contourVertices.push(pt); - - return this; - } - if (vertices.length > 0) { - isQuadratic = true; - var vert = []; - for (var i = 0; i < arguments.length; i++) { - vert[i] = arguments[i]; - } - vert.isVert = false; - if (isContour) { - contourVertices.push(vert); - } else { - vertices.push(vert); - } - } else { - throw 'vertex() must be used once before calling quadraticVertex()'; - } - return this; -}; - -/** - * All shapes are constructed by connecting a series of vertices. vertex() - * is used to specify the vertex coordinates for points, lines, triangles, - * quads, and polygons. It is used exclusively within the beginShape() and - * endShape() functions. - * - * @method vertex - * @param {Number} x x-coordinate of the vertex - * @param {Number} y y-coordinate of the vertex - * @return {Object} the p5 object - * @example - * <div> - * <code> - * beginShape(POINTS); - * vertex(30, 20); - * vertex(85, 20); - * vertex(85, 75); - * vertex(30, 75); - * endShape(); - * </code> - * </div> - */ -p5.prototype.vertex = function(x, y, moveTo) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - if(this._renderer.isP3D){ - this._validateParameters( - 'vertex', - args, - [ - ['Number', 'Number', 'Number'] - ] - ); - this._renderer.vertex - (arguments[0], arguments[1], arguments[2]); - }else{ - this._validateParameters( - 'vertex', - args, - [ - ['Number', 'Number'], - ['Number', 'Number', 'Number'] - ] - ); - var vert = []; - vert.isVert = true; - vert[0] = x; - vert[1] = y; - vert[2] = 0; - vert[3] = 0; - vert[4] = 0; - vert[5] = this._renderer._getFill(); - vert[6] = this._renderer._getStroke(); - - if (moveTo) { - vert.moveTo = moveTo; - } - if (isContour) { - if (contourVertices.length === 0) { - vert.moveTo = true; - } - contourVertices.push(vert); - } else { - vertices.push(vert); - } - } - return this; -}; - -module.exports = p5; - -},{"./constants":47,"./core":48}],61:[function(_dereq_,module,exports){ -/** - * @module Events - * @submodule Acceleration - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * The system variable deviceOrientation always contains the orientation of - * the device. The value of this variable will either be set 'landscape' - * or 'portrait'. If no data is available it will be set to 'undefined'. - * - * @property deviceOrientation - */ -p5.prototype.deviceOrientation = undefined; - -/** - * The system variable accelerationX always contains the acceleration of the - * device along the x axis. Value is represented as meters per second squared. - * - * @property accelerationX - */ -p5.prototype.accelerationX = 0; - -/** - * The system variable accelerationY always contains the acceleration of the - * device along the y axis. Value is represented as meters per second squared. - * - * @property accelerationY - */ -p5.prototype.accelerationY = 0; - -/** - * The system variable accelerationZ always contains the acceleration of the - * device along the z axis. Value is represented as meters per second squared. - * - * @property accelerationZ - */ -p5.prototype.accelerationZ = 0; - -/** - * The system variable pAccelerationX always contains the acceleration of the - * device along the x axis in the frame previous to the current frame. Value - * is represented as meters per second squared. - * - * @property pAccelerationX - */ -p5.prototype.pAccelerationX = 0; - -/** - * The system variable pAccelerationY always contains the acceleration of the - * device along the y axis in the frame previous to the current frame. Value - * is represented as meters per second squared. - * - * @property pAccelerationY - */ -p5.prototype.pAccelerationY = 0; - -/** - * The system variable pAccelerationZ always contains the acceleration of the - * device along the z axis in the frame previous to the current frame. Value - * is represented as meters per second squared. - * - * @property pAccelerationZ - */ -p5.prototype.pAccelerationZ = 0; - -/** - * _updatePAccelerations updates the pAcceleration values - * - * @private - */ -p5.prototype._updatePAccelerations = function(){ - this._setProperty('pAccelerationX', this.accelerationX); - this._setProperty('pAccelerationY', this.accelerationY); - this._setProperty('pAccelerationZ', this.accelerationZ); -}; - -/** - * The system variable rotationX always contains the rotation of the - * device along the x axis. Value is represented as 0 to +/-180 degrees. - * <br><br> - * Note: The order the rotations are called is important, ie. if used - * together, it must be called in the order Z-X-Y or there might be - * unexpected behaviour. - * - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * //rotateZ(radians(rotationZ)); - * rotateX(radians(rotationX)); - * //rotateY(radians(rotationY)); - * box(200, 200, 200); - * } - * </code> - * </div> - * - * @property rotationX - */ -p5.prototype.rotationX = 0; - -/** - * The system variable rotationY always contains the rotation of the - * device along the y axis. Value is represented as 0 to +/-90 degrees. - * <br><br> - * Note: The order the rotations are called is important, ie. if used - * together, it must be called in the order Z-X-Y or there might be - * unexpected behaviour. - * - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * //rotateZ(radians(rotationZ)); - * //rotateX(radians(rotationX)); - * rotateY(radians(rotationY)); - * box(200, 200, 200); - * } - * </code> - * </div> - * - * @property rotationY - */ -p5.prototype.rotationY = 0; - -/** - * The system variable rotationZ always contains the rotation of the - * device along the z axis. Value is represented as 0 to 359 degrees. - * <br><br> - * Unlike rotationX and rotationY, this variable is available for devices - * with a built-in compass only. - * <br><br> - * Note: The order the rotations are called is important, ie. if used - * together, it must be called in the order Z-X-Y or there might be - * unexpected behaviour. - * - * @example - * <div> - * <code> - * function setup(){ - * createCanvas(100, 100, WEBGL); - * } - * - * function draw(){ - * background(200); - * rotateZ(radians(rotationZ)); - * //rotateX(radians(rotationX)); - * //rotateY(radians(rotationY)); - * box(200, 200, 200); - * } - * </code> - * </div> - * - * @property rotationZ - */ -p5.prototype.rotationZ = 0; - -/** - * The system variable pRotationX always contains the rotation of the - * device along the x axis in the frame previous to the current frame. Value - * is represented as 0 to +/-180 degrees. - * <br><br> - * pRotationX can also be used with rotationX to determine the rotate - * direction of the device along the X-axis. - * @example - * <div class='norender'> - * <code> - * // A simple if statement looking at whether - * // rotationX - pRotationX < 0 is true or not will be - * // sufficient for determining the rotate direction - * // in most cases. - * - * // Some extra logic is needed to account for cases where - * // the angles wrap around. - * var rotateDirection = 'clockwise'; - * - * // Simple range conversion to make things simpler. - * // This is not absolutely neccessary but the logic - * // will be different in that case. - * - * var rX = rotationX + 180; - * var pRX = pRotationX + 180; - * - * if ((rX - pRX > 0 && rX - pRX < 270)|| rX - pRX < -270){ - * rotateDirection = 'clockwise'; - * } else if (rX - pRX < 0 || rX - pRX > 270){ - * rotateDirection = 'counter-clockwise'; - * } - * </code> - * </div> - * - * @property pRotationX - */ -p5.prototype.pRotationX = 0; - -/** - * The system variable pRotationY always contains the rotation of the - * device along the y axis in the frame previous to the current frame. Value - * is represented as 0 to +/-90 degrees. - * <br><br> - * pRotationY can also be used with rotationY to determine the rotate - * direction of the device along the Y-axis. - * @example - * <div class='norender'> - * <code> - * // A simple if statement looking at whether - * // rotationY - pRotationY < 0 is true or not will be - * // sufficient for determining the rotate direction - * // in most cases. - * - * // Some extra logic is needed to account for cases where - * // the angles wrap around. - * var rotateDirection = 'clockwise'; - * - * // Simple range conversion to make things simpler. - * // This is not absolutely neccessary but the logic - * // will be different in that case. - * - * var rY = rotationY + 180; - * var pRY = pRotationY + 180; - * - * if ((rY - pRY > 0 && rY - pRY < 270)|| rY - pRY < -270){ - * rotateDirection = 'clockwise'; - * } else if (rY - pRY < 0 || rY - pRY > 270){ - * rotateDirection = 'counter-clockwise'; - * } - * </code> - * </div> - * - * @property pRotationY - */ -p5.prototype.pRotationY = 0; - -/** - * The system variable pRotationZ always contains the rotation of the - * device along the z axis in the frame previous to the current frame. Value - * is represented as 0 to 359 degrees. - * <br><br> - * pRotationZ can also be used with rotationZ to determine the rotate - * direction of the device along the Z-axis. - * @example - * <div class='norender'> - * <code> - * // A simple if statement looking at whether - * // rotationZ - pRotationZ < 0 is true or not will be - * // sufficient for determining the rotate direction - * // in most cases. - * - * // Some extra logic is needed to account for cases where - * // the angles wrap around. - * var rotateDirection = 'clockwise'; - * - * if ((rotationZ - pRotationZ > 0 && - * rotationZ - pRotationZ < 270)|| - * rotationZ - pRotationZ < -270){ - * - * rotateDirection = 'clockwise'; - * - * } else if (rotationZ - pRotationZ < 0 || - * rotationZ - pRotationZ > 270){ - * - * rotateDirection = 'counter-clockwise'; - * - * } - * </code> - * </div> - * - * @property pRotationZ - */ -p5.prototype.pRotationZ = 0; - -var startAngleX = 0; -var startAngleY = 0; -var startAngleZ = 0; - -var rotateDirectionX = 'clockwise'; -var rotateDirectionY = 'clockwise'; -var rotateDirectionZ = 'clockwise'; - -var pRotateDirectionX; -var pRotateDirectionY; -var pRotateDirectionZ; - -p5.prototype._updatePRotations = function(){ - this._setProperty('pRotationX', this.rotationX); - this._setProperty('pRotationY', this.rotationY); - this._setProperty('pRotationZ', this.rotationZ); -}; - -p5.prototype.turnAxis = undefined; - -var move_threshold = 0.5; -var shake_threshold = 30; - -/** - * The setMoveThreshold() function is used to set the movement threshold for - * the deviceMoved() function. The default threshold is set to 0.5. - * - * @method setMoveThreshold - * @param {number} value The threshold value - */ -p5.prototype.setMoveThreshold = function(val){ - if(typeof val === 'number'){ - move_threshold = val; - } -}; - -/** - * The setShakeThreshold() function is used to set the movement threshold for - * the deviceShaken() function. The default threshold is set to 30. - * - * @method setShakeThreshold - * @param {number} value The threshold value - */ -p5.prototype.setShakeThreshold = function(val){ - if(typeof val === 'number'){ - shake_threshold = val; - } -}; - -/** - * The deviceMoved() function is called when the device is moved by more than - * the threshold value along X, Y or Z axis. The default threshold is set to - * 0.5. - * @method deviceMoved - * @example - * <div> - * <code> - * // Run this example on a mobile device - * // Move the device around - * // to change the value. - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function deviceMoved() { - * value = value + 5; - * if (value > 255) { - * value = 0; - * } - * } - * </code> - * </div> - */ - -/** - * The deviceTurned() function is called when the device rotates by - * more than 90 degrees continuously. - * <br><br> - * The axis that triggers the deviceTurned() method is stored in the turnAxis - * variable. The deviceTurned() method can be locked to trigger on any axis: - * X, Y or Z by comparing the turnAxis variable to 'X', 'Y' or 'Z'. - * - * @method deviceTurned - * @example - * <div> - * <code> - * // Run this example on a mobile device - * // Rotate the device by 90 degrees - * // to change the value. - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function deviceTurned() { - * if (value == 0){ - * value = 255 - * } else if (value == 255) { - * value = 0; - * } - * } - * </code> - * </div> - * <div> - * <code> - * // Run this example on a mobile device - * // Rotate the device by 90 degrees in the - * // X-axis to change the value. - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function deviceTurned() { - * if (turnAxis == 'X'){ - * if (value == 0){ - * value = 255 - * } else if (value == 255) { - * value = 0; - * } - * } - * } - * </code> - * </div> - */ - -/** - * The deviceShaken() function is called when the device total acceleration - * changes of accelerationX and accelerationY values is more than - * the threshold value. The default threshold is set to 30. - * @method deviceShaken - * @example - * <div> - * <code> - * // Run this example on a mobile device - * // Shake the device to change the value. - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function deviceShaken() { - * value = value + 5; - * if (value > 255) { - * value = 0; - * } - * } - * </code> - * </div> - */ - -p5.prototype._ondeviceorientation = function (e) { - this._updatePRotations(); - this._setProperty('rotationX', e.beta); - this._setProperty('rotationY', e.gamma); - this._setProperty('rotationZ', e.alpha); - this._handleMotion(); -}; -p5.prototype._ondevicemotion = function (e) { - this._updatePAccelerations(); - this._setProperty('accelerationX', e.acceleration.x * 2); - this._setProperty('accelerationY', e.acceleration.y * 2); - this._setProperty('accelerationZ', e.acceleration.z * 2); - this._handleMotion(); -}; -p5.prototype._handleMotion = function() { - if (window.orientation === 90 || window.orientation === -90) { - this._setProperty('deviceOrientation', 'landscape'); - } else if (window.orientation === 0) { - this._setProperty('deviceOrientation', 'portrait'); - } else if (window.orientation === undefined) { - this._setProperty('deviceOrientation', 'undefined'); - } - var deviceMoved = this.deviceMoved || window.deviceMoved; - if (typeof deviceMoved === 'function') { - if (Math.abs(this.accelerationX - this.pAccelerationX) > move_threshold || - Math.abs(this.accelerationY - this.pAccelerationY) > move_threshold || - Math.abs(this.accelerationZ - this.pAccelerationZ) > move_threshold) { - deviceMoved(); - } - } - var deviceTurned = this.deviceTurned || window.deviceTurned; - if (typeof deviceTurned === 'function') { - // The angles given by rotationX etc is from range -180 to 180. - // The following will convert them to 0 to 360 for ease of calculation - // of cases when the angles wrapped around. - // _startAngleX will be converted back at the end and updated. - var wRX = this.rotationX + 180; - var wPRX = this.pRotationX + 180; - var wSAX = startAngleX + 180; - if ((wRX - wPRX > 0 && wRX - wPRX < 270)|| wRX - wPRX < -270){ - rotateDirectionX = 'clockwise'; - } else if (wRX - wPRX < 0 || wRX - wPRX > 270){ - rotateDirectionX = 'counter-clockwise'; - } - if (rotateDirectionX !== pRotateDirectionX){ - wSAX = wRX; - } - if (Math.abs(wRX - wSAX) > 90 && Math.abs(wRX - wSAX) < 270){ - wSAX = wRX; - this._setProperty('turnAxis', 'X'); - deviceTurned(); - } - pRotateDirectionX = rotateDirectionX; - startAngleX = wSAX - 180; - - // Y-axis is identical to X-axis except for changing some names. - var wRY = this.rotationY + 180; - var wPRY = this.pRotationY + 180; - var wSAY = startAngleY + 180; - if ((wRY - wPRY > 0 && wRY - wPRY < 270)|| wRY - wPRY < -270){ - rotateDirectionY = 'clockwise'; - } else if (wRY - wPRY < 0 || wRY - this.pRotationY > 270){ - rotateDirectionY = 'counter-clockwise'; - } - if (rotateDirectionY !== pRotateDirectionY){ - wSAY = wRY; - } - if (Math.abs(wRY - wSAY) > 90 && Math.abs(wRY - wSAY) < 270){ - wSAY = wRY; - this._setProperty('turnAxis', 'Y'); - deviceTurned(); - } - pRotateDirectionY = rotateDirectionY; - startAngleY = wSAY - 180; - - // Z-axis is already in the range 0 to 360 - // so no conversion is needed. - if ((this.rotationZ - this.pRotationZ > 0 && - this.rotationZ - this.pRotationZ < 270)|| - this.rotationZ - this.pRotationZ < -270){ - rotateDirectionZ = 'clockwise'; - } else if (this.rotationZ - this.pRotationZ < 0 || - this.rotationZ - this.pRotationZ > 270){ - rotateDirectionZ = 'counter-clockwise'; - } - if (rotateDirectionZ !== pRotateDirectionZ){ - startAngleZ = this.rotationZ; - } - if (Math.abs(this.rotationZ - startAngleZ) > 90 && - Math.abs(this.rotationZ - startAngleZ) < 270){ - startAngleZ = this.rotationZ; - this._setProperty('turnAxis', 'Z'); - deviceTurned(); - } - pRotateDirectionZ = rotateDirectionZ; - this._setProperty('turnAxis', undefined); - } - var deviceShaken = this.deviceShaken || window.deviceShaken; - if (typeof deviceShaken === 'function') { - var accelerationChangeX; - var accelerationChangeY; - // Add accelerationChangeZ if acceleration change on Z is needed - if (this.pAccelerationX !== null) { - accelerationChangeX = Math.abs(this.accelerationX - this.pAccelerationX); - accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY); - } - if (accelerationChangeX + accelerationChangeY > shake_threshold) { - deviceShaken(); - } - } -}; - - -module.exports = p5; - -},{"../core/core":48}],62:[function(_dereq_,module,exports){ -/** - * @module Events - * @submodule Keyboard - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Holds the key codes of currently pressed keys. - * @private - */ -var downKeys = {}; - -/** - * The boolean system variable keyIsPressed is true if any key is pressed - * and false if no keys are pressed. - * - * @property keyIsPressed - * @example - * <div> - * <code> - * var value = 0; - * function draw() { - * if (keyIsPressed === true) { - * fill(0); - * } else { - * fill(255); - * } - * rect(25, 25, 50, 50); - * } - * </code> - * </div> - */ -p5.prototype.isKeyPressed = false; -p5.prototype.keyIsPressed = false; // khan - -/** - * The system variable key always contains the value of the most recent - * key on the keyboard that was typed. To get the proper capitalization, it - * is best to use it within keyTyped(). For non-ASCII keys, use the keyCode - * variable. - * - * @property key - * @example - * <div><code> - * // Click any key to display it! - * // (Not Guaranteed to be Case Sensitive) - * function setup() { - * fill(245, 123, 158); - * textSize(50); - * } - * - * function draw() { - * background(200); - * text(key, 33,65); // Display last key pressed. - * } - * </div></code> - */ -p5.prototype.key = ''; - -/** - * The variable keyCode is used to detect special keys such as BACKSPACE, - * DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, OPTION, ALT, UP_ARROW, - * DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW. - * - * @property keyCode - * @example - * <div><code> - * var fillVal = 126; - * function draw() { - * fill(fillVal); - * rect(25, 25, 50, 50); - * } - * - * function keyPressed() { - * if (keyCode == UP_ARROW) { - * fillVal = 255; - * } else if (keyCode == DOWN_ARROW) { - * fillVal = 0; - * } - * return false; // prevent default - * } - * </code></div> - */ -p5.prototype.keyCode = 0; - -/** - * The keyPressed() function is called once every time a key is pressed. The - * keyCode for the key that was pressed is stored in the keyCode variable. - * <br><br> - * For non-ASCII keys, use the keyCode variable. You can check if the keyCode - * equals BACKSPACE, DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, - * OPTION, ALT, UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW. - * <br><br> - * For ASCII keys that was pressed is stored in the key variable. However, it - * does not distinguish between uppercase and lowercase. For this reason, it - * is recommended to use keyTyped() to read the key variable, in which the - * case of the variable will be distinguished. - * <br><br> - * Because of how operating systems handle key repeats, holding down a key - * may cause multiple calls to keyTyped() (and keyReleased() as well). The - * rate of repeat is set by the operating system and how each computer is - * configured.<br><br> - * Browsers may have different default - * behaviors attached to various key events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * @method keyPressed - * @example - * <div> - * <code> - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function keyPressed() { - * if (value === 0) { - * value = 255; - * } else { - * value = 0; - * } - * } - * </code> - * </div> - * <div> - * <code> - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function keyPressed() { - * if (keyCode === LEFT_ARROW) { - * value = 255; - * } else if (keyCode === RIGHT_ARROW) { - * value = 0; - * } - * } - * </code> - * </div> - * <div class="norender"> - * <code> - * function keyPressed(){ - * // Do something - * return false; // prevent any default behaviour - * } - * </code> - * </div> - */ -p5.prototype._onkeydown = function (e) { - if (downKeys[e.which]) { // prevent multiple firings - return; - } - this._setProperty('isKeyPressed', true); - this._setProperty('keyIsPressed', true); - this._setProperty('keyCode', e.which); - downKeys[e.which] = true; - var key = String.fromCharCode(e.which); - if (!key) { - key = e.which; - } - this._setProperty('key', key); - var keyPressed = this.keyPressed || window.keyPressed; - if (typeof keyPressed === 'function' && !e.charCode) { - var executeDefault = keyPressed(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; -/** - * The keyReleased() function is called once every time a key is released. - * See key and keyCode for more information.<br><br> - * Browsers may have different default - * behaviors attached to various key events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * @method keyReleased - * @example - * <div> - * <code> - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function keyReleased() { - * if (value === 0) { - * value = 255; - * } else { - * value = 0; - * } - * return false; // prevent any default behavior - * } - * </code> - * </div> - */ -p5.prototype._onkeyup = function (e) { - var keyReleased = this.keyReleased || window.keyReleased; - this._setProperty('isKeyPressed', false); - this._setProperty('keyIsPressed', false); - this._setProperty('_lastKeyCodeTyped', null); - downKeys[e.which] = false; - //delete this._downKeys[e.which]; - var key = String.fromCharCode(e.which); - if (!key) { - key = e.which; - } - this._setProperty('key', key); - this._setProperty('keyCode', e.which); - if (typeof keyReleased === 'function') { - var executeDefault = keyReleased(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -/** - * The keyTyped() function is called once every time a key is pressed, but - * action keys such as Ctrl, Shift, and Alt are ignored. The most recent - * key pressed will be stored in the key variable. - * <br><br> - * Because of how operating systems handle key repeats, holding down a key - * will cause multiple calls to keyTyped() (and keyReleased() as well). The - * rate of repeat is set by the operating system and how each computer is - * configured.<br><br> - * Browsers may have different default behaviors attached to various key - * events. To prevent any default behavior for this event, add "return false" - * to the end of the method. - * - * @method keyTyped - * @example - * <div> - * <code> - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function keyTyped() { - * if (key === 'a') { - * value = 255; - * } else if (key === 'b') { - * value = 0; - * } - * return false; // prevent any default behavior - * } - * </code> - * </div> - */ -p5.prototype._onkeypress = function (e) { - if (e.which === this._lastKeyCodeTyped) { // prevent multiple firings - return; - } - this._setProperty('keyCode', e.which); - this._setProperty('_lastKeyCodeTyped', e.which); // track last keyCode - this._setProperty('key', String.fromCharCode(e.which)); - var keyTyped = this.keyTyped || window.keyTyped; - if (typeof keyTyped === 'function') { - var executeDefault = keyTyped(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; -/** - * The onblur function is called when the user is no longer focused - * on the p5 element. Because the keyup events will not fire if the user is - * not focused on the element we must assume all keys currently down have - * been released. - */ -p5.prototype._onblur = function (e) { - downKeys = {}; -}; - -/** - * The keyIsDown() function checks if the key is currently down, i.e. pressed. - * It can be used if you have an object that moves, and you want several keys - * to be able to affect its behaviour simultaneously, such as moving a - * sprite diagonally. You can put in any number representing the keyCode of - * the key, or use any of the variable keyCode names listed - * <a href="http://p5js.org/reference/#p5/keyCode">here</a>. - * - * @method keyIsDown - * @param {Number} code The key to check for. - * @return {Boolean} whether key is down or not - * @example - * <div><code> - * var x = 100; - * var y = 100; - * - * function setup() { - * createCanvas(512, 512); - * } - * - * function draw() { - * if (keyIsDown(LEFT_ARROW)) - * x-=5; - * - * if (keyIsDown(RIGHT_ARROW)) - * x+=5; - * - * if (keyIsDown(UP_ARROW)) - * y-=5; - * - * if (keyIsDown(DOWN_ARROW)) - * y+=5; - * - * clear(); - * fill(255, 0, 0); - * ellipse(x, y, 50, 50); - * } - * </code></div> - */ -p5.prototype.keyIsDown = function(code) { - return downKeys[code]; -}; - -module.exports = p5; - -},{"../core/core":48}],63:[function(_dereq_,module,exports){ -/** - * @module Events - * @submodule Mouse - * @for p5 - * @requires core - * @requires constants - */ - - -'use strict'; - -var p5 = _dereq_('../core/core'); -var constants = _dereq_('../core/constants'); - -/* - * These are helper vars that store the mouseX and mouseY vals - * between the time that a mouse event happens and the next frame - * of draw. This is done to deal with the asynchronicity of event - * calls interacting with the draw loop. When a mouse event occurs - * the _nextMouseX/Y vars are updated, then on each call of draw, mouseX/Y - * and pmouseX/Y are updated using the _nextMouseX/Y vals. - */ -p5.prototype._nextMouseX = 0; -p5.prototype._nextMouseY = 0; - -/** - * The system variable mouseX always contains the current horizontal - * position of the mouse, relative to (0, 0) of the canvas. - * - * @property mouseX - * - * @example - * <div> - * <code> - * // Move the mouse across the canvas - * function draw() { - * background(244, 248, 252); - * line(mouseX, 0, mouseX, 100); - * } - * </code> - * </div> - */ -p5.prototype.mouseX = 0; - -/** - * The system variable mouseY always contains the current vertical position - * of the mouse, relative to (0, 0) of the canvas. - * - * @property mouseY - * - * @example - * <div> - * <code> - * // Move the mouse across the canvas - * function draw() { - * background(244, 248, 252); - * line(0, mouseY, 100, mouseY); - *} - * </code> - * </div> - */ -p5.prototype.mouseY = 0; - -/** - * The system variable pmouseX always contains the horizontal position of - * the mouse in the frame previous to the current frame, relative to (0, 0) - * of the canvas. - * - * @property pmouseX - * - * @example - * <div> - * <code> - * // Move the mouse across the canvas to leave a trail - * function setup() { - * //slow down the frameRate to make it more visible - * frameRate(10); - * } - * - * function draw() { - * background(244, 248, 252); - * line(mouseX, mouseY, pmouseX, pmouseY); - * print(pmouseX + " -> " + mouseX); - * } - * - * </code> - * </div> - */ -p5.prototype.pmouseX = 0; - -/** - * The system variable pmouseY always contains the vertical position of the - * mouse in the frame previous to the current frame, relative to (0, 0) of - * the canvas. - * - * @property pmouseY - * - * @example - * <div> - * <code> - * function draw() { - * background(237, 34, 93); - * fill(0); - * //draw a square only if the mouse is not moving - * if(mouseY == pmouseY && mouseX == pmouseX) - * rect(20,20,60,60); - * - * print(pmouseY + " -> " + mouseY); - * } - * - * </code> - * </div> - */ -p5.prototype.pmouseY = 0; - -/** - * The system variable winMouseX always contains the current horizontal - * position of the mouse, relative to (0, 0) of the window. - * - * @property winMouseX - * - * @example - * <div> - * <code> - * var myCanvas; - * - * function setup() { - * //use a variable to store a pointer to the canvas - * myCanvas = createCanvas(100, 100); - * } - * - * function draw() { - * background(237, 34, 93); - * fill(0); - * - * //move the canvas to the horizontal mouse position - * //relative to the window - * myCanvas.position(winMouseX+1, windowHeight/2); - * - * //the y of the square is relative to the canvas - * rect(20,mouseY,60,60); - * } - * - * </code> - * </div> - */ -p5.prototype.winMouseX = 0; - -/** - * The system variable winMouseY always contains the current vertical - * position of the mouse, relative to (0, 0) of the window. - * - * @property winMouseY - * - * @example - * <div> - * <code> - *var myCanvas; - * - * function setup() { - * //use a variable to store a pointer to the canvas - * myCanvas = createCanvas(100, 100); - * } - * - * function draw() { - * background(237, 34, 93); - * fill(0); - * - * //move the canvas to the vertical mouse position - * //relative to the window - * myCanvas.position(windowWidth/2, winMouseY+1); - * - * //the x of the square is relative to the canvas - * rect(mouseX,20,60,60); - * } - * - * </code> - * </div> - */ -p5.prototype.winMouseY = 0; - -/** - * The system variable pwinMouseX always contains the horizontal position - * of the mouse in the frame previous to the current frame, relative to - * (0, 0) of the window. - * - * @property pwinMouseX - * - * @example - * <div> - * <code> - * - * var myCanvas; - * - * function setup() { - * //use a variable to store a pointer to the canvas - * myCanvas = createCanvas(100, 100); - * noStroke(); - * fill(237, 34, 93); - * } - * - * function draw() { - * clear(); - * //the difference between previous and - * //current x position is the horizontal mouse speed - * var speed = abs(winMouseX-pwinMouseX); - * //change the size of the circle - * //according to the horizontal speed - * ellipse(50, 50, 10+speed*5, 10+speed*5); - * //move the canvas to the mouse position - * myCanvas.position( winMouseX+1, winMouseY+1); - * } - * - * </code> - * </div> - */ -p5.prototype.pwinMouseX = 0; - -/** - * The system variable pwinMouseY always contains the vertical position of - * the mouse in the frame previous to the current frame, relative to (0, 0) - * of the window. - * - * @property pwinMouseY - * - * - * @example - * <div> - * <code> - * - * var myCanvas; - * - * function setup() { - * //use a variable to store a pointer to the canvas - * myCanvas = createCanvas(100, 100); - * noStroke(); - * fill(237, 34, 93); - * } - * - * function draw() { - * clear(); - * //the difference between previous and - * //current y position is the vertical mouse speed - * var speed = abs(winMouseY-pwinMouseY); - * //change the size of the circle - * //according to the vertical speed - * ellipse(50, 50, 10+speed*5, 10+speed*5); - * //move the canvas to the mouse position - * myCanvas.position( winMouseX+1, winMouseY+1); - * } - * - * </code> - * </div> - */ -p5.prototype.pwinMouseY = 0; - -/** - * Processing automatically tracks if the mouse button is pressed and which - * button is pressed. The value of the system variable mouseButton is either - * LEFT, RIGHT, or CENTER depending on which button was pressed last. - * Warning: different browsers may track mouseButton differently. - * - * @property mouseButton - * - * @example - * <div> - * <code> - * function draw() { - * background(237, 34, 93); - * fill(0); - * - * if (mouseIsPressed) { - * if (mouseButton == LEFT) - * ellipse(50, 50, 50, 50); - * if (mouseButton == RIGHT) - * rect(25, 25, 50, 50); - * if (mouseButton == CENTER) - * triangle(23, 75, 50, 20, 78, 75); - * } - * - * print(mouseButton); - * } - * </code> - * </div> - */ -p5.prototype.mouseButton = 0; - -/** - * The boolean system variable mouseIsPressed is true if the mouse is pressed - * and false if not. - * - * @property mouseIsPressed - * - * @example - * <div> - * <code> - * function draw() { - * background(237, 34, 93); - * fill(0); - * - * if (mouseIsPressed) - * ellipse(50, 50, 50, 50); - * else - * rect(25, 25, 50, 50); - * - * print(mouseIsPressed); - * } - * </code> - * </div> - */ -p5.prototype.mouseIsPressed = false; -p5.prototype.isMousePressed = false; // both are supported - -p5.prototype._updateNextMouseCoords = function(e) { - if(e.type === 'touchstart' || - e.type === 'touchmove' || - e.type === 'touchend') { - this._setProperty('_nextMouseX', this._nextTouchX); - this._setProperty('_nextMouseY', this._nextTouchY); - } else { - if(this._curElement !== null) { - var mousePos = getMousePos(this._curElement.elt, e); - this._setProperty('_nextMouseX', mousePos.x); - this._setProperty('_nextMouseY', mousePos.y); - } - } - this._setProperty('winMouseX', e.pageX); - this._setProperty('winMouseY', e.pageY); -}; - -p5.prototype._updateMouseCoords = function() { - this._setProperty('pmouseX', this.mouseX); - this._setProperty('pmouseY', this.mouseY); - this._setProperty('mouseX', this._nextMouseX); - this._setProperty('mouseY', this._nextMouseY); - this._setProperty('pwinMouseX', this.winMouseX); - this._setProperty('pwinMouseY', this.winMouseY); -}; - -function getMousePos(canvas, evt) { - var rect = canvas.getBoundingClientRect(); - return { - x: evt.clientX - rect.left, - y: evt.clientY - rect.top - }; -} - -p5.prototype._setMouseButton = function(e) { - if (e.button === 1) { - this._setProperty('mouseButton', constants.CENTER); - } else if (e.button === 2) { - this._setProperty('mouseButton', constants.RIGHT); - } else { - this._setProperty('mouseButton', constants.LEFT); - } -}; - -/** - * The mouseMoved() function is called every time the mouse moves and a mouse - * button is not pressed.<br><br> - * Browsers may have different default - * behaviors attached to various mouse events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * @method mouseMoved - * @example - * <div> - * <code> - * // Move the mouse across the page - * // to change its value - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function mouseMoved() { - * value = value + 5; - * if (value > 255) { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function mouseMoved() { - * ellipse(mouseX, mouseY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ - -/** - * The mouseDragged() function is called once every time the mouse moves and - * a mouse button is pressed. If no mouseDragged() function is defined, the - * touchMoved() function will be called instead if it is defined.<br><br> - * Browsers may have different default - * behaviors attached to various mouse events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * @method mouseDragged - * @example - * <div> - * <code> - * // Drag the mouse across the page - * // to change its value - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function mouseDragged() { - * value = value + 5; - * if (value > 255) { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function mouseDragged() { - * ellipse(mouseX, mouseY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._onmousemove = function(e){ - var context = this._isGlobal ? window : this; - var executeDefault; - this._updateNextMouseCoords(e); - this._updateNextTouchCoords(e); - if (!this.isMousePressed) { - if (typeof context.mouseMoved === 'function') { - executeDefault = context.mouseMoved(e); - if(executeDefault === false) { - e.preventDefault(); - } - } - } - else { - if (typeof context.mouseDragged === 'function') { - executeDefault = context.mouseDragged(e); - if(executeDefault === false) { - e.preventDefault(); - } - } else if (typeof context.touchMoved === 'function') { - executeDefault = context.touchMoved(e); - if(executeDefault === false) { - e.preventDefault(); - } - } - } -}; - -/** - * The mousePressed() function is called once after every time a mouse button - * is pressed. The mouseButton variable (see the related reference entry) - * can be used to determine which button has been pressed. If no - * mousePressed() function is defined, the touchStarted() function will be - * called instead if it is defined.<br><br> - * Browsers may have different default - * behaviors attached to various mouse events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * @method mousePressed - * @example - * <div> - * <code> - * // Click within the image to change - * // the value of the rectangle - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function mousePressed() { - * if (value == 0) { - * value = 255; - * } else { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function mousePressed() { - * ellipse(mouseX, mouseY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._onmousedown = function(e) { - var context = this._isGlobal ? window : this; - var executeDefault; - this._setProperty('isMousePressed', true); - this._setProperty('mouseIsPressed', true); - this._setMouseButton(e); - this._updateNextMouseCoords(e); - this._updateNextTouchCoords(e); - if (typeof context.mousePressed === 'function') { - executeDefault = context.mousePressed(e); - if(executeDefault === false) { - e.preventDefault(); - } - } else if (typeof context.touchStarted === 'function') { - executeDefault = context.touchStarted(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -/** - * The mouseReleased() function is called every time a mouse button is - * released. If no mouseReleased() function is defined, the touchEnded() - * function will be called instead if it is defined.<br><br> - * Browsers may have different default - * behaviors attached to various mouse events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * - * @method mouseReleased - * @example - * <div> - * <code> - * // Click within the image to change - * // the value of the rectangle - * // after the mouse has been clicked - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function mouseReleased() { - * if (value == 0) { - * value = 255; - * } else { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function mouseReleased() { - * ellipse(mouseX, mouseY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._onmouseup = function(e) { - var context = this._isGlobal ? window : this; - var executeDefault; - this._setProperty('isMousePressed', false); - this._setProperty('mouseIsPressed', false); - if (typeof context.mouseReleased === 'function') { - executeDefault = context.mouseReleased(e); - if(executeDefault === false) { - e.preventDefault(); - } - } else if (typeof context.touchEnded === 'function') { - executeDefault = context.touchEnded(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -p5.prototype._ondragend = p5.prototype._onmouseup; -p5.prototype._ondragover = p5.prototype._onmousemove; - -/** - * The mouseClicked() function is called once after a mouse button has been - * pressed and then released.<br><br> - * Browsers may have different default - * behaviors attached to various mouse events. To prevent any default - * behavior for this event, add "return false" to the end of the method. - * - * @method mouseClicked - * @example - * <div> - * <code> - * // Click within the image to change - * // the value of the rectangle - * // after the mouse has been clicked - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function mouseClicked() { - * if (value == 0) { - * value = 255; - * } else { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function mouseClicked() { - * ellipse(mouseX, mouseY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._onclick = function(e) { - var context = this._isGlobal ? window : this; - if (typeof context.mouseClicked === 'function') { - var executeDefault = context.mouseClicked(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -/** - * The function mouseWheel() is executed every time a vertical mouse wheel - * event is detected either triggered by an actual mouse wheel or by a - * touchpad.<br><br> - * The event.delta property returns the amount the mouse wheel - * have scrolled. The values can be positive or negative depending on the - * scroll direction (on OS X with "natural" scrolling enabled, the signs - * are inverted).<br><br> - * Browsers may have different default behaviors attached to various - * mouse events. To prevent any default behavior for this event, add - * "return false" to the end of the method.<br><br> - * Due to the current support of the "wheel" event on Safari, the function - * may only work as expected if "return false" is included while using Safari. - * - * @method mouseWheel - * - * @example - * <div> - * <code> - * var pos = 25; - * - * function draw() { - * background(237, 34, 93); - * fill(0); - * rect(25, pos, 50, 50); - * } - * - * function mouseWheel(event) { - * print(event.delta); - * //move the square according to the vertical scroll amount - * pos += event.delta; - * //uncomment to block page scrolling - * //return false; - * } - * </code> - * </div> - */ -p5.prototype._onwheel = function(e) { - var context = this._isGlobal ? window : this; - if (typeof context.mouseWheel === 'function') { - e.delta = e.deltaY; - var executeDefault = context.mouseWheel(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -module.exports = p5; - -},{"../core/constants":47,"../core/core":48}],64:[function(_dereq_,module,exports){ -/** - * @module Events - * @submodule Touch - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/* - * These are helper vars that store the touchX and touchY vals - * between the time that a mouse event happens and the next frame - * of draw. This is done to deal with the asynchronicity of event - * calls interacting with the draw loop. When a touch event occurs - * the _nextTouchX/Y vars are updated, then on each call of draw, touchX/Y - * and ptouchX/Y are updated using the _nextMouseX/Y vals. - */ -p5.prototype._nextTouchX = 0; -p5.prototype._nextTouchY = 0; - -/** - * The system variable touchX always contains the horizontal position of - * one finger, relative to (0, 0) of the canvas. This is best used for - * single touch interactions. For multi-touch interactions, use the - * touches[] array. - * - * @property touchX - */ -p5.prototype.touchX = 0; - -/** - * The system variable touchY always contains the vertical position of - * one finger, relative to (0, 0) of the canvas. This is best used for - * single touch interactions. For multi-touch interactions, use the - * touches[] array. - * - * @property touchY - */ -p5.prototype.touchY = 0; - -/** - * The system variable ptouchX always contains the horizontal position of - * one finger, relative to (0, 0) of the canvas, in the frame previous to the - * current frame. - * - * @property ptouchX - */ -p5.prototype.ptouchX = 0; - -/** - * The system variable ptouchY always contains the vertical position of - * one finger, relative to (0, 0) of the canvas, in the frame previous to the - * current frame. - * - * @property ptouchY - */ -p5.prototype.ptouchY = 0; - -/** - * The system variable touches[] contains an array of the positions of all - * current touch points, relative to (0, 0) of the canvas, and IDs identifying a - * unique touch as it moves. Each element in the array is an object with x, y, - * and id properties. - * - * @property touches[] - */ -p5.prototype.touches = []; - -/** - * The boolean system variable touchIsDown is true if the screen is - * touched and false if not. - * - * @property touchIsDown - */ -p5.prototype.touchIsDown = false; - -p5.prototype._updateNextTouchCoords = function(e) { - if(e.type === 'mousedown' || - e.type === 'mousemove' || - e.type === 'mouseup'){ - this._setProperty('_nextTouchX', this._nextMouseX); - this._setProperty('_nextTouchY', this._nextMouseY); - } else { - if(this._curElement !== null) { - var touchInfo = getTouchInfo(this._curElement.elt, e, 0); - this._setProperty('_nextTouchX', touchInfo.x); - this._setProperty('_nextTouchY', touchInfo.y); - - var touches = []; - for(var i = 0; i < e.touches.length; i++){ - touches[i] = getTouchInfo(this._curElement.elt, e, i); - } - this._setProperty('touches', touches); - } - } -}; - -p5.prototype._updateTouchCoords = function() { - this._setProperty('ptouchX', this.touchX); - this._setProperty('ptouchY', this.touchY); - this._setProperty('touchX', this._nextTouchX); - this._setProperty('touchY', this._nextTouchY); -}; - -function getTouchInfo(canvas, e, i) { - i = i || 0; - var rect = canvas.getBoundingClientRect(); - var touch = e.touches[i] || e.changedTouches[i]; - return { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - id: touch.identifier - }; -} - -/** - * The touchStarted() function is called once after every time a touch is - * registered. If no touchStarted() function is defined, the mousePressed() - * function will be called instead if it is defined.<br><br> - * Browsers may have different default behaviors attached to various touch - * events. To prevent any default behavior for this event, add "return false" - * to the end of the method. - * - * @method touchStarted - * @example - * <div> - * <code> - * // Touch within the image to change - * // the value of the rectangle - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function touchStarted() { - * if (value == 0) { - * value = 255; - * } else { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function touchStarted() { - * ellipse(touchX, touchY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._ontouchstart = function(e) { - var context = this._isGlobal ? window : this; - var executeDefault; - this._updateNextTouchCoords(e); - this._updateNextMouseCoords(e); - this._setProperty('touchIsDown', true); - if(typeof context.touchStarted === 'function') { - executeDefault = context.touchStarted(e); - if(executeDefault === false) { - e.preventDefault(); - } - } else if (typeof context.mousePressed === 'function') { - executeDefault = context.mousePressed(e); - if(executeDefault === false) { - e.preventDefault(); - } - //this._setMouseButton(e); - } -}; - -/** - * The touchMoved() function is called every time a touch move is registered. - * If no touchMoved() function is defined, the mouseDragged() function will - * be called instead if it is defined.<br><br> - * Browsers may have different default behaviors attached to various touch - * events. To prevent any default behavior for this event, add "return false" - * to the end of the method. - * - * @method touchMoved - * @example - * <div> - * <code> - * // Move your finger across the page - * // to change its value - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function touchMoved() { - * value = value + 5; - * if (value > 255) { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function touchMoved() { - * ellipse(touchX, touchY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._ontouchmove = function(e) { - var context = this._isGlobal ? window : this; - var executeDefault; - this._updateNextTouchCoords(e); - this._updateNextMouseCoords(e); - if (typeof context.touchMoved === 'function') { - executeDefault = context.touchMoved(e); - if(executeDefault === false) { - e.preventDefault(); - } - } else if (typeof context.mouseDragged === 'function') { - executeDefault = context.mouseDragged(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -/** - * The touchEnded() function is called every time a touch ends. If no - * touchEnded() function is defined, the mouseReleased() function will be - * called instead if it is defined.<br><br> - * Browsers may have different default behaviors attached to various touch - * events. To prevent any default behavior for this event, add "return false" - * to the end of the method. - * - * @method touchEnded - * @example - * <div> - * <code> - * // Release touch within the image to - * // change the value of the rectangle - * - * var value = 0; - * function draw() { - * fill(value); - * rect(25, 25, 50, 50); - * } - * function touchEnded() { - * if (value == 0) { - * value = 255; - * } else { - * value = 0; - * } - * } - * </code> - * </div> - * - * <div class="norender"> - * <code> - * function touchEnded() { - * ellipse(touchX, touchY, 5, 5); - * // prevent default - * return false; - * } - * </code> - * </div> - */ -p5.prototype._ontouchend = function(e) { - this._updateNextTouchCoords(e); - this._updateNextMouseCoords(e); - if (this.touches.length === 0) { - this._setProperty('touchIsDown', false); - } - var context = this._isGlobal ? window : this; - var executeDefault; - if (typeof context.touchEnded === 'function') { - executeDefault = context.touchEnded(e); - if(executeDefault === false) { - e.preventDefault(); - } - } else if (typeof context.mouseReleased === 'function') { - executeDefault = context.mouseReleased(e); - if(executeDefault === false) { - e.preventDefault(); - } - } -}; - -module.exports = p5; - -},{"../core/core":48}],65:[function(_dereq_,module,exports){ -/*global ImageData:false */ - -/** - * This module defines the filters for use with image buffers. - * - * This module is basically a collection of functions stored in an object - * as opposed to modules. The functions are destructive, modifying - * the passed in canvas rather than creating a copy. - * - * Generally speaking users of this module will use the Filters.apply method - * on a canvas to create an effect. - * - * A number of functions are borrowed/adapted from - * http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ - * or the java processing implementation. - */ - -'use strict'; - -var Filters = {}; - - -/* - * Helper functions - */ - - -/** - * Returns the pixel buffer for a canvas - * - * @private - * - * @param {Canvas|ImageData} canvas the canvas to get pixels from - * @return {Uint8ClampedArray} a one-dimensional array containing - * the data in thc RGBA order, with integer - * values between 0 and 255 - */ -Filters._toPixels = function (canvas) { - if (canvas instanceof ImageData) { - return canvas.data; - } else { - return canvas.getContext('2d').getImageData( - 0, - 0, - canvas.width, - canvas.height - ).data; - } -}; - -/** - * Returns a 32 bit number containing ARGB data at ith pixel in the - * 1D array containing pixels data. - * - * @private - * - * @param {Uint8ClampedArray} data array returned by _toPixels() - * @param {Integer} i index of a 1D Image Array - * @return {Integer} 32 bit integer value representing - * ARGB value. - */ -Filters._getARGB = function (data, i) { - var offset = i * 4; - return (data[offset+3] << 24) & 0xff000000 | - (data[offset] << 16) & 0x00ff0000 | - (data[offset+1] << 8) & 0x0000ff00 | - data[offset+2] & 0x000000ff; -}; - -/** - * Modifies pixels RGBA values to values contained in the data object. - * - * @private - * - * @param {Uint8ClampedArray} pixels array returned by _toPixels() - * @param {Int32Array} data source 1D array where each value - * represents ARGB values - */ -Filters._setPixels = function (pixels, data) { - var offset = 0; - for( var i = 0, al = pixels.length; i < al; i++) { - offset = i*4; - pixels[offset + 0] = (data[i] & 0x00ff0000)>>>16; - pixels[offset + 1] = (data[i] & 0x0000ff00)>>>8; - pixels[offset + 2] = (data[i] & 0x000000ff); - pixels[offset + 3] = (data[i] & 0xff000000)>>>24; - } -}; - -/** - * Returns the ImageData object for a canvas - * https://developer.mozilla.org/en-US/docs/Web/API/ImageData - * - * @private - * - * @param {Canvas|ImageData} canvas canvas to get image data from - * @return {ImageData} Holder of pixel data (and width and - * height) for a canvas - */ -Filters._toImageData = function (canvas) { - if (canvas instanceof ImageData) { - return canvas; - } else { - return canvas.getContext('2d').getImageData( - 0, - 0, - canvas.width, - canvas.height - ); - } -}; - -/** - * Returns a blank ImageData object. - * - * @private - * - * @param {Integer} width - * @param {Integer} height - * @return {ImageData} - */ -Filters._createImageData = function (width, height) { - Filters._tmpCanvas = document.createElement('canvas'); - Filters._tmpCtx = Filters._tmpCanvas.getContext('2d'); - return this._tmpCtx.createImageData(width, height); -}; - - -/** - * Applys a filter function to a canvas. - * - * The difference between this and the actual filter functions defined below - * is that the filter functions generally modify the pixel buffer but do - * not actually put that data back to the canvas (where it would actually - * update what is visible). By contrast this method does make the changes - * actually visible in the canvas. - * - * The apply method is the method that callers of this module would generally - * use. It has been separated from the actual filters to support an advanced - * use case of creating a filter chain that executes without actually updating - * the canvas in between everystep. - * - * @param {[type]} func [description] - * @param {[type]} canvas [description] - * @param {[type]} level [description] - * @return {[type]} [description] - */ -Filters.apply = function (canvas, func, filterParam) { - var ctx = canvas.getContext('2d'); - var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - - //Filters can either return a new ImageData object, or just modify - //the one they received. - var newImageData = func(imageData, filterParam); - if (newImageData instanceof ImageData) { - ctx.putImageData(newImageData, 0, 0, 0, 0, canvas.width, canvas.height); - } else { - ctx.putImageData(imageData, 0, 0, 0, 0, canvas.width, canvas.height); - } -}; - - -/* - * Filters - */ - - -/** - * Converts the image to black and white pixels depending if they are above or - * below the threshold defined by the level parameter. The parameter must be - * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used. - * - * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ - * - * @param {Canvas} canvas - * @param {Float} level - */ -Filters.threshold = function (canvas, level) { - var pixels = Filters._toPixels(canvas); - - if (level === undefined) { - level = 0.5; - } - var thresh = Math.floor(level * 255); - - for (var i = 0; i < pixels.length; i += 4) { - var r = pixels[i]; - var g = pixels[i + 1]; - var b = pixels[i + 2]; - var gray = (0.2126 * r + 0.7152 * g + 0.0722 * b); - var val; - if (gray >= thresh) { - val = 255; - } else { - val = 0; - } - pixels[i] = pixels[i + 1] = pixels[i + 2] = val; - } - -}; - - -/** - * Converts any colors in the image to grayscale equivalents. - * No parameter is used. - * - * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ - * - * @param {Canvas} canvas - */ -Filters.gray = function (canvas) { - var pixels = Filters._toPixels(canvas); - - for (var i = 0; i < pixels.length; i += 4) { - var r = pixels[i]; - var g = pixels[i + 1]; - var b = pixels[i + 2]; - - // CIE luminance for RGB - var gray = (0.2126 * r + 0.7152 * g + 0.0722 * b); - pixels[i] = pixels[i + 1] = pixels[i + 2] = gray; - } -}; - -/** - * Sets the alpha channel to entirely opaque. No parameter is used. - * - * @param {Canvas} canvas - */ -Filters.opaque = function (canvas) { - var pixels = Filters._toPixels(canvas); - - for (var i = 0; i < pixels.length; i += 4) { - pixels[i + 3] = 255; - } - - return pixels; -}; - -/** - * Sets each pixel to its inverse value. No parameter is used. - * @param {Invert} - */ -Filters.invert = function (canvas) { - var pixels = Filters._toPixels(canvas); - - for (var i = 0; i < pixels.length; i += 4) { - pixels[i] = 255 - pixels[i]; - pixels[i + 1] = 255 - pixels[i + 1]; - pixels[i + 2] = 255 - pixels[i + 2]; - } - -}; - - -/** - * Limits each channel of the image to the number of colors specified as - * the parameter. The parameter can be set to values between 2 and 255, but - * results are most noticeable in the lower ranges. - * - * Adapted from java based processing implementation - * - * @param {Canvas} canvas - * @param {Integer} level - */ -Filters.posterize = function (canvas, level) { - var pixels = Filters._toPixels(canvas); - - if ((level < 2) || (level > 255)) { - throw new Error( - 'Level must be greater than 2 and less than 255 for posterize' - ); - } - - var levels1 = level - 1; - for (var i = 0; i < pixels.length; i+=4) { - var rlevel = pixels[i]; - var glevel = pixels[i + 1]; - var blevel = pixels[i + 2]; - - pixels[i] = (((rlevel * level) >> 8) * 255) / levels1; - pixels[i + 1] = (((glevel * level) >> 8) * 255) / levels1; - pixels[i + 2] = (((blevel * level) >> 8) * 255) / levels1; - } -}; - -/** - * reduces the bright areas in an image - * @param {Canvas} canvas - * - */ -Filters.dilate = function (canvas) { - var pixels = Filters._toPixels(canvas); - var currIdx = 0; - var maxIdx = pixels.length ? pixels.length/4 : 0; - var out = new Int32Array(maxIdx); - var currRowIdx, maxRowIdx, colOrig, colOut, currLum; - var idxRight, idxLeft, idxUp, idxDown, - colRight, colLeft, colUp, colDown, - lumRight, lumLeft, lumUp, lumDown; - - while(currIdx < maxIdx) { - currRowIdx = currIdx; - maxRowIdx = currIdx + canvas.width; - while (currIdx < maxRowIdx) { - colOrig = colOut = Filters._getARGB(pixels, currIdx); - idxLeft = currIdx - 1; - idxRight = currIdx + 1; - idxUp = currIdx - canvas.width; - idxDown = currIdx + canvas.width; - - if (idxLeft < currRowIdx) { - idxLeft = currIdx; - } - if (idxRight >= maxRowIdx) { - idxRight = currIdx; - } - if (idxUp < 0){ - idxUp = 0; - } - if (idxDown >= maxIdx) { - idxDown = currIdx; - } - colUp = Filters._getARGB(pixels, idxUp); - colLeft = Filters._getARGB(pixels, idxLeft); - colDown = Filters._getARGB(pixels, idxDown); - colRight = Filters._getARGB(pixels, 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; - } - } - Filters._setPixels(pixels, out); -}; - -/** - * increases the bright areas in an image - * @param {Canvas} canvas - * - */ -Filters.erode = function(canvas) { - var pixels = Filters._toPixels(canvas); - var currIdx = 0; - var maxIdx = pixels.length ? pixels.length/4 : 0; - var out = new Int32Array(maxIdx); - var currRowIdx, maxRowIdx, colOrig, colOut, currLum; - var idxRight, idxLeft, idxUp, idxDown, - colRight, colLeft, colUp, colDown, - lumRight, lumLeft, lumUp, lumDown; - - while(currIdx < maxIdx) { - currRowIdx = currIdx; - maxRowIdx = currIdx + canvas.width; - while (currIdx < maxRowIdx) { - colOrig = colOut = Filters._getARGB(pixels, currIdx); - idxLeft = currIdx - 1; - idxRight = currIdx + 1; - idxUp = currIdx - canvas.width; - idxDown = currIdx + canvas.width; - - if (idxLeft < currRowIdx) { - idxLeft = currIdx; - } - if (idxRight >= maxRowIdx) { - idxRight = currIdx; - } - if (idxUp < 0) { - idxUp = 0; - } - if (idxDown >= maxIdx) { - idxDown = currIdx; - } - colUp = Filters._getARGB(pixels, idxUp); - colLeft = Filters._getARGB(pixels, idxLeft); - colDown = Filters._getARGB(pixels, idxDown); - colRight = Filters._getARGB(pixels, 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; - } - } - Filters._setPixels(pixels, out); -}; - -// BLUR - -// internal kernel stuff for the gaussian blur filter -var blurRadius; -var blurKernelSize; -var blurKernel; -var blurMult; - -/* - * Port of https://github.com/processing/processing/blob/ - * master/core/src/processing/core/PImage.java#L1250 - * - * Optimized code for building the blur kernel. - * further optimized blur code (approx. 15% for radius=20) - * bigger speed gains for larger radii (~30%) - * added support for various image types (ALPHA, RGB, ARGB) - * [toxi 050728] - */ -function buildBlurKernel(r) { - var radius = (r * 3.5)|0; - radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248); - - if (blurRadius !== radius) { - blurRadius = radius; - blurKernelSize = 1 + blurRadius<<1; - blurKernel = new Int32Array(blurKernelSize); - blurMult = new Array(blurKernelSize); - for(var l = 0; l < blurKernelSize; l++){ - blurMult[l] = new Int32Array(256); - } - - var bk,bki; - var bm,bmi; - - for (var i = 1, radiusi = radius - 1; i < radius; i++) { - blurKernel[radius+i] = blurKernel[radiusi] = bki = radiusi * radiusi; - bm = blurMult[radius+i]; - bmi = blurMult[radiusi--]; - for (var j = 0; j < 256; j++){ - bm[j] = bmi[j] = bki * j; - } - } - bk = blurKernel[radius] = radius * radius; - bm = blurMult[radius]; - - for (var k = 0; k < 256; k++){ - bm[k] = bk * k; - } - } - -} - -// Port of https://github.com/processing/processing/blob/ -// master/core/src/processing/core/PImage.java#L1433 -function blurARGB(canvas, radius) { - var pixels = Filters._toPixels(canvas); - var width = canvas.width; - var height = canvas.height; - var numPackedPixels = width * height; - var argb = new Int32Array(numPackedPixels); - for (var j = 0; j < numPackedPixels; j++) { - argb[j] = Filters._getARGB(pixels, j); - } - var sum, cr, cg, cb, ca; - var read, ri, ym, ymi, bk0; - var a2 = new Int32Array(numPackedPixels); - var r2 = new Int32Array(numPackedPixels); - var g2 = new Int32Array(numPackedPixels); - var b2 = new Int32Array(numPackedPixels); - var yi = 0; - buildBlurKernel(radius); - var x, y, i; - var bm; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - cb = cg = cr = ca = sum = 0; - read = x - blurRadius; - if (read < 0) { - bk0 = -read; - read = 0; - } else { - if (read >= width) { - break; - } - bk0 = 0; - } - for (i = bk0; i < blurKernelSize; i++) { - if (read >= width) { - break; - } - var c = argb[read + yi]; - bm = blurMult[i]; - ca += bm[(c & -16777216) >>> 24]; - cr += bm[(c & 16711680) >> 16]; - cg += bm[(c & 65280) >> 8]; - cb += bm[c & 255]; - sum += blurKernel[i]; - read++; - } - ri = yi + x; - a2[ri] = ca / sum; - r2[ri] = cr / sum; - g2[ri] = cg / sum; - b2[ri] = cb / sum; - } - yi += width; - } - yi = 0; - ym = -blurRadius; - ymi = ym * width; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - cb = cg = cr = ca = sum = 0; - if (ym < 0) { - bk0 = ri = -ym; - read = x; - } else { - if (ym >= height) { - break; - } - bk0 = 0; - ri = ym; - read = x + ymi; - } - for (i = bk0; i < blurKernelSize; i++) { - if (ri >= height) { - break; - } - bm = blurMult[i]; - ca += bm[a2[read]]; - cr += bm[r2[read]]; - cg += bm[g2[read]]; - cb += bm[b2[read]]; - sum += blurKernel[i]; - ri++; - read += width; - } - argb[x + yi] = (ca/sum)<<24 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum); - } - yi += width; - ymi += width; - ym++; - } - Filters._setPixels(pixels, argb); -} - -Filters.blur = function(canvas, radius){ - blurARGB(canvas, radius); -}; - - -module.exports = Filters; - -},{}],66:[function(_dereq_,module,exports){ -/** - * @module Image - * @submodule Image - * @for p5 - * @requires core - */ - -/** - * This module defines the p5 methods for the p5.Image class - * for drawing images to the main display canvas. - */ -'use strict'; - - -var p5 = _dereq_('../core/core'); - -/* global frames:true */// This is not global, but JSHint is not aware that -// this module is implicitly enclosed with Browserify: this overrides the -// redefined-global error and permits using the name "frames" for the array -// of saved animation frames. -var frames = []; - - -/** - * Creates a new p5.Image (the datatype for storing images). This provides a - * fresh buffer of pixels to play with. Set the size of the buffer with the - * width and height parameters. - * <br><br> - * .pixels gives access to an array containing the values for all the pixels - * in the display window. - * These values are numbers. This array is the size (including an appropriate - * factor for the pixelDensity) of the display window x4, - * representing the R, G, B, A values in order for each pixel, moving from - * left to right across each row, then down each column. See .pixels for - * more info. It may also be simpler to use set() or get(). - * <br><br> - * Before accessing the pixels of an image, the data must loaded with the - * loadPixels() function. After the array data has been modified, the - * updatePixels() function must be run to update the changes. - * - * @method createImage - * @param {Integer} width width in pixels - * @param {Integer} height height in pixels - * @return {p5.Image} the p5.Image object - * @example - * <div> - * <code> - * img = createImage(66, 66); - * img.loadPixels(); - * for (i = 0; i < img.width; i++) { - * for (j = 0; j < img.height; j++) { - * img.set(i, j, color(0, 90, 102)); - * } - * } - * img.updatePixels(); - * image(img, 17, 17); - * </code> - * </div> - * - * <div> - * <code> - * img = createImage(66, 66); - * img.loadPixels(); - * for (i = 0; i < img.width; i++) { - * for (j = 0; j < img.height; j++) { - * img.set(i, j, color(0, 90, 102, i % img.width * 2)); - * } - * } - * img.updatePixels(); - * image(img, 17, 17); - * image(img, 34, 34); - * </code> - * </div> - * - * <div> - * <code> - * var pink = color(255, 102, 204); - * img = createImage(66, 66); - * img.loadPixels(); - * var d = pixelDensity; - * var halfImage = 4 * (width * d) * (height/2 * d); - * for (var i = 0; i < halfImage; i+=4) { - * img.pixels[i] = red(pink); - * img.pixels[i+1] = green(pink); - * img.pixels[i+2] = blue(pink); - * img.pixels[i+3] = alpha(pink); - * } - * img.updatePixels(); - * image(img, 17, 17); - * </code> - * </div> - */ -p5.prototype.createImage = function(width, height) { - return new p5.Image(width, height); -}; - -/** - * Save the current canvas as an image. In Safari, this will open the - * image in the window and the user must provide their own - * filename on save-as. Other browsers will either save the - * file immediately, or prompt the user with a dialogue window. - * - * @method saveCanvas - * @param {[selectedCanvas]} canvas a variable representing a - * specific html5 canvas (optional) - * @param {[String]} filename - * @param {[String]} extension 'jpg' or 'png' - * @example - * <div class='norender'><code> - * function setup() { - * var c = createCanvas(100, 100); - * background(255, 0, 0); - * saveCanvas(c, 'myCanvas', 'jpg'); - * } - * </code></div> - * <div class='norender'><code> - * // note that this example has the same result as above - * // if no canvas is specified, defaults to main canvas - * function setup() { - * createCanvas(100, 100); - * background(255, 0, 0); - * saveCanvas('myCanvas', 'jpg'); - * } - * </code></div> - * <div class='norender'><code> - * // all of the following are valid - * saveCanvas(c, 'myCanvas', 'jpg'); - * saveCanvas(c, 'myCanvas'); - * saveCanvas(c); - * saveCanvas('myCanvas', 'png'); - * saveCanvas('myCanvas'); - * saveCanvas(); - * </code></div> - */ -p5.prototype.saveCanvas = function() { - - var cnv, filename, extension; - if (arguments.length === 3) { - cnv = arguments[0]; - filename = arguments[1]; - extension = arguments[2]; - } else if (arguments.length === 2) { - if (typeof arguments[0] === 'object') { - cnv = arguments[0]; - filename = arguments[1]; - } else { - filename = arguments[0]; - extension = arguments[1]; - } - } else if (arguments.length === 1) { - if (typeof arguments[0] === 'object') { - cnv = arguments[0]; - } else { - filename = arguments[0]; - } - } - - if (cnv instanceof p5.Element) { - cnv = cnv.elt; - } - if (!(cnv instanceof HTMLCanvasElement)) { - cnv = null; - } - - if (!extension) { - extension = p5.prototype._checkFileExtension(filename, extension)[1]; - if (extension === '') { - extension = 'png'; - } - } - - if (!cnv) { - if (this._curElement && this._curElement.elt) { - cnv = this._curElement.elt; - } - } - - if ( p5.prototype._isSafari() ) { - var aText = 'Hello, Safari user!\n'; - aText += 'Now capturing a screenshot...\n'; - aText += 'To save this image,\n'; - aText += 'go to File --> Save As.\n'; - alert(aText); - window.location.href = cnv.toDataURL(); - } else { - var mimeType; - if (typeof(extension) === 'undefined') { - extension = 'png'; - mimeType = 'image/png'; - } - else { - switch(extension){ - case 'png': - mimeType = 'image/png'; - break; - case 'jpeg': - mimeType = 'image/jpeg'; - break; - case 'jpg': - mimeType = 'image/jpeg'; - break; - default: - mimeType = 'image/png'; - break; - } - } - var downloadMime = 'image/octet-stream'; - var imageData = cnv.toDataURL(mimeType); - imageData = imageData.replace(mimeType, downloadMime); - - p5.prototype.downloadFile(imageData, filename, extension); - } -}; - -/** - * Capture a sequence of frames that can be used to create a movie. - * Accepts a callback. For example, you may wish to send the frames - * to a server where they can be stored or converted into a movie. - * If no callback is provided, the browser will attempt to download - * all of the images that have just been created. - * - * @method saveFrames - * @param {String} filename - * @param {String} extension 'jpg' or 'png' - * @param {Number} duration Duration in seconds to save the frames for. - * @param {Number} framerate Framerate to save the frames in. - * @param {Function} [callback] A callback function that will be executed - to handle the image data. This function - should accept an array as argument. The - array will contain the spcecified number of - frames of objects. Each object have three - properties: imageData - an - image/octet-stream, filename and extension. - */ -p5.prototype.saveFrames = function(fName, ext, _duration, _fps, callback) { - var duration = _duration || 3; - duration = p5.prototype.constrain(duration, 0, 15); - duration = duration * 1000; - var fps = _fps || 15; - fps = p5.prototype.constrain(fps, 0, 22); - var count = 0; - - var makeFrame = p5.prototype._makeFrame; - var cnv = this._curElement.elt; - var frameFactory = setInterval(function(){ - makeFrame(fName + count, ext, cnv); - count++; - },1000/fps); - - setTimeout(function(){ - clearInterval(frameFactory); - if (callback) { - callback(frames); - } - else { - for (var i = 0; i < frames.length; i++) { - var f = frames[i]; - p5.prototype.downloadFile(f.imageData, f.filename, f.ext); - } - } - frames = []; // clear frames - }, duration + 0.01); -}; - -p5.prototype._makeFrame = function(filename, extension, _cnv) { - var cnv; - if (this) { - cnv = this._curElement.elt; - } else { - cnv = _cnv; - } - var mimeType; - if (!extension) { - extension = 'png'; - mimeType = 'image/png'; - } - else { - switch(extension.toLowerCase()){ - case 'png': - mimeType = 'image/png'; - break; - case 'jpeg': - mimeType = 'image/jpeg'; - break; - case 'jpg': - mimeType = 'image/jpeg'; - break; - default: - mimeType = 'image/png'; - break; - } - } - var downloadMime = 'image/octet-stream'; - var imageData = cnv.toDataURL(mimeType); - imageData = imageData.replace(mimeType, downloadMime); - - var thisFrame = {}; - thisFrame.imageData = imageData; - thisFrame.filename = filename; - thisFrame.ext = extension; - frames.push(thisFrame); -}; - -module.exports = p5; - -},{"../core/core":48}],67:[function(_dereq_,module,exports){ -/** - * @module Image - * @submodule Loading & Displaying - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var Filters = _dereq_('./filters'); -var canvas = _dereq_('../core/canvas'); -var constants = _dereq_('../core/constants'); - -_dereq_('../core/error_helpers'); - -/** - * Loads an image from a path and creates a p5.Image from it. - * <br><br> - * The image may not be immediately available for rendering - * If you want to ensure that the image is ready before doing - * anything with it, place the loadImage() call in preload(). - * You may also supply a callback function to handle the image when it's ready. - * <br><br> - * The path to the image should be relative to the HTML file - * that links in your sketch. Loading an from a URL or other - * remote location may be blocked due to your browser's built-in - * security. - * - * @method loadImage - * @param {String} path Path of the image to be loaded - * @param {Function(p5.Image)} [successCallback] Function to be called once - * the image is loaded. Will be passed the - * p5.Image. - * @param {Function(Event)} [failureCallback] called with event error if - * the image fails to load. - * @return {p5.Image} the p5.Image object - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/laDefense.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * } - * </code> - * </div> - * <div> - * <code> - * function setup() { - * // here we use a callback to display the image after loading - * loadImage("assets/laDefense.jpg", function(img) { - * image(img, 0, 0); - * }); - * } - * </code> - * </div> - */ -p5.prototype.loadImage = function(path, successCallback, failureCallback) { - var img = new Image(); - var pImg = new p5.Image(1, 1, this); - var decrementPreload = p5._getDecrementPreload.apply(this, arguments); - - img.onload = function() { - pImg.width = pImg.canvas.width = img.width; - pImg.height = pImg.canvas.height = img.height; - - // Draw the image into the backing canvas of the p5.Image - pImg.drawingContext.drawImage(img, 0, 0); - - if (typeof successCallback === 'function') { - successCallback(pImg); - } - if (decrementPreload && (successCallback !== decrementPreload)) { - decrementPreload(); - } - }; - img.onerror = function(e) { - p5._friendlyFileLoadError(0,img.src); - // don't get failure callback mixed up with decrementPreload - if ((typeof failureCallback === 'function') && - (failureCallback !== decrementPreload)) { - failureCallback(e); - } - }; - - //set crossOrigin in case image is served which CORS headers - //this will let us draw to canvas without tainting it. - //see https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image - // When using data-uris the file will be loaded locally - // so we don't need to worry about crossOrigin with base64 file types - if(path.indexOf('data:image/') !== 0) { - img.crossOrigin = 'Anonymous'; - } - - //start loading the image - img.src = path; - - return pImg; -}; - -/** - * Validates clipping params. Per drawImage spec sWidth and sHight cannot be - * negative or greater than image intrinsic width and height - * @private - * @param {Number} sVal - * @param {Number} iVal - * @returns {Number} - * @private - */ -function _sAssign(sVal, iVal) { - if (sVal > 0 && sVal < iVal) { - return sVal; - } - else { - return iVal; - } -} - -/** - * Draw an image to the main canvas of the p5js sketch - * - * @method image - * @param {p5.Image} img the image to display - * @param {Number} [sx=0] The X coordinate of the top left corner of the - * sub-rectangle of the source image to draw into - * the destination canvas. - * @param {Number} [sy=0] The Y coordinate of the top left corner of the - * sub-rectangle of the source image to draw into - * the destination canvas. - * @param {Number} [sWidth=img.width] The width of the sub-rectangle of the - * source image to draw into the destination - * canvas. - * @param {Number} [sHeight=img.height] The height of the sub-rectangle of the - * source image to draw into the - * destination context. - * @param {Number} [dx=0] The X coordinate in the destination canvas at - * which to place the top-left corner of the - * source image. - * @param {Number} [dy=0] The Y coordinate in the destination canvas at - * which to place the top-left corner of the - * source image. - * @param {Number} [dWidth] The width to draw the image in the destination - * canvas. This allows scaling of the drawn image. - * @param {Number} [dHeight] The height to draw the image in the destination - * canvas. This allows scaling of the drawn image. - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/laDefense.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * image(img, 0, 0, 100, 100); - * image(img, 0, 0, 100, 100, 0, 0, 100, 100); - * } - * </code> - * </div> - * <div> - * <code> - * function setup() { - * // here we use a callback to display the image after loading - * loadImage("assets/laDefense.jpg", function(img) { - * image(img, 0, 0); - * }); - * } - * </code> - * </div> - */ -p5.prototype.image = - function(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) { - // Temporarily disabling until options for p5.Graphics are added. - // var args = new Array(arguments.length); - // for (var i = 0; i < args.length; ++i) { - // args[i] = arguments[i]; - // } - // this._validateParameters( - // 'image', - // args, - // [ - // ['p5.Image', 'Number', 'Number'], - // ['p5.Image', 'Number', 'Number', 'Number', 'Number'] - // ] - // ); - - // set defaults per spec: https://goo.gl/3ykfOq - if (arguments.length <= 5) { - dx = sx || 0; - dy = sy || 0; - sx = 0; - sy = 0; - if (img.elt && img.elt.videoWidth && !img.canvas) { // video no canvas - var actualW = img.elt.videoWidth; - var actualH = img.elt.videoHeight; - dWidth = sWidth || img.elt.width; - dHeight = sHeight || img.elt.width*actualH/actualW; - sWidth = actualW; - sHeight = actualH; - } else { - dWidth = sWidth || img.width; - dHeight = sHeight || img.height; - sWidth = img.width; - sHeight = img.height; - } - } else if (arguments.length === 9) { - sx = sx || 0; - sy = sy || 0; - sWidth = _sAssign(sWidth, img.width); - sHeight = _sAssign(sHeight, img.height); - - dx = dx || 0; - dy = dy || 0; - dWidth = dWidth || img.width; - dHeight = dHeight || img.height; - } else { - throw 'Wrong number of arguments to image()'; - } - - var vals = canvas.modeAdjust(dx, dy, dWidth, dHeight, - this._renderer._imageMode); - - // tint the image if there is a tint - this._renderer.image(img, sx, sy, sWidth, sHeight, vals.x, vals.y, vals.w, - vals.h); -}; - -/** - * Sets the fill value for displaying images. Images can be tinted to - * specified colors or made transparent by including an alpha value. - * <br><br> - * To apply transparency to an image without affecting its color, use - * white as the tint color and specify an alpha value. For instance, - * tint(255, 128) will make an image 50% transparent (assuming the default - * alpha range of 0-255, which can be changed with colorMode()). - * <br><br> - * The value for the gray parameter must be less than or equal to the current - * maximum value as specified by colorMode(). The default maximum value is - * 255. - * - * @method tint - * @param {Number|Array} v1 gray value, red or hue value (depending on the - * current color mode), or color Array - * @param {Number|Array} [v2] green or saturation value (depending on the - * current color mode) - * @param {Number|Array} [v3] blue or brightness value (depending on the - * current color mode) - * @param {Number|Array} [a] opacity of the background - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/laDefense.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * tint(0, 153, 204); // Tint blue - * image(img, 50, 0); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/laDefense.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * tint(0, 153, 204, 126); // Tint blue and set transparency - * image(img, 50, 0); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/laDefense.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * tint(255, 126); // Apply transparency without changing color - * image(img, 50, 0); - * } - * </code> - * </div> - */ -p5.prototype.tint = function () { - var c = this.color.apply(this, arguments); - this._renderer._tint = c.levels; -}; - -/** - * Removes the current fill value for displaying images and reverts to - * displaying images with their original hues. - * - * @method noTint - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * tint(0, 153, 204); // Tint blue - * image(img, 0, 0); - * noTint(); // Disable tint - * image(img, 50, 0); - * } - * </code> - * </div> - */ -p5.prototype.noTint = function() { - this._renderer._tint = null; -}; - -/** - * Apply the current tint color to the input image, return the resulting - * canvas. - * - * @param {p5.Image} The image to be tinted - * @return {canvas} The resulting tinted canvas - * - */ -p5.prototype._getTintedImageCanvas = function(img) { - if (!img.canvas) { - return img; - } - var pixels = Filters._toPixels(img.canvas); - var tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = img.canvas.width; - tmpCanvas.height = img.canvas.height; - var tmpCtx = tmpCanvas.getContext('2d'); - var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height); - var newPixels = id.data; - - for(var i = 0; i < pixels.length; i += 4) { - var r = pixels[i]; - var g = pixels[i+1]; - var b = pixels[i+2]; - var a = pixels[i+3]; - - newPixels[i] = r*this._renderer._tint[0]/255; - newPixels[i+1] = g*this._renderer._tint[1]/255; - newPixels[i+2] = b*this._renderer._tint[2]/255; - newPixels[i+3] = a*this._renderer._tint[3]/255; - } - - tmpCtx.putImageData(id, 0, 0); - return tmpCanvas; -}; - -/** - * Set image mode. Modifies the location from which images are drawn by - * changing the way in which parameters given to image() are interpreted. - * The default mode is imageMode(CORNER), which interprets the second and - * third parameters of image() as the upper-left corner of the image. If - * two additional parameters are specified, they are used to set the image's - * width and height. - * <br><br> - * imageMode(CORNERS) interprets the second and third parameters of image() - * as the location of one corner, and the fourth and fifth parameters as the - * opposite corner. - * <br><br> - * imageMode(CENTER) interprets the second and third parameters of image() - * as the image's center point. If two additional parameters are specified, - * they are used to set the image's width and height. - * - * @method imageMode - * @param {String} m The mode: either CORNER, CORNERS, or CENTER. - * @example - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * imageMode(CORNER); - * image(img, 10, 10, 50, 50); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * imageMode(CORNERS); - * image(img, 10, 10, 90, 40); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * imageMode(CENTER); - * image(img, 50, 50, 80, 80); - * } - * </code> - * </div> - */ -p5.prototype.imageMode = function(m) { - if (m === constants.CORNER || - m === constants.CORNERS || - m === constants.CENTER) { - this._renderer._imageMode = m; - } -}; - - -module.exports = p5; - -},{"../core/canvas":46,"../core/constants":47,"../core/core":48,"../core/error_helpers":51,"./filters":65}],68:[function(_dereq_,module,exports){ -/** - * @module Image - * @submodule Image - * @requires core - * @requires constants - * @requires filters - */ - -/** - * This module defines the p5.Image class and P5 methods for - * drawing images to the main display canvas. - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var Filters = _dereq_('./filters'); - -/* - * Class methods - */ - -/** - * Creates a new p5.Image. A p5.Image is a canvas backed representation of an - * image. - * <br><br> - * p5 can display .gif, .jpg and .png images. Images may be displayed - * in 2D and 3D space. Before an image is used, it must be loaded with the - * loadImage() function. The p5.Image class contains fields for the width and - * height of the image, as well as an array called pixels[] that contains the - * values for every pixel in the image. - * <br><br> - * The methods described below allow easy access to the image's pixels and - * alpha channel and simplify the process of compositing. - * <br><br> - * Before using the pixels[] array, be sure to use the loadPixels() method on - * the image to make sure that the pixel data is properly loaded. - * - * @class p5.Image - * @constructor - * @param {Number} width - * @param {Number} height - * @param {Object} pInst An instance of a p5 sketch. - */ -p5.Image = function(width, height){ - /** - * Image width. - * @property width - * @example - * <div><code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * createCanvas(100, 100); - * image(img, 0, 0); - * for (var i=0; i < img.width; i++) { - * var c = img.get(i, img.height/2); - * stroke(c); - * line(i, height/2, i, height); - * } - * } - * </code></div> - */ - this.width = width; - /** - * Image height. - * @property height - * @example - * <div><code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * createCanvas(100, 100); - * image(img, 0, 0); - * for (var i=0; i < img.height; i++) { - * var c = img.get(img.width/2, i); - * stroke(c); - * line(0, i, width/2, i); - * } - * } - * </code></div> - */ - this.height = height; - this.canvas = document.createElement('canvas'); - this.canvas.width = this.width; - this.canvas.height = this.height; - this.drawingContext = this.canvas.getContext('2d'); - this._pixelDensity = 1; - //used for webgl texturing only - this.isTexture = false; - /** - * Array containing the values for all the pixels in the display window. - * These values are numbers. This array is the size (include an appropriate - * factor for pixelDensity) of the display window x4, - * representing the R, G, B, A values in order for each pixel, moving from - * left to right across each row, then down each column. Retina and other - * high denisty displays may have more pixels[] (by a factor of - * pixelDensity^2). - * For example, if the image is 100x100 pixels, there will be 40,000. With - * pixelDensity = 2, there will be 160,000. The first four values - * (indices 0-3) in the array will be the R, G, B, A values of the pixel at - * (0, 0). The second four values (indices 4-7) will contain the R, G, B, A - * values of the pixel at (1, 0). More generally, to set values for a pixel - * at (x, y): - * <code><pre>var d = pixelDensity; - * for (var i = 0; i < d; i++) { - * for (var j = 0; j < d; j++) { - * // loop over - * idx = 4*((y * d + j) * width * d + (x * d + i)); - * pixels[idx] = r; - * pixels[idx+1] = g; - * pixels[idx+2] = b; - * pixels[idx+3] = a; - * } - * } - * </pre></code> - * <br><br> - * Before accessing this array, the data must loaded with the loadPixels() - * function. After the array data has been modified, the updatePixels() - * function must be run to update the changes. - * @property pixels[] - * @example - * <div> - * <code> - * img = createImage(66, 66); - * img.loadPixels(); - * for (i = 0; i < img.width; i++) { - * for (j = 0; j < img.height; j++) { - * img.set(i, j, color(0, 90, 102)); - * } - * } - * img.updatePixels(); - * image(img, 17, 17); - * </code> - * </div> - * <div> - * <code> - * var pink = color(255, 102, 204); - * img = createImage(66, 66); - * img.loadPixels(); - * for (var i = 0; i < 4*(width*height/2); i+=4) { - * img.pixels[i] = red(pink); - * img.pixels[i+1] = green(pink); - * img.pixels[i+2] = blue(pink); - * img.pixels[i+3] = alpha(pink); - * } - * img.updatePixels(); - * image(img, 17, 17); - * </code> - * </div> - */ - this.pixels = []; -}; - -/** - * Helper fxn for sharing pixel methods - * - */ -p5.Image.prototype._setProperty = function (prop, value) { - this[prop] = value; -}; - -/** - * Loads the pixels data for this image into the [pixels] attribute. - * - * @method loadPixels - * @example - * <div><code> - * var myImage; - * var halfImage; - * - * function preload() { - * myImage = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * myImage.loadPixels(); - * halfImage = 4 * width * height/2; - * for(var i = 0; i < halfImage; i++){ - * myImage.pixels[i+halfImage] = myImage.pixels[i]; - * } - * myImage.updatePixels(); - * } - * - * function draw() { - * image(myImage, 0, 0); - * } - * </code></div> - */ -p5.Image.prototype.loadPixels = function(){ - p5.Renderer2D.prototype.loadPixels.call(this); -}; - -/** - * Updates the backing canvas for this image with the contents of - * the [pixels] array. - * - * @method updatePixels - * @param {Integer|undefined} x x-offset of the target update area for the - * underlying canvas - * @param {Integer|undefined} y y-offset of the target update area for the - * underlying canvas - * @param {Integer|undefined} w height of the target update area for the - * underlying canvas - * @param {Integer|undefined} h height of the target update area for the - * underlying canvas - * @example - * <div><code> - * var myImage; - * var halfImage; - * - * function preload() { - * myImage = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * myImage.loadPixels(); - * halfImage = 4 * width * height/2; - * for(var i = 0; i < halfImage; i++){ - * myImage.pixels[i+halfImage] = myImage.pixels[i]; - * } - * myImage.updatePixels(); - * } - * - * function draw() { - * image(myImage, 0, 0); - * } - * </code></div> - */ -p5.Image.prototype.updatePixels = function(x, y, w, h){ - p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h); -}; - -/** - * Get a region of pixels from an image. - * - * If no params are passed, those whole image is returned, - * if x and y are the only params passed a single pixel is extracted - * if all params are passed a rectangle region is extracted and a p5.Image - * is returned. - * - * Returns undefined if the region is outside the bounds of the image - * - * @method get - * @param {Number} [x] x-coordinate of the pixel - * @param {Number} [y] y-coordinate of the pixel - * @param {Number} [w] width - * @param {Number} [h] height - * @return {Array/Color | p5.Image} color of pixel at x,y in array format - * [R, G, B, A] or p5.Image - * @example - * <div><code> - * var myImage; - * var c; - * - * function preload() { - * myImage = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * background(myImage); - * noStroke(); - * c = myImage.get(60, 90); - * fill(c); - * rect(25, 25, 50, 50); - * } - * - * //get() returns color here - * </code></div> - */ -p5.Image.prototype.get = function(x, y, w, h){ - return p5.Renderer2D.prototype.get.call(this, x, y, w, h); -}; - -/** - * Set the color of a single pixel or write an image into - * this p5.Image. - * - * Note that for a large number of pixels this will - * be slower than directly manipulating the pixels array - * and then calling updatePixels(). - * - * @method set - * @param {Number} x x-coordinate of the pixel - * @param {Number} y y-coordinate of the pixel - * @param {Number|Array|Object} a grayscale value | pixel array | - * a p5.Color | image to copy - * @example - * <div> - * <code> - * img = createImage(66, 66); - * img.loadPixels(); - * for (i = 0; i < img.width; i++) { - * for (j = 0; j < img.height; j++) { - * img.set(i, j, color(0, 90, 102, i % img.width * 2)); - * } - * } - * img.updatePixels(); - * image(img, 17, 17); - * image(img, 34, 34); - * </code> - * </div> - */ -p5.Image.prototype.set = function(x, y, imgOrCol){ - p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol); -}; - -/** - * Resize the image to a new width and height. To make the image scale - * proportionally, use 0 as the value for the wide or high parameter. - * For instance, to make the width of an image 150 pixels, and change - * the height using the same proportion, use resize(150, 0). - * - * @method resize - * @param {Number} width the resized image width - * @param {Number} height the resized image height - * @example - * <div><code> - * var img; - * - * function setup() { - * img = loadImage("assets/rockies.jpg"); - * } - - * function draw() { - * image(img, 0, 0); - * } - * - * function mousePressed() { - * img.resize(50, 100); - * } - * </code></div> - */ -p5.Image.prototype.resize = function(width, height){ - - // Copy contents to a temporary canvas, resize the original - // and then copy back. - // - // There is a faster approach that involves just one copy and swapping the - // this.canvas reference. We could switch to that approach if (as i think - // is the case) there an expectation that the user would not hold a - // reference to the backing canvas of a p5.Image. But since we do not - // enforce that at the moment, I am leaving in the slower, but safer - // implementation. - - // auto-resize - if (width === 0 && height === 0) { - width = this.canvas.width; - height = this.canvas.height; - } else if (width === 0) { - width = this.canvas.width * height / this.canvas.height; - } else if (height === 0) { - height = this.canvas.height * width / this.canvas.width; - } - - var tempCanvas = document.createElement('canvas'); - tempCanvas.width = width; - tempCanvas.height = height; - tempCanvas.getContext('2d').drawImage(this.canvas, - 0, 0, this.canvas.width, this.canvas.height, - 0, 0, tempCanvas.width, tempCanvas.height - ); - - - // Resize the original canvas, which will clear its contents - this.canvas.width = this.width = width; - this.canvas.height = this.height = height; - - //Copy the image back - - this.drawingContext.drawImage(tempCanvas, - 0, 0, width, height, - 0, 0, width, height - ); - - if(this.pixels.length > 0){ - this.loadPixels(); - } -}; - -/** - * Copies a region of pixels from one image to another. If no - * srcImage is specified this is used as the source. If the source - * and destination regions aren't the same size, it will - * automatically resize source pixels to fit the specified - * target region. - * - * @method copy - * @param {p5.Image|undefined} srcImage source image - * @param {Integer} sx X coordinate of the source's upper left corner - * @param {Integer} sy Y coordinate of the source's upper left corner - * @param {Integer} sw source image width - * @param {Integer} sh source image height - * @param {Integer} dx X coordinate of the destination's upper left corner - * @param {Integer} dy Y coordinate of the destination's upper left corner - * @param {Integer} dw destination image width - * @param {Integer} dh destination image height - * @example - * <div><code> - * var photo; - * var bricks; - * var x; - * var y; - * - * function preload() { - * photo = loadImage("assets/rockies.jpg"); - * bricks = loadImage("assets/bricks.jpg"); - * } - * - * function setup() { - * x = bricks.width/2; - * y = bricks.height/2; - * photo.copy(bricks, 0, 0, x, y, 0, 0, x, y); - * image(photo, 0, 0); - * } - * </code></div> - */ -p5.Image.prototype.copy = function () { - p5.prototype.copy.apply(this, arguments); -}; - -/** - * Masks part of an image from displaying by loading another - * image and using it's blue channel as an alpha channel for - * this image. - * - * @method mask - * @param {p5.Image} srcImage source image - * @example - * <div><code> - * var photo, maskImage; - * function preload() { - * photo = loadImage("assets/rockies.jpg"); - * maskImage = loadImage("assets/mask2.png"); - * } - * - * function setup() { - * createCanvas(100, 100); - * photo.mask(maskImage); - * image(photo, 0, 0); - * } - * </code></div> - * - * http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ - * - */ -// TODO: - Accept an array of alpha values. -// - Use other channels of an image. p5 uses the -// blue channel (which feels kind of arbitrary). Note: at the -// moment this method does not match native processings original -// functionality exactly. -p5.Image.prototype.mask = function(p5Image) { - if(p5Image === undefined){ - p5Image = this; - } - var currBlend = this.drawingContext.globalCompositeOperation; - - var scaleFactor = 1; - if (p5Image instanceof p5.Renderer) { - scaleFactor = p5Image._pInst._pixelDensity; - } - - var copyArgs = [ - p5Image, - 0, - 0, - scaleFactor*p5Image.width, - scaleFactor*p5Image.height, - 0, - 0, - this.width, - this.height - ]; - - this.drawingContext.globalCompositeOperation = 'destination-in'; - this.copy.apply(this, copyArgs); - this.drawingContext.globalCompositeOperation = currBlend; -}; - -/** - * Applies an image filter to a p5.Image - * - * @method filter - * @param {String} operation one of threshold, gray, invert, posterize and - * opaque see Filters.js for docs on each available - * filter - * @param {Number|undefined} value - * @example - * <div><code> - * var photo1; - * var photo2; - * - * function preload() { - * photo1 = loadImage("assets/rockies.jpg"); - * photo2 = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * photo2.filter("gray"); - * image(photo1, 0, 0); - * image(photo2, width/2, 0); - * } - * </code></div> - */ -p5.Image.prototype.filter = function(operation, value) { - Filters.apply(this.canvas, Filters[operation.toLowerCase()], value); -}; - -/** - * Copies a region of pixels from one image to another, using a specified - * blend mode to do the operation. - * - * @method blend - * @param {p5.Image|undefined} srcImage source image - * @param {Integer} sx X coordinate of the source's upper left corner - * @param {Integer} sy Y coordinate of the source's upper left corner - * @param {Integer} sw source image width - * @param {Integer} sh source image height - * @param {Integer} dx X coordinate of the destination's upper left corner - * @param {Integer} dy Y coordinate of the destination's upper left corner - * @param {Integer} dw destination image width - * @param {Integer} dh destination image height - * @param {Integer} blendMode the blend mode - * - * Available blend modes are: normal | multiply | screen | overlay | - * darken | lighten | color-dodge | color-burn | hard-light | - * soft-light | difference | exclusion | hue | saturation | - * color | luminosity - * - * - * http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ - * - */ -p5.Image.prototype.blend = function() { - p5.prototype.blend.apply(this, arguments); -}; - -/** - * Saves the image to a file and force the browser to download it. - * Accepts two strings for filename and file extension - * Supports png (default) and jpg. - * - * @method save - * @param {String} filename give your file a name - * @param {String} extension 'png' or 'jpg' - * @example - * <div><code> - * var photo; - * - * function preload() { - * photo = loadImage("assets/rockies.jpg"); - * } - * - * function draw() { - * image(photo, 0, 0); - * } - * - * function keyTyped() { - * if (key == 's') { - * photo.save("photo", "png"); - * } - * } - * </code></div> - */ -p5.Image.prototype.save = function(filename, extension) { - var mimeType; - if (!extension) { - extension = 'png'; - mimeType = 'image/png'; - } - else { - // en.wikipedia.org/wiki/Comparison_of_web_browsers#Image_format_support - switch(extension.toLowerCase()){ - case 'png': - mimeType = 'image/png'; - break; - case 'jpeg': - mimeType = 'image/jpeg'; - break; - case 'jpg': - mimeType = 'image/jpeg'; - break; - default: - mimeType = 'image/png'; - break; - } - } - var downloadMime = 'image/octet-stream'; - var imageData = this.canvas.toDataURL(mimeType); - imageData = imageData.replace(mimeType, downloadMime); - - //Make the browser download the file - p5.prototype.downloadFile(imageData, filename, extension); -}; - -/** - * creates a gl texture - * used in WEBGL mode only - * @param {[type]} tex [description] - * @return {[type]} [description] - */ -p5.Image.prototype.createTexture = function(tex){ - //this.texture = tex; - return this; -}; - -module.exports = p5.Image; - -},{"../core/core":48,"./filters":65}],69:[function(_dereq_,module,exports){ -/** - * @module Image - * @submodule Pixels - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var Filters = _dereq_('./filters'); -_dereq_('../color/p5.Color'); - -/** - * <a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference - * /Global_Objects/Uint8ClampedArray' target='_blank'>Uint8ClampedArray</a> - * containing the values for all the pixels in the display window. - * These values are numbers. This array is the size (include an appropriate - * factor for pixelDensity) of the display window x4, - * representing the R, G, B, A values in order for each pixel, moving from - * left to right across each row, then down each column. Retina and other - * high denisty displays will have more pixels[] (by a factor of - * pixelDensity^2). - * For example, if the image is 100x100 pixels, there will be 40,000. On a - * retina display, there will be 160,000. - * <br><br> - * The first four values (indices 0-3) in the array will be the R, G, B, A - * values of the pixel at (0, 0). The second four values (indices 4-7) will - * contain the R, G, B, A values of the pixel at (1, 0). More generally, to - * set values for a pixel at (x, y): - * <code><pre> - * var d = pixelDensity; - * for (var i = 0; i < d; i++) { - * for (var j = 0; j < d; j++) { - * // loop over - * idx = 4 * ((y * d + j) * width * d + (x * d + i)); - * pixels[idx] = r; - * pixels[idx+1] = g; - * pixels[idx+2] = b; - * pixels[idx+3] = a; - * } - * } - * </pre></code> - * - * <p>While the above method is complex, it is flexible enough to work with - * any pixelDensity. Note that set() will automatically take care of - * setting all the appropriate values in pixels[] for a given (x, y) at - * any pixelDensity, but the performance may not be as fast when lots of - * modifications are made to the pixel array. - * <br><br> - * Before accessing this array, the data must loaded with the loadPixels() - * function. After the array data has been modified, the updatePixels() - * function must be run to update the changes. - * <br><br> - * Note that this is not a standard javascript array. This means that - * standard javascript functions such as <code>slice()</code> or - * <code>arrayCopy()</code> do not - * work.</p> - * - * @property pixels[] - * @example - * <div> - * <code> - * var pink = color(255, 102, 204); - * loadPixels(); - * var d = pixelDensity(); - * var halfImage = 4 * (width * d) * (height/2 * d); - * for (var i = 0; i < halfImage; i+=4) { - * pixels[i] = red(pink); - * pixels[i+1] = green(pink); - * pixels[i+2] = blue(pink); - * pixels[i+3] = alpha(pink); - * } - * updatePixels(); - * </code> - * </div> - */ -p5.prototype.pixels = []; - -/** - * Copies a region of pixels from one image to another, using a specified - * blend mode to do the operation.<br><br> - * Available blend modes are: BLEND | DARKEST | LIGHTEST | DIFFERENCE | - * MULTIPLY| EXCLUSION | SCREEN | REPLACE | OVERLAY | HARD_LIGHT | - * SOFT_LIGHT | DODGE | BURN | ADD | NORMAL - * - * - * @method blend - * @param {p5.Image|undefined} srcImage source image - * @param {Integer} sx X coordinate of the source's upper left corner - * @param {Integer} sy Y coordinate of the source's upper left corner - * @param {Integer} sw source image width - * @param {Integer} sh source image height - * @param {Integer} dx X coordinate of the destination's upper left corner - * @param {Integer} dy Y coordinate of the destination's upper left corner - * @param {Integer} dw destination image width - * @param {Integer} dh destination image height - * @param {Integer} blendMode the blend mode - * - * @example - * <div><code> - * var img0; - * var img1; - * - * function preload() { - * img0 = loadImage("assets/rockies.jpg"); - * img1 = loadImage("assets/bricks_third.jpg"); - * } - * - * function setup() { - * background(img0); - * image(img1, 0, 0); - * blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, LIGHTEST); - * } - * </code></div> - * <div><code> - * var img0; - * var img1; - * - * function preload() { - * img0 = loadImage("assets/rockies.jpg"); - * img1 = loadImage("assets/bricks_third.jpg"); - * } - * - * function setup() { - * background(img0); - * image(img1, 0, 0); - * blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, DARKEST); - * } - * </code></div> - * <div><code> - * var img0; - * var img1; - * - * function preload() { - * img0 = loadImage("assets/rockies.jpg"); - * img1 = loadImage("assets/bricks_third.jpg"); - * } - * - * function setup() { - * background(img0); - * image(img1, 0, 0); - * blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, ADD); - * } - * </code></div> - */ -p5.prototype.blend = function() { - this._renderer.blend.apply(this._renderer, arguments); -}; - -/** - * Copies a region of the canvas to another region of the canvas - * and copies a region of pixels from an image used as the srcImg parameter - * into the canvas srcImage is specified this is used as the source. If - * the source and destination regions aren't the same size, it will - * automatically resize source pixels to fit the specified - * target region. - * - * @method copy - * @param {p5.Image|undefined} srcImage source image - * @param {Integer} sx X coordinate of the source's upper left corner - * @param {Integer} sy Y coordinate of the source's upper left corner - * @param {Integer} sw source image width - * @param {Integer} sh source image height - * @param {Integer} dx X coordinate of the destination's upper left corner - * @param {Integer} dy Y coordinate of the destination's upper left corner - * @param {Integer} dw destination image width - * @param {Integer} dh destination image height - * - * @example - * <div><code> - * var img; - * - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * background(img); - * copy(img, 7, 22, 10, 10, 35, 25, 50, 50); - * stroke(255); - * noFill(); - * // Rectangle shows area being copied - * rect(7, 22, 10, 10); - * } - * </code></div> - */ -p5.prototype.copy = function () { - p5.Renderer2D._copyHelper.apply(this, arguments); -}; - -/** - * Applies a filter to the canvas. - * <br><br> - * - * The presets options are: - * <br><br> - * - * THRESHOLD - * Converts the image to black and white pixels depending if they are above or - * below the threshold defined by the level parameter. The parameter must be - * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used. - * <br><br> - * - * GRAY - * Converts any colors in the image to grayscale equivalents. No parameter - * is used. - * <br><br> - * - * OPAQUE - * Sets the alpha channel to entirely opaque. No parameter is used. - * <br><br> - * - * INVERT - * Sets each pixel to its inverse value. No parameter is used. - * <br><br> - * - * POSTERIZE - * Limits each channel of the image to the number of colors specified as the - * parameter. The parameter can be set to values between 2 and 255, but - * results are most noticeable in the lower ranges. - * <br><br> - * - * BLUR - * Executes a Guassian blur with the level parameter specifying the extent - * of the blurring. If no parameter is used, the blur is equivalent to - * Guassian blur of radius 1. Larger values increase the blur. - * <br><br> - * - * ERODE - * Reduces the light areas. No parameter is used. - * <br><br> - * - * DILATE - * Increases the light areas. No parameter is used. - * - * @method filter - * @param {String} filterType - * @param {Number} filterParam an optional parameter unique - * to each filter, see above - * - * - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(THRESHOLD); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(GRAY); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(OPAQUE); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(INVERT); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(POSTERIZE,3); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(DILATE); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(BLUR,3); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/bricks.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * filter(ERODE); - * } - * </code> - * </div> - */ -p5.prototype.filter = function(operation, value) { - Filters.apply(this.canvas, Filters[operation.toLowerCase()], value); -}; - -/** - * Returns an array of [R,G,B,A] values for any pixel or grabs a section of - * an image. If no parameters are specified, the entire image is returned. - * Use the x and y parameters to get the value of one pixel. Get a section of - * the display window by specifying additional w and h parameters. When - * getting an image, the x and y parameters define the coordinates for the - * upper-left corner of the image, regardless of the current imageMode(). - * <br><br> - * If the pixel requested is outside of the image window, [0,0,0,255] is - * returned. To get the numbers scaled according to the current color ranges - * and taking into account colorMode, use getColor instead of get. - * <br><br> - * Getting the color of a single pixel with get(x, y) is easy, but not as fast - * as grabbing the data directly from pixels[]. The equivalent statement to - * get(x, y) using pixels[] with pixel density d is - * <code>[pixels[(y*width*d+x)*d], - * pixels[(y*width*d+x)*d+1], - * pixels[(y*width*d+x)*d+2], - * pixels[(y*width*d+x)*d+3]]</code>. - * <br><br> - * See the reference for pixels[] for more information. - * - * @method get - * @param {Number} [x] x-coordinate of the pixel - * @param {Number} [y] y-coordinate of the pixel - * @param {Number} [w] width - * @param {Number} [h] height - * @return {Array|p5.Image} values of pixel at x,y in array format - * [R, G, B, A] or p5.Image - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * var c = get(); - * image(c, width/2, 0); - * } - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * function setup() { - * image(img, 0, 0); - * var c = get(50, 90); - * fill(c); - * noStroke(); - * rect(25, 25, 50, 50); - * } - * </code> - * </div> - */ -p5.prototype.get = function(x, y, w, h){ - return this._renderer.get(x, y, w, h); -}; - -/** - * Loads the pixel data for the display window into the pixels[] array. This - * function must always be called before reading from or writing to pixels[]. - * - * @method loadPixels - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * image(img, 0, 0); - * var d = pixelDensity(); - * var halfImage = 4 * (img.width * d) * - (img.height/2 * d); - * loadPixels(); - * for (var i = 0; i < halfImage; i++) { - * pixels[i+halfImage] = pixels[i]; - * } - * updatePixels(); - * } - * </code> - * </div> - */ -p5.prototype.loadPixels = function() { - this._renderer.loadPixels(); -}; - -/** - * <p>Changes the color of any pixel, or writes an image directly to the - * display window.</p> - * <p>The x and y parameters specify the pixel to change and the c parameter - * specifies the color value. This can be a p5.Color object, or [R, G, B, A] - * pixel array. It can also be a single grayscale value. - * When setting an image, the x and y parameters define the coordinates for - * the upper-left corner of the image, regardless of the current imageMode(). - * </p> - * <p> - * After using set(), you must call updatePixels() for your changes to - * appear. This should be called once all pixels have been set. - * </p> - * <p>Setting the color of a single pixel with set(x, y) is easy, but not as - * fast as putting the data directly into pixels[]. Setting the pixels[] - * values directly may be complicated when working with a retina display, - * but will perform better when lots of pixels need to be set directly on - * every loop.</p> - * <p>See the reference for pixels[] for more information.</p> - * - * @method set - * @param {Number} x x-coordinate of the pixel - * @param {Number} y y-coordinate of the pixel - * @param {Number|Array|Object} c insert a grayscale value | a pixel array | - * a p5.Color object | a p5.Image to copy - * @example - * <div> - * <code> - * var black = color(0); - * set(30, 20, black); - * set(85, 20, black); - * set(85, 75, black); - * set(30, 75, black); - * updatePixels(); - * </code> - * </div> - * - * <div> - * <code> - * for (var i = 30; i < width-15; i++) { - * for (var j = 20; j < height-25; j++) { - * var c = color(204-j, 153-i, 0); - * set(i, j, c); - * } - * } - * updatePixels(); - * </code> - * </div> - * - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * set(0, 0, img); - * updatePixels(); - * line(0, 0, width, height); - * line(0, height, width, 0); - * } - * </code> - * </div> - */ -p5.prototype.set = function (x, y, imgOrCol) { - this._renderer.set(x, y, imgOrCol); -}; -/** - * Updates the display window with the data in the pixels[] array. - * Use in conjunction with loadPixels(). If you're only reading pixels from - * the array, there's no need to call updatePixels() — updating is only - * necessary to apply changes. updatePixels() should be called anytime the - * pixels array is manipulated or set() is called. - * - * @method updatePixels - * @param {Number} [x] x-coordinate of the upper-left corner of region - * to update - * @param {Number} [y] y-coordinate of the upper-left corner of region - * to update - * @param {Number} [w] width of region to update - * @param {Number} [w] height of region to update - * @example - * <div> - * <code> - * var img; - * function preload() { - * img = loadImage("assets/rockies.jpg"); - * } - * - * function setup() { - * image(img, 0, 0); - * var halfImage = 4 * (img.width * pixelDensity()) * - * (img.height * pixelDensity()/2); - * loadPixels(); - * for (var i = 0; i < halfImage; i++) { - * pixels[i+halfImage] = pixels[i]; - * } - * updatePixels(); - * } - * </code> - * </div> - */ -p5.prototype.updatePixels = function (x, y, w, h) { - // graceful fail - if loadPixels() or set() has not been called, pixel - // array will be empty, ignore call to updatePixels() - if (this.pixels.length === 0) { - return; - } - this._renderer.updatePixels(x, y, w, h); -}; - -module.exports = p5; - -},{"../color/p5.Color":42,"../core/core":48,"./filters":65}],70:[function(_dereq_,module,exports){ -/** - * @module IO - * @submodule Input - * @for p5 - * @requires core - * @requires reqwest - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var reqwest = _dereq_('reqwest'); -var opentype = _dereq_('opentype.js'); -_dereq_('../core/error_helpers'); - -/** - * Checks if we are in preload and returns the last arg which will be the - * _decrementPreload function if called from a loadX() function. Should - * only be used in loadX() functions. - * @private - */ -p5._getDecrementPreload = function () { - var decrementPreload = arguments[arguments.length - 1]; - - // when in preload decrementPreload will always be the last arg as it is set - // with args.push() before invocation in _wrapPreload - if ((window.preload || (this && this.preload)) && - typeof decrementPreload === 'function') { - return decrementPreload; - } else { - return null; - } -}; - -/** - * Loads an opentype font file (.otf, .ttf) from a file or a URL, - * and returns a PFont Object. This method is asynchronous, - * meaning it may not finish before the next line in your sketch - * is executed. - * <br><br> - * The path to the font should be relative to the HTML file - * that links in your sketch. Loading an from a URL or other - * remote location may be blocked due to your browser's built-in - * security. - * - * @method loadFont - * @param {String} path name of the file or url to load - * @param {Function} [callback] function to be executed after - * loadFont() - * completes - * @return {Object} p5.Font object - * @example - * - * <p>Calling loadFont() inside preload() guarantees that the load - * operation will have completed before setup() and draw() are called.</p> - * - * <div><code> - * var myFont; - * function preload() { - * myFont = loadFont('assets/AvenirNextLTPro-Demi.otf'); - * } - * - * function setup() { - * fill('#ED225D'); - * textFont(myFont); - * textSize(36); - * text('p5*js', 10, 50); - * } - * </code></div> - * - * <p>Outside of preload(), you may supply a callback function to handle the - * object:</p> - * - * <div><code> - * function setup() { - * loadFont('assets/AvenirNextLTPro-Demi.otf', drawText); - * } - * - * function drawText(font) { - * fill('#ED225D'); - * textFont(font, 36); - * text('p5*js', 10, 50); - * } - * - * </code></div> - * - * <p>You can also use the string name of the font to style other HTML - * elements.</p> - * - * <div><code> - * var myFont; - * - * function preload() { - * myFont = loadFont('assets/Avenir.otf'); - * } - * - * function setup() { - * var myDiv = createDiv('hello there'); - * myDiv.style('font-family', 'Avenir'); - * } - * </code></div> - */ -p5.prototype.loadFont = function (path, onSuccess, onError) { - - var p5Font = new p5.Font(this); - var decrementPreload = p5._getDecrementPreload.apply(this, arguments); - - opentype.load(path, function (err, font) { - - if (err) { - - if ((typeof onError !== 'undefined') && (onError !== decrementPreload)) { - return onError(err); - } - throw err; - } - - p5Font.font = font; - - if (typeof onSuccess !== 'undefined') { - onSuccess(p5Font); - } - - if (decrementPreload && (onSuccess !== decrementPreload)) { - decrementPreload(); - } - - // check that we have an acceptable font type - var validFontTypes = [ 'ttf', 'otf', 'woff', 'woff2' ], - fileNoPath = path.split('\\').pop().split('/').pop(), - lastDotIdx = fileNoPath.lastIndexOf('.'), fontFamily, newStyle, - fileExt = lastDotIdx < 1 ? null : fileNoPath.substr(lastDotIdx + 1); - - // if so, add it to the DOM (name-only) for use with p5.dom - if (validFontTypes.indexOf(fileExt) > -1) { - - fontFamily = fileNoPath.substr(0, lastDotIdx); - newStyle = document.createElement('style'); - newStyle.appendChild(document.createTextNode('\n@font-face {' + - '\nfont-family: ' + fontFamily + ';\nsrc: url(' + path + ');\n}\n')); - document.head.appendChild(newStyle); - } - - }); - - return p5Font; -}; - -//BufferedReader -p5.prototype.createInput = function () { - // TODO - throw 'not yet implemented'; -}; - -p5.prototype.createReader = function () { - // TODO - throw 'not yet implemented'; -}; - -p5.prototype.loadBytes = function () { - // TODO - throw 'not yet implemented'; -}; - -/** - * Loads a JSON file from a file or a URL, and returns an Object or Array. - * This method is asynchronous, meaning it may not finish before the next - * line in your sketch is executed. - * - * @method loadJSON - * @param {String} path name of the file or url to load - * @param {Function} [callback] function to be executed after - * loadJSON() completes, data is passed - * in as first argument - * @param {Function} [errorCallback] function to be executed if - * there is an error, response is passed - * in as first argument - * @param {String} [datatype] "json" or "jsonp" - * @return {Object|Array} JSON data - * @example - * - * <p>Calling loadJSON() inside preload() guarantees to complete the - * operation before setup() and draw() are called.</p> - * - * <div><code> - * var weather; - * function preload() { - * var url = 'http://api.openweathermap.org/data/2.5/weather?q=London,UK'+ - * '&APPID=7bbbb47522848e8b9c26ba35c226c734'; - * weather = loadJSON(url); - * } - * - * function setup() { - * noLoop(); - * } - * - * function draw() { - * background(200); - * // get the humidity value out of the loaded JSON - * var humidity = weather.main.humidity; - * fill(0, humidity); // use the humidity value to set the alpha - * ellipse(width/2, height/2, 50, 50); - * } - * </code></div> - * - * - * <p>Outside of preload(), you may supply a callback function to handle the - * object:</p> - * <div><code> - * function setup() { - * noLoop(); - * var url = 'http://api.openweathermap.org/data/2.5/weather?q=NewYork'+ - * '&APPID=7bbbb47522848e8b9c26ba35c226c734'; - * loadJSON(url, drawWeather); - * } - * - * function draw() { - * background(200); - * } - * - * function drawWeather(weather) { - * // get the humidity value out of the loaded JSON - * var humidity = weather.main.humidity; - * fill(0, humidity); // use the humidity value to set the alpha - * ellipse(width/2, height/2, 50, 50); - * } - * </code></div> - * - */ -p5.prototype.loadJSON = function () { - var path = arguments[0]; - var callback = arguments[1]; - var errorCallback; - var decrementPreload = p5._getDecrementPreload.apply(this, arguments); - - var ret = []; // array needed for preload - // assume jsonp for URLs - var t = 'json'; //= path.indexOf('http') === -1 ? 'json' : 'jsonp'; - - // check for explicit data type argument - for (var i = 2; i < arguments.length; i++) { - var arg = arguments[i]; - if (typeof arg === 'string') { - if (arg === 'jsonp' || arg === 'json') { - t = arg; - } - } else if (typeof arg === 'function') { - errorCallback = arg; - } - } - - reqwest({ - url: path, - type: t, - crossOrigin: true, - error: function (resp) { - // pass to error callback if defined - if (errorCallback) { - errorCallback(resp); - } else { // otherwise log error msg - console.log(resp.statusText); - } - }, - success: function (resp) { - for (var k in resp) { - ret[k] = resp[k]; - } - if (typeof callback !== 'undefined') { - callback(resp); - } - if (decrementPreload && (callback !== decrementPreload)) { - decrementPreload(); - } - } - }); - - return ret; -}; - -/** - * Reads the contents of a file and creates a String array of its individual - * lines. If the name of the file is used as the parameter, as in the above - * example, the file must be located in the sketch directory/folder. - * <br><br> - * Alternatively, the file maybe be loaded from anywhere on the local - * computer using an absolute path (something that starts with / on Unix and - * Linux, or a drive letter on Windows), or the filename parameter can be a - * URL for a file found on a network. - * <br><br> - * This method is asynchronous, meaning it may not finish before the next - * line in your sketch is executed. - * - * @method loadStrings - * @param {String} filename name of the file or url to load - * @param {Function} [callback] function to be executed after loadStrings() - * completes, Array is passed in as first - * argument - * @param {Function} [errorCallback] function to be executed if - * there is an error, response is passed - * in as first argument - * @return {Array} Array of Strings - * @example - * - * <p>Calling loadStrings() inside preload() guarantees to complete the - * operation before setup() and draw() are called.</p> - * - * <div><code> - * var result; - * function preload() { - * result = loadStrings('assets/test.txt'); - * } - - * function setup() { - * background(200); - * var ind = floor(random(result.length)); - * text(result[ind], 10, 10, 80, 80); - * } - * </code></div> - * - * <p>Outside of preload(), you may supply a callback function to handle the - * object:</p> - * - * <div><code> - * function setup() { - * loadStrings('assets/test.txt', pickString); - * } - * - * function pickString(result) { - * background(200); - * var ind = floor(random(result.length)); - * text(result[ind], 10, 10, 80, 80); - * } - * </code></div> - */ -p5.prototype.loadStrings = function (path, callback, errorCallback) { - var ret = []; - var req = new XMLHttpRequest(); - var decrementPreload = p5._getDecrementPreload.apply(this, arguments); - - req.addEventListener('error', function (resp) { - if (errorCallback) { - errorCallback(resp); - } else { - console.log(resp.responseText); - } - }); - - req.open('GET', path, true); - req.onreadystatechange = function () { - if (req.readyState === 4) { - if (req.status === 200) { - var arr = req.responseText.match(/[^\r\n]+/g); - for (var k in arr) { - ret[k] = arr[k]; - } - if (typeof callback !== 'undefined') { - callback(ret); - } - if (decrementPreload && (callback !== decrementPreload)) { - decrementPreload(); - } - } else { - if (errorCallback) { - errorCallback(req); - } else { - console.log(req.statusText); - } - //p5._friendlyFileLoadError(3, path); - } - } - }; - req.send(null); - return ret; -}; - -/** - * <p>Reads the contents of a file or URL and creates a p5.Table object with - * its values. If a file is specified, it must be located in the sketch's - * "data" folder. The filename parameter can also be a URL to a file found - * online. By default, the file is assumed to be comma-separated (in CSV - * format). Table only looks for a header row if the 'header' option is - * included.</p> - * - * <p>Possible options include: - * <ul> - * <li>csv - parse the table as comma-separated values</li> - * <li>tsv - parse the table as tab-separated values</li> - * <li>header - this table has a header (title) row</li> - * </ul> - * </p> - * - * <p>When passing in multiple options, pass them in as separate parameters, - * seperated by commas. For example: - * <br><br> - * <code> - * loadTable("my_csv_file.csv", "csv", "header") - * </code> - * </p> - * - * <p> All files loaded and saved use UTF-8 encoding.</p> - * - * <p>This method is asynchronous, meaning it may not finish before the next - * line in your sketch is executed. Calling loadTable() inside preload() - * guarantees to complete the operation before setup() and draw() are called. - * <p>Outside of preload(), you may supply a callback function to handle the - * object:</p> - * </p> - * - * @method loadTable - * @param {String} filename name of the file or URL to load - * @param {String|Strings} [options] "header" "csv" "tsv" - * @param {Function} [callback] function to be executed after - * loadTable() completes, Table object is - * passed in as first argument - * @return {Object} Table object containing data - * - * @example - * <div class="norender"> - * <code> - * // Given the following CSV file called "mammals.csv" - * // located in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * //the file can be remote - * //table = loadTable("http://p5js.org/reference/assets/mammals.csv", - * // "csv", "header"); - * } - * - * function setup() { - * //count the columns - * print(table.getRowCount() + " total rows in table"); - * print(table.getColumnCount() + " total columns in table"); - * - * print(table.getColumn("name")); - * //["Goat", "Leopard", "Zebra"] - * - * //cycle through the table - * for (var r = 0; r < table.getRowCount(); r++) - * for (var c = 0; c < table.getColumnCount(); c++) { - * print(table.getString(r, c)); - * } - * } - * </code> - * </div> - */ -p5.prototype.loadTable = function (path) { - var callback = null; - var options = []; - var header = false; - var sep = ','; - var separatorSet = false; - var decrementPreload = p5._getDecrementPreload.apply(this, arguments); - - for (var i = 1; i < arguments.length; i++) { - if ((typeof (arguments[i]) === 'function') && - (arguments[i] !== decrementPreload)) { - callback = arguments[i]; - } else if (typeof (arguments[i]) === 'string') { - options.push(arguments[i]); - if (arguments[i] === 'header') { - header = true; - } - if (arguments[i] === 'csv') { - if (separatorSet) { - throw new Error('Cannot set multiple separator types.'); - } else { - sep = ','; - separatorSet = true; - } - } else if (arguments[i] === 'tsv') { - if (separatorSet) { - throw new Error('Cannot set multiple separator types.'); - } else { - sep = '\t'; - separatorSet = true; - } - } - } - } - - var t = new p5.Table(); - reqwest({ - url: path, - crossOrigin: true, - type: 'csv' - }) - .then(function (resp) { - resp = resp.responseText; - - var state = {}; - - // define constants - var PRE_TOKEN = 0, - MID_TOKEN = 1, - POST_TOKEN = 2, - POST_RECORD = 4; - - var QUOTE = '\"', - CR = '\r', - LF = '\n'; - - var records = []; - var offset = 0; - var currentRecord = null; - var currentChar; - - var recordBegin = function () { - state.escaped = false; - currentRecord = []; - tokenBegin(); - }; - - var recordEnd = function () { - state.currentState = POST_RECORD; - records.push(currentRecord); - currentRecord = null; - }; - - var tokenBegin = function () { - state.currentState = PRE_TOKEN; - state.token = ''; - }; - - var tokenEnd = function () { - currentRecord.push(state.token); - tokenBegin(); - }; - - while (true) { - currentChar = resp[offset++]; - - // EOF - if (currentChar == null) { - if (state.escaped) { - throw new Error('Unclosed quote in file.'); - } - if (currentRecord) { - tokenEnd(); - recordEnd(); - break; - } - } - if (currentRecord === null) { - recordBegin(); - } - - // Handle opening quote - if (state.currentState === PRE_TOKEN) { - if (currentChar === QUOTE) { - state.escaped = true; - state.currentState = MID_TOKEN; - continue; - } - state.currentState = MID_TOKEN; - } - - // mid-token and escaped, look for sequences and end quote - if (state.currentState === MID_TOKEN && state.escaped) { - if (currentChar === QUOTE) { - if (resp[offset] === QUOTE) { - state.token += QUOTE; - offset++; - } else { - state.escaped = false; - state.currentState = POST_TOKEN; - } - } else { - state.token += currentChar; - } - continue; - } - - // fall-through: mid-token or post-token, not escaped - if (currentChar === CR) { - if (resp[offset] === LF) { - offset++; - } - tokenEnd(); - recordEnd(); - } else if (currentChar === LF) { - tokenEnd(); - recordEnd(); - } else if (currentChar === sep) { - tokenEnd(); - } else if (state.currentState === MID_TOKEN) { - state.token += currentChar; - } - } - - // set up column names - if (header) { - t.columns = records.shift(); - } else { - for (i = 0; i < records[0].length; i++) { - t.columns[i] = 'null'; - } - } - var row; - for (i = 0; i < records.length; i++) { - //Handles row of 'undefined' at end of some CSVs - if (i === records.length - 1 && records[i].length === 1) { - if (records[i][0] === 'undefined') { - break; - } - } - row = new p5.TableRow(); - row.arr = records[i]; - row.obj = makeObject(records[i], t.columns); - t.addRow(row); - } - if (callback !== null) { - callback(t); - } - if (decrementPreload && (callback !== decrementPreload)) { - decrementPreload(); - } - }) - .fail(function (err, msg) { - p5._friendlyFileLoadError(2, path); - // don't get error callback mixed up with decrementPreload - if ((typeof callback !== 'undefined') && - (callback !== decrementPreload)) { - callback(false); - } - }); - - return t; -}; - -// helper function to turn a row into a JSON object -function makeObject(row, headers) { - var ret = {}; - headers = headers || []; - if (typeof (headers) === 'undefined') { - for (var j = 0; j < row.length; j++) { - headers[j.toString()] = j; - } - } - for (var i = 0; i < headers.length; i++) { - var key = headers[i]; - var val = row[i]; - ret[key] = val; - } - return ret; -} - -/** - * Reads the contents of a file and creates an XML object with its values. - * If the name of the file is used as the parameter, as in the above example, - * the file must be located in the sketch directory/folder. - * <br><br> - * Alternatively, the file maybe be loaded from anywhere on the local - * computer using an absolute path (something that starts with / on Unix and - * Linux, or a drive letter on Windows), or the filename parameter can be a - * URL for a file found on a network. - * <br><br> - * This method is asynchronous, meaning it may not finish before the next - * line in your sketch is executed. Calling loadXML() inside preload() - * guarantees to complete the operation before setup() and draw() are called. - * <br><br> - * Outside of preload(), you may supply a callback function to handle the - * object: - * - * @method loadXML - * @param {String} filename name of the file or URL to load - * @param {Function} [callback] function to be executed after loadXML() - * completes, XML object is passed in as - * first argument - * @param {Function} [errorCallback] function to be executed if - * there is an error, response is passed - * in as first argument - * @return {Object} XML object containing data - */ -p5.prototype.loadXML = function (path, callback, errorCallback) { - var ret = document.implementation.createDocument(null, null); - var decrementPreload = p5._getDecrementPreload.apply(this, arguments); - - reqwest({ - url: path, - type: 'xml', - crossOrigin: true, - error: function (resp) { - // pass to error callback if defined - if (errorCallback) { - errorCallback(resp); - } else { // otherwise log error msg - console.log(resp.statusText); - } - //p5._friendlyFileLoadError(1,path); - } - }) - .then(function (resp) { - var x = resp.documentElement; - ret.appendChild(x); - if (typeof callback !== 'undefined') { - callback(ret); - } - if (decrementPreload && (callback !== decrementPreload)) { - decrementPreload(); - } - }); - return ret; -}; - -// name clash with window.open -// p5.prototype.open = function() { -// // TODO - -// }; - -p5.prototype.parseXML = function () { - // TODO - throw 'not yet implemented'; - -}; - -p5.prototype.selectFolder = function () { - // TODO - throw 'not yet implemented'; - -}; - -p5.prototype.selectInput = function () { - // TODO - throw 'not yet implemented'; - -}; - -/** - * Method for executing an HTTP GET request. If data type is not specified, - * p5 will try to guess based on the URL, defaulting to text. - * - * @method httpGet - * @param {String} path name of the file or url to load - * @param {Object} [data] param data passed sent with request - * @param {String} [datatype] "json", "jsonp", "xml", or "text" - * @param {Function} [callback] function to be executed after - * httpGet() completes, data is passed in - * as first argument - * @param {Function} [errorCallback] function to be executed if - * there is an error, response is passed - * in as first argument - */ -p5.prototype.httpGet = function () { - var args = Array.prototype.slice.call(arguments); - args.push('GET'); - p5.prototype.httpDo.apply(this, args); -}; - -/** - * Method for executing an HTTP POST request. If data type is not specified, - * p5 will try to guess based on the URL, defaulting to text. - * - * @method httpPost - * @param {String} path name of the file or url to load - * @param {Object} [data] param data passed sent with request - * @param {String} [datatype] "json", "jsonp", "xml", or "text" - * @param {Function} [callback] function to be executed after - * httpGet() completes, data is passed in - * as first argument - * @param {Function} [errorCallback] function to be executed if - * there is an error, response is passed - * in as first argument - */ -p5.prototype.httpPost = function () { - var args = Array.prototype.slice.call(arguments); - args.push('POST'); - p5.prototype.httpDo.apply(this, args); -}; - -/** - * Method for executing an HTTP request. If data type is not specified, - * p5 will try to guess based on the URL, defaulting to text.<br><br> - * You may also pass a single object specifying all parameters for the - * request following the examples inside the reqwest() calls here: - * <a href='https://github.com/ded/reqwest#api' - * >https://github.com/ded/reqwest#api</a> - * - * @method httpDo - * @param {String} path name of the file or url to load - * @param {String} [method] either "GET", "POST", or "PUT", - * defaults to "GET" - * @param {Object} [data] param data passed sent with request - * @param {String} [datatype] "json", "jsonp", "xml", or "text" - * @param {Function} [callback] function to be executed after - * httpGet() completes, data is passed in - * as first argument - * @param {Function} [errorCallback] function to be executed if - * there is an error, response is passed - * in as first argument - */ -p5.prototype.httpDo = function () { - if (typeof arguments[0] === 'object') { - reqwest(arguments[0]); - } else { - var method = 'GET'; - var path = arguments[0]; - var data = {}; - var type = ''; - var callback; - var errorCallback; - - for (var i = 1; i < arguments.length; i++) { - var a = arguments[i]; - if (typeof a === 'string') { - if (a === 'GET' || a === 'POST' || a === 'PUT') { - method = a; - } else { - type = a; - } - } else if (typeof a === 'object') { - data = a; - } else if (typeof a === 'function') { - if (!callback) { - callback = a; - } else { - errorCallback = a; - } - } - } - - // do some sort of smart type checking - if (type === '') { - if (path.indexOf('json') !== -1) { - type = 'json'; - } else if (path.indexOf('xml') !== -1) { - type = 'xml'; - } else { - type = 'text'; - } - } - - reqwest({ - url: path, - method: method, - data: data, - type: type, - crossOrigin: true, - success: function (resp) { - if (typeof callback !== 'undefined') { - if (type === 'text') { - callback(resp.response); - } else { - callback(resp); - } - } - }, - error: function (resp) { - if (errorCallback) { - errorCallback(resp); - } else { - console.log(resp.statusText); - } - } - }); - } -}; - -/** - * @module IO - * @submodule Output - * @for p5 - */ - -window.URL = window.URL || window.webkitURL; - -// private array of p5.PrintWriter objects -p5.prototype._pWriters = []; - -p5.prototype.beginRaw = function () { - // TODO - throw 'not yet implemented'; - -}; - -p5.prototype.beginRecord = function () { - // TODO - throw 'not yet implemented'; - -}; - -p5.prototype.createOutput = function () { - // TODO - - throw 'not yet implemented'; -}; - -p5.prototype.createWriter = function (name, extension) { - var newPW; - // check that it doesn't already exist - for (var i in p5.prototype._pWriters) { - if (p5.prototype._pWriters[i].name === name) { - // if a p5.PrintWriter w/ this name already exists... - // return p5.prototype._pWriters[i]; // return it w/ contents intact. - // or, could return a new, empty one with a unique name: - newPW = new p5.PrintWriter(name + window.millis(), extension); - p5.prototype._pWriters.push(newPW); - return newPW; - } - } - newPW = new p5.PrintWriter(name, extension); - p5.prototype._pWriters.push(newPW); - return newPW; -}; - -p5.prototype.endRaw = function () { - // TODO - - throw 'not yet implemented'; -}; - -p5.prototype.endRecord = function () { - // TODO - throw 'not yet implemented'; - -}; - -p5.PrintWriter = function (filename, extension) { - var self = this; - this.name = filename; - this.content = ''; - this.print = function (data) { - this.content += data; - }; - this.println = function (data) { - this.content += data + '\n'; - }; - this.flush = function () { - this.content = ''; - }; - this.close = function () { - // convert String to Array for the writeFile Blob - var arr = []; - arr.push(this.content); - p5.prototype.writeFile(arr, filename, extension); - // remove from _pWriters array and delete self - for (var i in p5.prototype._pWriters) { - if (p5.prototype._pWriters[i].name === this.name) { - // remove from _pWriters array - p5.prototype._pWriters.splice(i, 1); - } - } - self.flush(); - self = {}; - }; -}; - -p5.prototype.saveBytes = function () { - // TODO - throw 'not yet implemented'; - -}; - -// object, filename, options --> saveJSON, saveStrings, saveTable -// filename, [extension] [canvas] --> saveImage - -/** - * <p>Save an image, text, json, csv, wav, or html. Prompts download to - * the client's computer. <b>Note that it is not recommended to call save() - * within draw if it's looping, as the save() function will open a new save - * dialog every frame.</b></p> - * <p>The default behavior is to save the canvas as an image. You can - * optionally specify a filename. - * For example:</p> - * <pre class='language-javascript'><code> - * save(); - * save('myCanvas.jpg'); // save a specific canvas with a filename - * </code></pre> - * - * <p>Alternately, the first parameter can be a pointer to a canvas - * p5.Element, an Array of Strings, - * an Array of JSON, a JSON object, a p5.Table, a p5.Image, or a - * p5.SoundFile (requires p5.sound). The second parameter is a filename - * (including extension). The third parameter is for options specific - * to this type of object. This method will save a file that fits the - * given paramaters. For example:</p> - * - * <pre class='language-javascript'><code> - * - * save('myCanvas.jpg'); // Saves canvas as an image - * - * var cnv = createCanvas(100, 100); - * save(cnv, 'myCanvas.jpg'); // Saves canvas as an image - * - * var gb = createGraphics(100, 100); - * save(gb, 'myGraphics.jpg'); // Saves p5.Renderer object as an image - * - * save(myTable, 'myTable.html'); // Saves table as html file - * save(myTable, 'myTable.csv',); // Comma Separated Values - * save(myTable, 'myTable.tsv'); // Tab Separated Values - * - * save(myJSON, 'my.json'); // Saves pretty JSON - * save(myJSON, 'my.json', true); // Optimizes JSON filesize - * - * save(img, 'my.png'); // Saves pImage as a png image - * - * save(arrayOfStrings, 'my.txt'); // Saves strings to a text file with line - * // breaks after each item in the array - * </code></pre> - * - * @method save - * @param {[Object|String]} objectOrFilename If filename is provided, will - * save canvas as an image with - * either png or jpg extension - * depending on the filename. - * If object is provided, will - * save depending on the object - * and filename (see examples - * above). - * @param {[String]} filename If an object is provided as the first - * parameter, then the second parameter - * indicates the filename, - * and should include an appropriate - * file extension (see examples above). - * @param {[Boolean/String]} options Additional options depend on - * filetype. For example, when saving JSON, - * <code>true</code> indicates that the - * output will be optimized for filesize, - * rather than readability. - */ -p5.prototype.save = function (object, _filename, _options) { - // parse the arguments and figure out which things we are saving - var args = arguments; - // ================================================= - // OPTION 1: saveCanvas... - - // if no arguments are provided, save canvas - var cnv = this._curElement.elt; - if (args.length === 0) { - p5.prototype.saveCanvas(cnv); - return; - } - // otherwise, parse the arguments - - // if first param is a p5Graphics, then saveCanvas - else if (args[0] instanceof p5.Renderer || - args[0] instanceof p5.Graphics) { - p5.prototype.saveCanvas(args[0].elt, args[1], args[2]); - return; - } - - // if 1st param is String and only one arg, assume it is canvas filename - else if (args.length === 1 && typeof (args[0]) === 'string') { - p5.prototype.saveCanvas(cnv, args[0]); - } - - // ================================================= - // OPTION 2: extension clarifies saveStrings vs. saveJSON - else { - var extension = _checkFileExtension(args[1], args[2])[1]; - switch (extension) { - case 'json': - p5.prototype.saveJSON(args[0], args[1], args[2]); - return; - case 'txt': - p5.prototype.saveStrings(args[0], args[1], args[2]); - return; - // ================================================= - // OPTION 3: decide based on object... - default: - if (args[0] instanceof Array) { - p5.prototype.saveStrings(args[0], args[1], args[2]); - } else if (args[0] instanceof p5.Table) { - p5.prototype.saveTable(args[0], args[1], args[2], args[3]); - } else if (args[0] instanceof p5.Image) { - p5.prototype.saveCanvas(args[0].canvas, args[1]); - } else if (args[0] instanceof p5.SoundFile) { - p5.prototype.saveSound(args[0], args[1], args[2], args[3]); - } - } - } -}; - -/** - * Writes the contents of an Array or a JSON object to a .json file. - * The file saving process and location of the saved file will - * vary between web browsers. - * - * @method saveJSON - * @param {Array|Object} json - * @param {String} filename - * @param {Boolean} [optimize] If true, removes line breaks - * and spaces from the output - * file to optimize filesize - * (but not readability). - * @example - * <div><code> - * var json; - * - * function setup() { - * - * json = {}; // new JSON Object - * - * json.id = 0; - * json.species = 'Panthera leo'; - * json.name = 'Lion'; - * - * // To save, un-comment the line below, then click 'run' - * // saveJSONObject(json, 'lion.json'); - * } - * - * // Saves the following to a file called "lion.json": - * // { - * // "id": 0, - * // "species": "Panthera leo", - * // "name": "Lion" - * // } - * </div></code> - */ -p5.prototype.saveJSON = function (json, filename, opt) { - var stringify; - if (opt) { - stringify = JSON.stringify(json); - } else { - stringify = JSON.stringify(json, undefined, 2); - } - console.log(stringify); - this.saveStrings(stringify.split('\n'), filename, 'json'); -}; - -p5.prototype.saveJSONObject = p5.prototype.saveJSON; -p5.prototype.saveJSONArray = p5.prototype.saveJSON; - -p5.prototype.saveStream = function () { - // TODO - throw 'not yet implemented'; - -}; - -/** - * Writes an array of Strings to a text file, one line per String. - * The file saving process and location of the saved file will - * vary between web browsers. - * - * @method saveStrings - * @param {Array} list string array to be written - * @param {String} filename filename for output - * @example - * <div><code> - * var words = 'apple bear cat dog'; - * - * // .split() outputs an Array - * var list = split(words, ' '); - * - * // To save the file, un-comment next line and click 'run' - * // saveStrings(list, 'nouns.txt'); - * - * // Saves the following to a file called 'nouns.txt': - * // - * // apple - * // bear - * // cat - * // dog - * </code></div> - */ -p5.prototype.saveStrings = function (list, filename, extension) { - var ext = extension || 'txt'; - var pWriter = this.createWriter(filename, ext); - for (var i = 0; i < list.length; i++) { - if (i < list.length - 1) { - pWriter.println(list[i]); - } else { - pWriter.print(list[i]); - } - } - pWriter.close(); - pWriter.flush(); -}; - -p5.prototype.saveXML = function () { - // TODO - throw 'not yet implemented'; - -}; - -p5.prototype.selectOutput = function () { - // TODO - throw 'not yet implemented'; - -}; - -// ======= -// HELPERS -// ======= - -function escapeHelper(content) { - return content - .replace(/&/g, '&') - .replace(/</g, '<') - .replace(/>/g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - -/** - * Writes the contents of a Table object to a file. Defaults to a - * text file with comma-separated-values ('csv') but can also - * use tab separation ('tsv'), or generate an HTML table ('html'). - * The file saving process and location of the saved file will - * vary between web browsers. - * - * @method saveTable - * @param {p5.Table} Table the Table object to save to a file - * @param {String} filename the filename to which the Table should be saved - * @param {String} [options] can be one of "tsv", "csv", or "html" - * @example - * <div><code> - * var table; - * - * function setup() { - * table = new p5.Table(); - * - * table.addColumn('id'); - * table.addColumn('species'); - * table.addColumn('name'); - * - * var newRow = table.addRow(); - * newRow.setNum('id', table.getRowCount() - 1); - * newRow.setString('species', 'Panthera leo'); - * newRow.setString('name', 'Lion'); - * - * // To save, un-comment next line then click 'run' - * // saveTable(table, 'new.csv'); - * } - * - * // Saves the following to a file called 'new.csv': - * // id,species,name - * // 0,Panthera leo,Lion - * </code></div> - */ -p5.prototype.saveTable = function (table, filename, options) { - var pWriter = this.createWriter(filename, options); - - var header = table.columns; - - var sep = ','; // default to CSV - if (options === 'tsv') { - sep = '\t'; - } - if (options !== 'html') { - // make header if it has values - if (header[0] !== '0') { - for (var h = 0; h < header.length; h++) { - if (h < header.length - 1) { - pWriter.print(header[h] + sep); - } else { - pWriter.println(header[h]); - } - } - } - - // make rows - for (var i = 0; i < table.rows.length; i++) { - var j; - for (j = 0; j < table.rows[i].arr.length; j++) { - if (j < table.rows[i].arr.length - 1) { - pWriter.print(table.rows[i].arr[j] + sep); - } else if (i < table.rows.length - 1) { - pWriter.println(table.rows[i].arr[j]); - } else { - pWriter.print(table.rows[i].arr[j]); // no line break - } - } - } - } - - // otherwise, make HTML - else { - pWriter.println('<html>'); - pWriter.println('<head>'); - var str = ' <meta http-equiv=\"content-type\" content'; - str += '=\"text/html;charset=utf-8\" />'; - pWriter.println(str); - pWriter.println('</head>'); - - pWriter.println('<body>'); - pWriter.println(' <table>'); - - // make header if it has values - if (header[0] !== '0') { - pWriter.println(' <tr>'); - for (var k = 0; k < header.length; k++) { - var e = escapeHelper(header[k]); - pWriter.println(' <td>' + e); - pWriter.println(' </td>'); - } - pWriter.println(' </tr>'); - } - - // make rows - for (var row = 0; row < table.rows.length; row++) { - pWriter.println(' <tr>'); - for (var col = 0; col < table.columns.length; col++) { - var entry = table.rows[row].getString(col); - var htmlEntry = escapeHelper(entry); - pWriter.println(' <td>' + htmlEntry); - pWriter.println(' </td>'); - } - pWriter.println(' </tr>'); - } - pWriter.println(' </table>'); - pWriter.println('</body>'); - pWriter.print('</html>'); - } - // close and flush the pWriter - pWriter.close(); - pWriter.flush(); -}; // end saveTable() - -/** - * Generate a blob of file data as a url to prepare for download. - * Accepts an array of data, a filename, and an extension (optional). - * This is a private function because it does not do any formatting, - * but it is used by saveStrings, saveJSON, saveTable etc. - * - * @param {Array} dataToDownload - * @param {String} filename - * @param {[String]} extension - * @private - */ -p5.prototype.writeFile = function (dataToDownload, filename, extension) { - var type = 'application\/octet-stream'; - if (p5.prototype._isSafari()) { - type = 'text\/plain'; - } - var blob = new Blob(dataToDownload, { - 'type': type - }); - var href = window.URL.createObjectURL(blob); - p5.prototype.downloadFile(href, filename, extension); -}; - -/** - * Forces download. Accepts a url to filedata/blob, a filename, - * and an extension (optional). - * This is a private function because it does not do any formatting, - * but it is used by saveStrings, saveJSON, saveTable etc. - * - * @param {String} href i.e. an href generated by createObjectURL - * @param {[String]} filename - * @param {[String]} extension - */ -p5.prototype.downloadFile = function (href, fName, extension) { - var fx = _checkFileExtension(fName, extension); - var filename = fx[0]; - var ext = fx[1]; - - var a = document.createElement('a'); - a.href = href; - a.download = filename; - - // Firefox requires the link to be added to the DOM before click() - a.onclick = destroyClickedElement; - a.style.display = 'none'; - document.body.appendChild(a); - - // Safari will open this file in the same page as a confusing Blob. - if (p5.prototype._isSafari()) { - var aText = 'Hello, Safari user! To download this file...\n'; - aText += '1. Go to File --> Save As.\n'; - aText += '2. Choose "Page Source" as the Format.\n'; - aText += '3. Name it with this extension: .\"' + ext + '\"'; - alert(aText); - } - a.click(); - href = null; -}; - -/** - * Returns a file extension, or another string - * if the provided parameter has no extension. - * - * @param {String} filename - * @return {Array} [fileName, fileExtension] - * - * @private - */ -function _checkFileExtension(filename, extension) { - if (!extension || extension === true || extension === 'true') { - extension = ''; - } - if (!filename) { - filename = 'untitled'; - } - var ext = ''; - // make sure the file will have a name, see if filename needs extension - if (filename && filename.indexOf('.') > -1) { - ext = filename.split('.').pop(); - } - // append extension if it doesn't exist - if (extension) { - if (ext !== extension) { - ext = extension; - filename = filename + '.' + ext; - } - } - return [filename, ext]; -} -p5.prototype._checkFileExtension = _checkFileExtension; - -/** - * Returns true if the browser is Safari, false if not. - * Safari makes trouble for downloading files. - * - * @return {Boolean} [description] - * @private - */ -p5.prototype._isSafari = function () { - var x = Object.prototype.toString.call(window.HTMLElement); - return x.indexOf('Constructor') > 0; -}; - -/** - * Helper function, a callback for download that deletes - * an invisible anchor element from the DOM once the file - * has been automatically downloaded. - * - * @private - */ -function destroyClickedElement(event) { - document.body.removeChild(event.target); -} - -module.exports = p5; - -},{"../core/core":48,"../core/error_helpers":51,"opentype.js":8,"reqwest":27}],71:[function(_dereq_,module,exports){ -/** - * @module IO - * @submodule Table - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - - -/** - * Table Options - * <p>Generic class for handling tabular data, typically from a - * CSV, TSV, or other sort of spreadsheet file.</p> - * <p>CSV files are - * <a href="http://en.wikipedia.org/wiki/Comma-separated_values"> - * comma separated values</a>, often with the data in quotes. TSV - * files use tabs as separators, and usually don't bother with the - * quotes.</p> - * <p>File names should end with .csv if they're comma separated.</p> - * <p>A rough "spec" for CSV can be found - * <a href="http://tools.ietf.org/html/rfc4180">here</a>.</p> - * <p>To load files, use the loadTable method.</p> - * <p>To save tables to your computer, use the save method - * or the saveTable method.</p> - * - * Possible options include: - * <ul> - * <li>csv - parse the table as comma-separated values - * <li>tsv - parse the table as tab-separated values - * <li>header - this table has a header (title) row - * </ul> - */ - -/** - * Table objects store data with multiple rows and columns, much - * like in a traditional spreadsheet. Tables can be generated from - * scratch, dynamically, or using data from an existing file. - * - * @class p5.Table - * @constructor - * @param {Array} [rows] An array of p5.TableRow objects - * @return {p5.Table} p5.Table generated - */ -p5.Table = function (rows) { - /** - * @property columns - * @type {Array} - */ - this.columns = []; - - /** - * @property rows - * @type {Array} - */ - this.rows = []; -}; - -/** - * Use addRow() to add a new row of data to a p5.Table object. By default, - * an empty row is created. Typically, you would store a reference to - * the new row in a TableRow object (see newRow in the example above), - * and then set individual values using set(). - * - * If a p5.TableRow object is included as a parameter, then that row is - * duplicated and added to the table. - * - * @method addRow - * @param {p5.TableRow} [row] row to be added to the table - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * //add a row - * var newRow = table.addRow(); - * newRow.setString("id", table.getRowCount() - 1); - * newRow.setString("species", "Canis Lupus"); - * newRow.setString("name", "Wolf"); - * - * //print the results - * for (var r = 0; r < table.getRowCount(); r++) - * for (var c = 0; c < table.getColumnCount(); c++) - * print(table.getString(r, c)); - * } - * </code> - * </div> - */ -p5.Table.prototype.addRow = function(row) { - // make sure it is a valid TableRow - var r = row || new p5.TableRow(); - - if (typeof(r.arr) === 'undefined' || typeof(r.obj) === 'undefined') { - //r = new p5.prototype.TableRow(r); - throw 'invalid TableRow: ' + r; - } - r.table = this; - this.rows.push(r); - return r; -}; - -/** - * Removes a row from the table object. - * - * @method removeRow - * @param {Number} id ID number of the row to remove - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * //remove the first row - * var r = table.removeRow(0); - * - * //print the results - * for (var r = 0; r < table.getRowCount(); r++) - * for (var c = 0; c < table.getColumnCount(); c++) - * print(table.getString(r, c)); - * } - * </code> - * </div> - */ -p5.Table.prototype.removeRow = function(id) { - this.rows[id].table = null; // remove reference to table - var chunk = this.rows.splice(id+1, this.rows.length); - this.rows.pop(); - this.rows = this.rows.concat(chunk); -}; - - -/** - * Returns a reference to the specified p5.TableRow. The reference - * can then be used to get and set values of the selected row. - * - * @method getRow - * @param {Number} rowID ID number of the row to get - * @return {TableRow} p5.TableRow object - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * var row = table.getRow(1); - * //print it column by column - * //note: a row is an object, not an array - * for (var c = 0; c < table.getColumnCount(); c++) - * print(row.getString(c)); - * } - * </code> - * </div> - */ -p5.Table.prototype.getRow = function(r) { - return this.rows[r]; -}; - -/** - * Gets all rows from the table. Returns an array of p5.TableRows. - * - * @method getRows - * @return {Array} Array of p5.TableRows - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * var rows = table.getRows(); - * - * //warning: rows is an array of objects - * for (var r = 0; r < rows.length; r++) - * rows[r].set("name", "Unicorn"); - * - * //print the results - * for (var r = 0; r < table.getRowCount(); r++) - * for (var c = 0; c < table.getColumnCount(); c++) - * print(table.getString(r, c)); - * } - * </code> - * </div> - */ -p5.Table.prototype.getRows = function() { - return this.rows; -}; - -/** - * Finds the first row in the Table that contains the value - * provided, and returns a reference to that row. Even if - * multiple rows are possible matches, only the first matching - * row is returned. The column to search may be specified by - * either its ID or title. - * - * @method findRow - * @param {String} value The value to match - * @param {Number|String} column ID number or title of the - * column to search - * @return {TableRow} - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * //find the animal named zebra - * var row = table.findRow("Zebra", "name"); - * //find the corresponding species - * print(row.getString("species")); - * } - * </code> - * </div> - */ -p5.Table.prototype.findRow = function(value, column) { - // try the Object - if (typeof(column) === 'string') { - for (var i = 0; i < this.rows.length; i++){ - if (this.rows[i].obj[column] === value) { - return this.rows[i]; - } - } - } - // try the Array - else { - for (var j = 0; j < this.rows.length; j++){ - if (this.rows[j].arr[column] === value) { - return this.rows[j]; - } - } - } - // otherwise... - return null; -}; - -/** - * Finds the rows in the Table that contain the value - * provided, and returns references to those rows. Returns an - * Array, so for must be used to iterate through all the rows, - * as shown in the example above. The column to search may be - * specified by either its ID or title. - * - * @method findRows - * @param {String} value The value to match - * @param {Number|String} column ID number or title of the - * column to search - * @return {Array} An Array of TableRow objects - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * //add another goat - * var newRow = table.addRow(); - * newRow.setString("id", table.getRowCount() - 1); - * newRow.setString("species", "Scape Goat"); - * newRow.setString("name", "Goat"); - * - * //find the rows containing animals named Goat - * var rows = table.findRows("Goat", "name"); - * print(rows.length + " Goats found"); - * } - * </code> - * </div> - */ -p5.Table.prototype.findRows = function(value, column) { - var ret = []; - if (typeof(column) === 'string') { - for (var i = 0; i < this.rows.length; i++){ - if (this.rows[i].obj[column] === value) { - ret.push( this.rows[i] ); - } - } - } - // try the Array - else { - for (var j = 0; j < this.rows.length; j++){ - if (this.rows[j].arr[column] === value) { - ret.push( this.rows[j] ); - } - } - } - return ret; -}; - -/** - * Finds the first row in the Table that matches the regular - * expression provided, and returns a reference to that row. - * Even if multiple rows are possible matches, only the first - * matching row is returned. The column to search may be - * specified by either its ID or title. - * - * @method matchRow - * @param {String} regexp The regular expression to match - * @param {String|Number} column The column ID (number) or - * title (string) - * @return {TableRow} TableRow object - */ -p5.Table.prototype.matchRow = function(regexp, column) { - if (typeof(column) === 'number') { - for (var j = 0; j < this.rows.length; j++) { - if ( this.rows[j].arr[column].match(regexp) ) { - return this.rows[j]; - } - } - } - - else { - for (var i = 0; i < this.rows.length; i++) { - if ( this.rows[i].obj[column].match(regexp) ) { - return this.rows[i]; - } - } - } - return null; -}; - -/** - * Finds the first row in the Table that matches the regular - * expression provided, and returns a reference to that row. - * Even if multiple rows are possible matches, only the first - * matching row is returned. The column to search may be specified - * by either its ID or title. - * - * @method matchRows - * @param {String} regexp The regular expression to match - * @param {String|Number} [column] The column ID (number) or - * title (string) - * @return {Array} An Array of TableRow objects - */ -p5.Table.prototype.matchRows = function(regexp, column) { - var ret = []; - if (typeof(column) === 'number') { - for (var j = 0; j < this.rows.length; j++) { - if ( this.rows[j].arr[column].match(regexp) ) { - ret.push( this.rows[j] ); - } - } - } - - else { - for (var i = 0; i < this.rows.length; i++) { - if ( this.rows[i].obj[column].match(regexp) ) { - ret.push( this.rows[i] ); - } - } - } - return ret; -}; - - -/** - * Retrieves all values in the specified column, and returns them - * as an array. The column may be specified by either its ID or title. - * - * @method getColumn - * @param {String|Number} column String or Number of the column to return - * @return {Array} Array of column values - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * //getColumn returns an array that can be printed directly - * print(table.getColumn("species")); - * //outputs ["Capra hircus", "Panthera pardus", "Equus zebra"] - * } - * </code> - * </div> - */ -p5.Table.prototype.getColumn = function(value) { - var ret = []; - if (typeof(value) === 'string'){ - for (var i = 0; i < this.rows.length; i++){ - ret.push (this.rows[i].obj[value]); - } - } else { - for (var j = 0; j < this.rows.length; j++){ - ret.push (this.rows[j].arr[value]); - } - } - return ret; -}; - -/** - * Removes all rows from a Table. While all rows are removed, - * columns and column titles are maintained. - * - * @method clearRows - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * table.clearRows(); - * print(table.getRowCount() + " total rows in table"); - * print(table.getColumnCount() + " total columns in table"); - * } - * </code> - * </div> - */ -p5.Table.prototype.clearRows = function() { - delete this.rows; - this.rows = []; -}; - -/** - * Use addColumn() to add a new column to a Table object. - * Typically, you will want to specify a title, so the column - * may be easily referenced later by name. (If no title is - * specified, the new column's title will be null.) - * - * @method addColumn - * @param {String} [title] title of the given column - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * table.addColumn("carnivore"); - * table.set(0, "carnivore", "no"); - * table.set(1, "carnivore", "yes"); - * table.set(2, "carnivore", "no"); - * - * //print the results - * for (var r = 0; r < table.getRowCount(); r++) - * for (var c = 0; c < table.getColumnCount(); c++) - * print(table.getString(r, c)); - * } - * </code> - * </div> - */ -p5.Table.prototype.addColumn = function(title) { - var t = title || null; - this.columns.push(t); -}; - -/** - * Returns the total number of columns in a Table. - * - * @return {Number} Number of columns in this table - */ -p5.Table.prototype.getColumnCount = function() { - return this.columns.length; -}; - -/** - * Returns the total number of rows in a Table. - * - * @method getRowCount - * @return {Number} Number of rows in this table - - */ -p5.Table.prototype.getRowCount = function() { - return this.rows.length; -}; - -/** - * <p>Removes any of the specified characters (or "tokens").</p> - * - * <p>If no column is specified, then the values in all columns and - * rows are processed. A specific column may be referenced by - * either its ID or title.</p> - * - * @method removeTokens - * @param {String} chars String listing characters to be removed - * @param {String|Number} [column] Column ID (number) - * or name (string) - */ -p5.Table.prototype.removeTokens = function(chars, column) { - var escape= function(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - }; - var charArray = []; - for (var i = 0; i < chars.length; i++) { - charArray.push( escape( chars.charAt(i) ) ); - } - var regex = new RegExp(charArray.join('|'), 'g'); - - if (typeof(column) === 'undefined'){ - for (var c = 0; c < this.columns.length; c++) { - for (var d = 0; d < this.rows.length; d++) { - var s = this.rows[d].arr[c]; - s = s.replace(regex, ''); - this.rows[d].arr[c] = s; - this.rows[d].obj[this.columns[c]] = s; - } - } - } - else if (typeof(column) === 'string'){ - for (var j = 0; j < this.rows.length; j++) { - var val = this.rows[j].obj[column]; - val = val.replace(regex, ''); - this.rows[j].obj[column] = val; - var pos = this.columns.indexOf(column); - this.rows[j].arr[pos] = val; - } - } - else { - for (var k = 0; k < this.rows.length; k++) { - var str = this.rows[k].arr[column]; - str = str.replace(regex, ''); - this.rows[k].arr[column] = str; - this.rows[k].obj[this.columns[column]] = str; - } - } -}; - -/** - * Trims leading and trailing whitespace, such as spaces and tabs, - * from String table values. If no column is specified, then the - * values in all columns and rows are trimmed. A specific column - * may be referenced by either its ID or title. - * - * @method trim - * @param {String|Number} column Column ID (number) - * or name (string) - */ -p5.Table.prototype.trim = function(column) { - var regex = new RegExp( (' '), 'g'); - - if (typeof(column) === 'undefined'){ - for (var c = 0; c < this.columns.length; c++) { - for (var d = 0; d < this.rows.length; d++) { - var s = this.rows[d].arr[c]; - s = s.replace(regex, ''); - this.rows[d].arr[c] = s; - this.rows[d].obj[this.columns[c]] = s; - } - } - } - else if (typeof(column) === 'string'){ - for (var j = 0; j < this.rows.length; j++) { - var val = this.rows[j].obj[column]; - val = val.replace(regex, ''); - this.rows[j].obj[column] = val; - var pos = this.columns.indexOf(column); - this.rows[j].arr[pos] = val; - } - } - else { - for (var k = 0; k < this.rows.length; k++) { - var str = this.rows[k].arr[column]; - str = str.replace(regex, ''); - this.rows[k].arr[column] = str; - this.rows[k].obj[this.columns[column]] = str; - } - } -}; - -/** - * Use removeColumn() to remove an existing column from a Table - * object. The column to be removed may be identified by either - * its title (a String) or its index value (an int). - * removeColumn(0) would remove the first column, removeColumn(1) - * would remove the second column, and so on. - * - * @method removeColumn - * @param {String|Number} column columnName (string) or ID (number) - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * table.removeColumn("id"); - * print(table.getColumnCount()); - * } - * </code> - * </div> - */ -p5.Table.prototype.removeColumn = function(c) { - var cString; - var cNumber; - if (typeof(c) === 'string') { - // find the position of c in the columns - cString = c; - cNumber = this.columns.indexOf(c); - console.log('string'); - } - else{ - cNumber = c; - cString = this.columns[c]; - } - - var chunk = this.columns.splice(cNumber+1, this.columns.length); - this.columns.pop(); - this.columns = this.columns.concat(chunk); - - for (var i = 0; i < this.rows.length; i++){ - var tempR = this.rows[i].arr; - var chip = tempR.splice(cNumber+1, tempR.length); - tempR.pop(); - this.rows[i].arr = tempR.concat(chip); - delete this.rows[i].obj[cString]; - } - -}; - - -/** - * Stores a value in the Table's specified row and column. - * The row is specified by its ID, while the column may be specified - * by either its ID or title. - * - * @method set - * @param {String|Number} column column ID (Number) - * or title (String) - * @param {String|Number} value value to assign - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * table.set(0, "species", "Canis Lupus"); - * table.set(0, "name", "Wolf"); - * - * //print the results - * for (var r = 0; r < table.getRowCount(); r++) - * for (var c = 0; c < table.getColumnCount(); c++) - * print(table.getString(r, c)); - * } - * </code> - * </div> - */ -p5.Table.prototype.set = function(row, column, value) { - this.rows[row].set(column, value); -}; - -/** - * Stores a Float value in the Table's specified row and column. - * The row is specified by its ID, while the column may be specified - * by either its ID or title. - * - * @method setNum - * @param {Number} row row ID - * @param {String|Number} column column ID (Number) - * or title (String) - * @param {Number} value value to assign - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * table.setNum(1, "id", 1); - * - * print(table.getColumn(0)); - * //["0", 1, "2"] - * } - * </code> - * </div> - */ -p5.Table.prototype.setNum = function(row, column, value){ - this.rows[row].setNum(column, value); -}; - - -/** - * Stores a String value in the Table's specified row and column. - * The row is specified by its ID, while the column may be specified - * by either its ID or title. - * - * @method setString - * @param {Number} row row ID - * @param {String|Number} column column ID (Number) - * or title (String) - * @param {String} value value to assign - */ -p5.Table.prototype.setString = function(row, column, value){ - this.rows[row].setString(column, value); -}; - -/** - * Retrieves a value from the Table's specified row and column. - * The row is specified by its ID, while the column may be specified by - * either its ID or title. - * - * @method get - * @param {Number} row row ID - * @param {String|Number} column columnName (string) or - * ID (number) - * @return {String|Number} - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * print(table.get(0, 1)); - * //Capra hircus - * print(table.get(0, "species")); - * //Capra hircus - * } - * </code> - * </div> - */ -p5.Table.prototype.get = function(row, column) { - return this.rows[row].get(column); -}; - -/** - * Retrieves a Float value from the Table's specified row and column. - * The row is specified by its ID, while the column may be specified by - * either its ID or title. - * - * @method getNum - * @param {Number} row row ID - * @param {String|Number} column columnName (string) or - * ID (number) - * @return {Number} - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * print(table.getNum(1, 0) + 100); - * //id 1 + 100 = 101 - * } - * </code> - * </div> - */ -p5.Table.prototype.getNum = function(row, column) { - return this.rows[row].getNum(column); -}; - -/** - * Retrieves a String value from the Table's specified row and column. - * The row is specified by its ID, while the column may be specified by - * either its ID or title. - * - * @method getString - * @param {Number} row row ID - * @param {String|Number} column columnName (string) or - * ID (number) - * @return {String} - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * var tableArray = table.getArray(); - * - * //output each row as array - * for (var i = 0; i < tableArray.length; i++) - * print(tableArray[i]); - * } - * </code> - * </div> - */ -p5.Table.prototype.getString = function(row, column) { - return this.rows[row].getString(column); -}; - -/** - * Retrieves all table data and returns as an object. If a column name is - * passed in, each row object will be stored with that attribute as its - * title. - * - * @method getObject - * @param {String} headerColumn Name of the column which should be used to - * title each row object (optional) - * @return {Object} - * - * @example - * <div class="norender"> - * <code> - * // Given the CSV file "mammals.csv" - * // in the project's "assets" folder: - * // - * // id,species,name - * // 0,Capra hircus,Goat - * // 1,Panthera pardus,Leopard - * // 2,Equus zebra,Zebra - * - * var table; - * - * function preload() { - * //my table is comma separated value "csv" - * //and has a header specifying the columns labels - * table = loadTable("assets/mammals.csv", "csv", "header"); - * } - * - * function setup() { - * var tableObject = table.getObject(); - * - * print(tableObject); - * //outputs an object - * } - * </code> - * </div> - - */ -p5.Table.prototype.getObject = function (headerColumn) { - var tableObject = {}; - var obj, cPos, index; - - for(var i = 0; i < this.rows.length; i++) { - obj = this.rows[i].obj; - - if (typeof(headerColumn) === 'string'){ - cPos = this.columns.indexOf(headerColumn); // index of columnID - if (cPos >= 0) { - index = obj[headerColumn]; - tableObject[index] = obj; - } else { - throw 'This table has no column named "' + headerColumn +'"'; - } - } else { - tableObject[i] = this.rows[i].obj; - } - } - return tableObject; -}; - -/** - * Retrieves all table data and returns it as a multidimensional array. - * - * @method getArray - * @return {Array} - */ -p5.Table.prototype.getArray = function () { - var tableArray = []; - for(var i = 0; i < this.rows.length; i++) { - tableArray.push(this.rows[i].arr); - } - return tableArray; -}; - -module.exports = p5.Table; - -},{"../core/core":48}],72:[function(_dereq_,module,exports){ -/** - * @module IO - * @submodule Table - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * A TableRow object represents a single row of data values, - * stored in columns, from a table. - * - * A Table Row contains both an ordered array, and an unordered - * JSON object. - * - * @class p5.TableRow - * @constructor - * @param {String} [str] optional: populate the row with a - * string of values, separated by the - * separator - * @param {String} [separator] comma separated values (csv) by default - */ -p5.TableRow = function (str, separator) { - var arr = []; - var obj = {}; - if (str){ - separator = separator || ','; - arr = str.split(separator); - } - for (var i = 0; i < arr.length; i++){ - var key = i; - var val = arr[i]; - obj[key] = val; - } - this.arr = arr; - this.obj = obj; - this.table = null; -}; - -/** - * Stores a value in the TableRow's specified column. - * The column may be specified by either its ID or title. - * - * @method set - * @param {String|Number} column Column ID (Number) - * or Title (String) - * @param {String|Number} value The value to be stored - */ -p5.TableRow.prototype.set = function(column, value) { - // if typeof column is string, use .obj - if (typeof(column) === 'string'){ - var cPos = this.table.columns.indexOf(column); // index of columnID - if (cPos >= 0) { - this.obj[column] = value; - this.arr[cPos] = value; - } - else { - throw 'This table has no column named "' + column +'"'; - } - } - - // if typeof column is number, use .arr - else { - if (column < this.table.columns.length) { - this.arr[column] = value; - var cTitle = this.table.columns[column]; - this.obj[cTitle] = value; - } - else { - throw 'Column #' + column + ' is out of the range of this table'; - } - } -}; - - -/** - * Stores a Float value in the TableRow's specified column. - * The column may be specified by either its ID or title. - * - * @method setNum - * @param {String|Number} column Column ID (Number) - * or Title (String) - * @param {Number} value The value to be stored - * as a Float - */ -p5.TableRow.prototype.setNum = function(column, value){ - var floatVal = parseFloat(value, 10); - this.set(column, floatVal); -}; - - -/** - * Stores a String value in the TableRow's specified column. - * The column may be specified by either its ID or title. - * - * @method setString - * @param {String|Number} column Column ID (Number) - * or Title (String) - * @param {String} value The value to be stored - * as a String - */ -p5.TableRow.prototype.setString = function(column, value){ - var stringVal = value.toString(); - this.set(column, stringVal); -}; - -/** - * Retrieves a value from the TableRow's specified column. - * The column may be specified by either its ID or title. - * - * @method get - * @param {String|Number} column columnName (string) or - * ID (number) - * @return {String|Number} - */ -p5.TableRow.prototype.get = function(column) { - if (typeof(column) === 'string'){ - return this.obj[column]; - } else { - return this.arr[column]; - } -}; - -/** - * Retrieves a Float value from the TableRow's specified - * column. The column may be specified by either its ID or - * title. - * - * @method getNum - * @param {String|Number} column columnName (string) or - * ID (number) - * @return {Number} Float Floating point number - */ -p5.TableRow.prototype.getNum = function(column) { - var ret; - if (typeof(column) === 'string'){ - ret = parseFloat(this.obj[column], 10); - } else { - ret = parseFloat(this.arr[column], 10); - } - - if (ret.toString() === 'NaN') { - throw 'Error: ' + this.obj[column]+ ' is NaN (Not a Number)'; - } - return ret; -}; - -/** - * Retrieves an String value from the TableRow's specified - * column. The column may be specified by either its ID or - * title. - * - * @method getString - * @param {String|Number} column columnName (string) or - * ID (number) - * @return {String} String - */ -p5.TableRow.prototype.getString = function(column) { - if (typeof(column) === 'string'){ - return this.obj[column].toString(); - } else { - return this.arr[column].toString(); - } -}; - -module.exports = p5.TableRow; - -},{"../core/core":48}],73:[function(_dereq_,module,exports){ -/** - * @module Math - * @submodule Calculation - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Calculates the absolute value (magnitude) of a number. Maps to Math.abs(). - * The absolute value of a number is always positive. - * - * @method abs - * @param {Number} n number to compute - * @return {Number} absolute value of given number - * @example - * <div class = "norender"><code> - * function setup() { - * var x = -3; - * var y = abs(x); - * - * print(x); // -3 - * print(y); // 3 - * } - * </code></div> - */ -p5.prototype.abs = Math.abs; - -/** - * Calculates the closest int value that is greater than or equal to the - * value of the parameter. Maps to Math.ceil(). For example, ceil(9.03) - * returns the value 10. - * - * @method ceil - * @param {Number} n number to round up - * @return {Number} rounded up number - * @example - * <div><code> - * function draw() { - * background(200); - * // map, mouseX between 0 and 5. - * var ax = map(mouseX, 0, 100, 0, 5); - * var ay = 66; - * - * //Get the ceiling of the mapped number. - * var bx = ceil(map(mouseX, 0, 100, 0,5)); - * var by = 33; - * - * // Multiply the mapped numbers by 20 to more easily - * // see the changes. - * stroke(0); - * fill(0); - * line(0, ay, ax * 20, ay); - * line(0, by, bx * 20, by); - * - * // Reformat the float returned by map and draw it. - * noStroke(); - * text(nfc(ax, 2,2), ax, ay - 5); - * text(nfc(bx,1,1), bx, by - 5); - * } - * </code></div> - */ -p5.prototype.ceil = Math.ceil; - -/** - * Constrains a value between a minimum and maximum value. - * - * @method constrain - * @param {Number} n number to constrain - * @param {Number} low minimum limit - * @param {Number} high maximum limit - * @return {Number} constrained number - * @example - * <div><code> - * function draw() { - * background(200); - * - * var leftWall = 25; - * var rightWall = 75; - * - * // xm is just the mouseX, while - * // xc is the mouseX, but constrained - * // between the leftWall and rightWall! - * var xm = mouseX; - * var xc = constrain(mouseX, leftWall, rightWall); - * - * // Draw the walls. - * stroke(150); - * line(leftWall, 0, leftWall, height); - * line(rightWall, 0, rightWall, height); - * - * // Draw xm and xc as circles. - * noStroke(); - * fill(150); - * ellipse(xm, 33, 9,9); // Not Constrained - * fill(0); - * ellipse(xc, 66, 9,9); // Constrained - * } - * </code></div> - */ -p5.prototype.constrain = function(n, low, high) { - return Math.max(Math.min(n, high), low); -}; - -/** - * Calculates the distance between two points. - * - * @method dist - * @param {Number} x1 x-coordinate of the first point - * @param {Number} y1 y-coordinate of the first point - * @param {Number} [z1] z-coordinate of the first point - * @param {Number} x2 x-coordinate of the second point - * @param {Number} y2 y-coordinate of the second point - * @param {Number} [z2] z-coordinate of the second point - * @return {Number} distance between the two points - * @example - * <div><code> - * // Move your mouse inside the canvas to see the - * // change in distance between two points! - * function draw() { - * background(200); - * fill(0); - * - * var x1 = 10; - * var y1 = 90; - * var x2 = mouseX; - * var y2 = mouseY; - * - * line(x1, y1, x2, y2); - * ellipse(x1, y1, 7, 7); - * ellipse(x2, y2, 7, 7); - * - * // d is the length of the line - * // the distance from point 1 to point 2. - * var d = int(dist(x1, y1, x2, y2)); - * - * // Let's write d along the line we are drawing! - * push(); - * translate( (x1+x2)/2, (y1+y2)/2 ); - * rotate( atan2(y2-y1,x2-x1) ); - * text(nfc(d,1,1), 0, -5); - * pop(); - * // Fancy! - * } - * </code></div> - */ -p5.prototype.dist = function(x1, y1, z1, x2, y2, z2) { - if (arguments.length === 4) { - // In the case of 2d: z1 means x2 and x2 means y2 - return Math.sqrt( (z1-x1)*(z1-x1) + (x2-y1)*(x2-y1) ); - } else if (arguments.length === 6) { - return Math.sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1) ); - } -}; - -/** - * Returns Euler's number e (2.71828...) raised to the power of the n - * parameter. Maps to Math.exp(). - * - * @method exp - * @param {Number} n exponent to raise - * @return {Number} e^n - * @example - * <div><code> - * function draw() { - * background(200); - * - * // Compute the exp() function with a value between 0 and 2 - * var xValue = map(mouseX, 0, width, 0, 2); - * var yValue = exp(xValue); - * - * var y = map(yValue, 0, 8, height, 0); - * - * var legend = "exp (" + nfc(xValue, 3) +")\n= " + nf(yValue, 1, 4); - * stroke(150); - * line(mouseX, y, mouseX, height); - * fill(0); - * text(legend, 5, 15); - * noStroke(); - * ellipse (mouseX,y, 7, 7); - * - * // Draw the exp(x) curve, - * // over the domain of x from 0 to 2 - * noFill(); - * stroke(0); - * beginShape(); - * for (var x = 0; x < width; x++) { - * xValue = map(x, 0, width, 0, 2); - * yValue = exp(xValue); - * y = map(yValue, 0, 8, height, 0); - * vertex(x, y); - * } - * - * endShape(); - * line(0, 0, 0, height); - * line(0, height-1, width, height-1); - * } - * </code></div> - */ -p5.prototype.exp = Math.exp; - -/** - * Calculates the closest int value that is less than or equal to the - * value of the parameter. Maps to Math.floor(). - * - * @method floor - * @param {Number} n number to round down - * @return {Number} rounded down number - * @example - * <div><code> - * function draw() { - * background(200); - * //map, mouseX between 0 and 5. - * var ax = map(mouseX, 0, 100, 0, 5); - * var ay = 66; - * - * //Get the floor of the mapped number. - * var bx = floor(map(mouseX, 0, 100, 0,5)); - * var by = 33; - * - * // Multiply the mapped numbers by 20 to more easily - * // see the changes. - * stroke(0); - * fill(0); - * line(0, ay, ax * 20, ay); - * line(0, by, bx * 20, by); - * - * // Reformat the float returned by map and draw it. - * noStroke(); - * text(nfc(ax, 2,2), ax, ay - 5); - * text(nfc(bx,1,1), bx, by - 5); - * } - * </code></div> - */ -p5.prototype.floor = Math.floor; - -/** - * Calculates a number between two numbers at a specific increment. The amt - * parameter is the amount to interpolate between the two values where 0.0 - * equal to the first point, 0.1 is very near the first point, 0.5 is - * half-way in between, etc. The lerp function is convenient for creating - * motion along a straight path and for drawing dotted lines. - * - * @method lerp - * @param {Number} start first value - * @param {Number} stop second value - * @param {Number} amt number between 0.0 and 1.0 - * @return {Number} lerped value - * @example - * <div><code> - * function setup() { - * background(200); - * var a = 20; - * var b = 80; - * var c = lerp(a,b, .2); - * var d = lerp(a,b, .5); - * var e = lerp(a,b, .8); - * - * var y = 50 - * - * strokeWeight(5); - * stroke(0); // Draw the original points in black - * point(a, y); - * point(b, y); - * - * stroke(100); // Draw the lerp points in gray - * point(c, y); - * point(d, y); - * point(e, y); - * } - * </code></div> - */ -p5.prototype.lerp = function(start, stop, amt) { - return amt*(stop-start)+start; -}; - -/** - * Calculates the natural logarithm (the base-e logarithm) of a number. This - * function expects the n parameter to be a value greater than 0.0. Maps to - * Math.log(). - * - * @method log - * @param {Number} n number greater than 0 - * @return {Number} natural logarithm of n - * @example - * <div><code> - * function draw() { - * background(200); - * var maxX = 2.8; - * var maxY = 1.5; - * - * // Compute the natural log of a value between 0 and maxX - * var xValue = map(mouseX, 0, width, 0, maxX); - * if (xValue > 0) { // Cannot take the log of a negative number. - * var yValue = log(xValue); - * var y = map(yValue, -maxY, maxY, height, 0); - * - * // Display the calculation occurring. - * var legend = "log(" + nf(xValue, 1, 2) + ")\n= " + nf(yValue, 1, 3); - * stroke(150); - * line(mouseX, y, mouseX, height); - * fill(0); - * text (legend, 5, 15); - * noStroke(); - * ellipse (mouseX, y, 7, 7); - * } - * - * // Draw the log(x) curve, - * // over the domain of x from 0 to maxX - * noFill(); - * stroke(0); - * beginShape(); - * for(var x=0; x < width; x++) { - * xValue = map(x, 0, width, 0, maxX); - * yValue = log(xValue); - * y = map(yValue, -maxY, maxY, height, 0); - * vertex(x, y); - * } - * endShape(); - * line(0,0,0,height); - * line(0,height/2,width, height/2); - * } - * </code></div> - */ -p5.prototype.log = Math.log; - -/** - * Calculates the magnitude (or length) of a vector. A vector is a direction - * in space commonly used in computer graphics and linear algebra. Because it - * has no "start" position, the magnitude of a vector can be thought of as - * the distance from the coordinate 0,0 to its x,y value. Therefore, mag() is - * a shortcut for writing dist(0, 0, x, y). - * - * @method mag - * @param {Number} a first value - * @param {Number} b second value - * @return {Number} magnitude of vector from (0,0) to (a,b) - * @example - * <div><code> - * function setup() { - * var x1 = 20; - * var x2 = 80; - * var y1 = 30; - * var y2 = 70; - * - * line(0, 0, x1, y1); - * print(mag(x1, y1)); // Prints "36.05551" - * line(0, 0, x2, y1); - * print(mag(x2, y1)); // Prints "85.44004" - * line(0, 0, x1, y2); - * print(mag(x1, y2)); // Prints "72.8011" - * line(0, 0, x2, y2); - * print(mag(x2, y2)); // Prints "106.30146" - * } - * </code></div> - */ -p5.prototype.mag = function(x, y) { - return Math.sqrt(x*x+y*y); -}; - -/** - * Re-maps a number from one range to another. - * <br><br> - * In the first example above, the number 25 is converted from a value in the - * range of 0 to 100 into a value that ranges from the left edge of the - * window (0) to the right edge (width). - * - * @method map - * @param {Number} value the incoming value to be converted - * @param {Number} start1 lower bound of the value's current range - * @param {Number} stop1 upper bound of the value's current range - * @param {Number} start2 lower bound of the value's target range - * @param {Number} stop upper bound of the value's target range - * @return {Number} remapped number - * @example - * <div><code> - * var value = 25; - * var m = map(value, 0, 100, 0, width); - * ellipse(m, 50, 10, 10); - * </code></div> - * - * <div><code> - * function setup() { - * noStroke(); - * } - * - * function draw() { - * background(204); - * var x1 = map(mouseX, 0, width, 25, 75); - * ellipse(x1, 25, 25, 25); - * var x2 = map(mouseX, 0, width, 0, 100); - * ellipse(x2, 75, 25, 25); - * } - * </code></div> - */ -p5.prototype.map = function(n, start1, stop1, start2, stop2) { - return ((n-start1)/(stop1-start1))*(stop2-start2)+start2; -}; - -/** - * Determines the largest value in a sequence of numbers, and then returns - * that value. max() accepts any number of Number parameters, or an Array - * of any length. - * - * @method max - * @param {Number|Array} n0 Numbers to compare - * @return {Number} maximum Number - * @example - * <div><code> - * function setup() { - * // Change the elements in the array and run the sketch - * // to show how max() works! - * numArray = new Array(2,1,5,4,8,9); - * fill(0); - * noStroke(); - * text("Array Elements", 0, 10); - * // Draw all numbers in the array - * var spacing = 15; - * var elemsY = 25; - * for(var i = 0; i < numArray.length; i++) { - * text(numArray[i], i * spacing, elemsY); - * } - * maxX = 33; - * maxY = 80; - * // Draw the Maximum value in the array. - * textSize(32); - * text(max(numArray), maxX, maxY); - * } - * </code></div> - */ -p5.prototype.max = function() { - if (arguments[0] instanceof Array) { - return Math.max.apply(null,arguments[0]); - } else { - return Math.max.apply(null,arguments); - } -}; - -/** - * Determines the smallest value in a sequence of numbers, and then returns - * that value. min() accepts any number of Number parameters, or an Array - * of any length. - * - * @method min - * @param {Number|Array} n0 Numbers to compare - * @return {Number} minimum Number - * @example - * <div><code> - * function setup() { - * // Change the elements in the array and run the sketch - * // to show how min() works! - * numArray = new Array(2,1,5,4,8,9); - * fill(0); - * noStroke(); - * text("Array Elements", 0, 10); - * // Draw all numbers in the array - * var spacing = 15; - * var elemsY = 25; - * for(var i = 0; i < numArray.length; i++) { - * text(numArray[i], i * spacing, elemsY); - * } - * maxX = 33; - * maxY = 80; - * // Draw the Minimum value in the array. - * textSize(32); - * text(min(numArray), maxX, maxY); - * } - * </code></div> - */ -p5.prototype.min = function() { - if (arguments[0] instanceof Array) { - return Math.min.apply(null,arguments[0]); - } else { - return Math.min.apply(null,arguments); - } -}; - -/** - * Normalizes a number from another range into a value between 0 and 1. - * Identical to map(value, low, high, 0, 1). - * Numbers outside of the range are not clamped to 0 and 1, because - * out-of-range values are often intentional and useful. (See the second - * example above.) - * - * @method norm - * @param {Number} value incoming value to be normalized - * @param {Number} start lower bound of the value's current range - * @param {Number} stop upper bound of the value's current range - * @return {Number} normalized number - * @example - * <div><code> - * function draw() { - * background(200); - * currentNum = mouseX; - * lowerBound = 0; - * upperBound = width; //100; - * normalized = norm(currentNum, lowerBound, upperBound); - * lineY = 70 - * line(0, lineY, width, lineY); - * //Draw an ellipse mapped to the non-normalized value. - * noStroke(); - * fill(50) - * var s = 7; // ellipse size - * ellipse(currentNum, lineY, s, s); - * - * // Draw the guide - * guideY = lineY + 15; - * text("0", 0, guideY); - * textAlign(RIGHT); - * text("100", width, guideY); - * - * // Draw the normalized value - * textAlign(LEFT); - * fill(0); - * textSize(32); - * normalY = 40; - * normalX = 20; - * text(normalized, normalX, normalY); - * } - * </code></div> - */ -p5.prototype.norm = function(n, start, stop) { - return this.map(n, start, stop, 0, 1); -}; - -/** - * Facilitates exponential expressions. The pow() function is an efficient - * way of multiplying numbers by themselves (or their reciprocals) in large - * quantities. For example, pow(3, 5) is equivalent to the expression - * 3*3*3*3*3 and pow(3, -5) is equivalent to 1 / 3*3*3*3*3. Maps to - * Math.pow(). - * - * @method pow - * @param {Number} n base of the exponential expression - * @param {Number} e power by which to raise the base - * @return {Number} n^e - * @example - * <div><code> - * function setup() { - * //Exponentially increase the size of an ellipse. - * eSize = 3; // Original Size - * eLoc = 10; // Original Location - * - * ellipse(eLoc, eLoc, eSize, eSize); - * - * ellipse(eLoc*2, eLoc*2, pow(eSize, 2), pow(eSize, 2)); - * - * ellipse(eLoc*4, eLoc*4, pow(eSize, 3), pow(eSize, 3)); - * - * ellipse(eLoc*8, eLoc*8, pow(eSize, 4), pow(eSize, 4)); - * } - * </code></div> - */ -p5.prototype.pow = Math.pow; - -/** - * Calculates the integer closest to the n parameter. For example, - * round(133.8) returns the value 134. Maps to Math.round(). - * - * @method round - * @param {Number} n number to round - * @return {Number} rounded number - * @example - * <div><code> - * function draw() { - * background(200); - * //map, mouseX between 0 and 5. - * var ax = map(mouseX, 0, 100, 0, 5); - * var ay = 66; - * - * // Round the mapped number. - * var bx = round(map(mouseX, 0, 100, 0,5)); - * var by = 33; - * - * // Multiply the mapped numbers by 20 to more easily - * // see the changes. - * stroke(0); - * fill(0); - * line(0, ay, ax * 20, ay); - * line(0, by, bx * 20, by); - * - * // Reformat the float returned by map and draw it. - * noStroke(); - * text(nfc(ax, 2,2), ax, ay - 5); - * text(nfc(bx,1,1), bx, by - 5); - * } - * </code></div> - */ -p5.prototype.round = Math.round; - -/** - * Squares a number (multiplies a number by itself). The result is always a - * positive number, as multiplying two negative numbers always yields a - * positive result. For example, -1 * -1 = 1. - * - * @method sq - * @param {Number} n number to square - * @return {Number} squared number - * @example - * <div><code> - * function draw() { - * background(200); - * eSize = 7; - * x1 = map(mouseX, 0, width, 0, 10); - * y1 = 80; - * x2 = sq(x1); - * y2 = 20; - * - * // Draw the non-squared. - * line(0, y1, width, y1); - * ellipse(x1, y1, eSize, eSize); - * - * // Draw the squared. - * line(0, y2, width, y2); - * ellipse(x2, y2, eSize, eSize); - * - * // Draw dividing line. - * stroke(100) - * line(0, height/2, width, height/2); - * - * // Draw text. - * var spacing = 15; - * noStroke(); - * fill(0); - * text("x = " + x1, 0, y1 + spacing); - * text("sq(x) = " + x2, 0, y2 + spacing); - * } - * </code></div> - */ -p5.prototype.sq = function(n) { return n*n; }; - -/** - * Calculates the square root of a number. The square root of a number is - * always positive, even though there may be a valid negative root. The - * square root s of number a is such that s*s = a. It is the opposite of - * squaring. Maps to Math.sqrt(). - * - * @method sqrt - * @param {Number} n non-negative number to square root - * @return {Number} square root of number - * @example - * <div><code> - * function draw() { - * background(200); - * eSize = 7; - * x1 = mouseX; - * y1 = 80; - * x2 = sqrt(x1); - * y2 = 20; - * - * // Draw the non-squared. - * line(0, y1, width, y1); - * ellipse(x1, y1, eSize, eSize); - * - * // Draw the squared. - * line(0, y2, width, y2); - * ellipse(x2, y2, eSize, eSize); - * - * // Draw dividing line. - * stroke(100) - * line(0, height/2, width, height/2); - * - * // Draw text. - * noStroke(); - * fill(0); - * var spacing = 15; - * text("x = " + x1, 0, y1 + spacing); - * text("sqrt(x) = " + x2, 0, y2 + spacing); - * } - * </code></div> - */ -p5.prototype.sqrt = Math.sqrt; - -module.exports = p5; - -},{"../core/core":48}],74:[function(_dereq_,module,exports){ -/** - * @module Math - * @submodule Math - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - - -/** - * Creates a new p5.Vector (the datatype for storing vectors). This provides a - * two or three dimensional vector, specifically a Euclidean (also known as - * geometric) vector. A vector is an entity that has both magnitude and - * direction. - * - * @method createVector - * @param {Number} [x] x component of the vector - * @param {Number} [y] y component of the vector - * @param {Number} [z] z component of the vector - */ -p5.prototype.createVector = function (x, y, z) { - if (this instanceof p5) { - return new p5.Vector(this, arguments); - } else { - return new p5.Vector(x, y, z); - } -}; - -module.exports = p5; - -},{"../core/core":48}],75:[function(_dereq_,module,exports){ -////////////////////////////////////////////////////////////// - -// http://mrl.nyu.edu/~perlin/noise/ -// Adapting from PApplet.java -// which was adapted from toxi -// which was adapted from the german demo group farbrausch -// as used in their demo "art": http://www.farb-rausch.de/fr010src.zip - -// someday we might consider using "improved noise" -// http://mrl.nyu.edu/~perlin/paper445.pdf -// See: https://github.com/shiffman/The-Nature-of-Code-Examples-p5.js/ -// blob/master/introduction/Noise1D/noise.js - -/** - * @module Math - * @submodule Noise - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -var PERLIN_YWRAPB = 4; -var PERLIN_YWRAP = 1<<PERLIN_YWRAPB; -var PERLIN_ZWRAPB = 8; -var PERLIN_ZWRAP = 1<<PERLIN_ZWRAPB; -var PERLIN_SIZE = 4095; - -var perlin_octaves = 4; // default to medium smooth -var perlin_amp_falloff = 0.5; // 50% reduction/octave - -var scaled_cosine = function(i) { - return 0.5*(1.0-Math.cos(i*Math.PI)); -}; - -var perlin; // will be initialized lazily by noise() or noiseSeed() - - -/** - * Returns the Perlin noise value at specified coordinates. Perlin noise is - * a random sequence generator producing a more natural ordered, harmonic - * succession of numbers compared to the standard <b>random()</b> function. - * It was invented by Ken Perlin in the 1980s and been used since in - * graphical applications to produce procedural textures, natural motion, - * shapes, terrains etc.<br /><br /> The main difference to the - * <b>random()</b> function is that Perlin noise is defined in an infinite - * n-dimensional space where each pair of coordinates corresponds to a - * fixed semi-random value (fixed only for the lifespan of the program; see - * the noiseSeed() function). p5.js can compute 1D, 2D and 3D noise, - * depending on the number of coordinates given. The resulting value will - * always be between 0.0 and 1.0. The noise value can be animated by moving - * through the noise space as demonstrated in the example above. The 2nd - * and 3rd dimension can also be interpreted as time.<br /><br />The actual - * noise is structured similar to an audio signal, in respect to the - * function's use of frequencies. Similar to the concept of harmonics in - * physics, perlin noise is computed over several octaves which are added - * together for the final result. <br /><br />Another way to adjust the - * character of the resulting sequence is the scale of the input - * coordinates. As the function works within an infinite space the value of - * the coordinates doesn't matter as such, only the distance between - * successive coordinates does (eg. when using <b>noise()</b> within a - * loop). As a general rule the smaller the difference between coordinates, - * the smoother the resulting noise sequence will be. Steps of 0.005-0.03 - * work best for most applications, but this will differ depending on use. - * - * - * @method noise - * @param {Number} x x-coordinate in noise space - * @param {Number} y y-coordinate in noise space - * @param {Number} z z-coordinate in noise space - * @return {Number} Perlin noise value (between 0 and 1) at specified - * coordinates - * @example - * <div> - * <code>var xoff = 0.0; - * - * function draw() { - * background(204); - * xoff = xoff + .01; - * var n = noise(xoff) * width; - * line(n, 0, n, height); - * } - * </code> - * </div> - * <div> - * <code>var noiseScale=0.02; - * - * function draw() { - * background(0); - * for (var x=0; x < width; x++) { - * var noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale); - * stroke(noiseVal*255); - * line(x, mouseY+noiseVal*80, x, height); - * } - * } - * </code> - * </div> - */ -p5.prototype.noise = function(x,y,z) { - y = y || 0; - z = z || 0; - - if (perlin == null) { - perlin = new Array(PERLIN_SIZE + 1); - for (var i = 0; i < PERLIN_SIZE + 1; i++) { - perlin[i] = Math.random(); - } - } - - if (x<0) { x=-x; } - if (y<0) { y=-y; } - if (z<0) { z=-z; } - - var xi=Math.floor(x), yi=Math.floor(y), zi=Math.floor(z); - var xf = x - xi; - var yf = y - yi; - var zf = z - zi; - var rxf, ryf; - - var r=0; - var ampl=0.5; - - var n1,n2,n3; - - for (var o=0; o<perlin_octaves; o++) { - var of=xi+(yi<<PERLIN_YWRAPB)+(zi<<PERLIN_ZWRAPB); - - rxf = scaled_cosine(xf); - ryf = scaled_cosine(yf); - - n1 = perlin[of&PERLIN_SIZE]; - n1 += rxf*(perlin[(of+1)&PERLIN_SIZE]-n1); - n2 = perlin[(of+PERLIN_YWRAP)&PERLIN_SIZE]; - n2 += rxf*(perlin[(of+PERLIN_YWRAP+1)&PERLIN_SIZE]-n2); - n1 += ryf*(n2-n1); - - of += PERLIN_ZWRAP; - n2 = perlin[of&PERLIN_SIZE]; - n2 += rxf*(perlin[(of+1)&PERLIN_SIZE]-n2); - n3 = perlin[(of+PERLIN_YWRAP)&PERLIN_SIZE]; - n3 += rxf*(perlin[(of+PERLIN_YWRAP+1)&PERLIN_SIZE]-n3); - n2 += ryf*(n3-n2); - - n1 += scaled_cosine(zf)*(n2-n1); - - r += n1*ampl; - ampl *= perlin_amp_falloff; - xi<<=1; - xf*=2; - yi<<=1; - yf*=2; - zi<<=1; - zf*=2; - - if (xf>=1.0) { xi++; xf--; } - if (yf>=1.0) { yi++; yf--; } - if (zf>=1.0) { zi++; zf--; } - } - return r; -}; - - -/** - * - * Adjusts the character and level of detail produced by the Perlin noise - * function. Similar to harmonics in physics, noise is computed over - * several octaves. Lower octaves contribute more to the output signal and - * as such define the overall intensity of the noise, whereas higher octaves - * create finer grained details in the noise sequence. - * <br><br> - * By default, noise is computed over 4 octaves with each octave contributing - * exactly half than its predecessor, starting at 50% strength for the 1st - * octave. This falloff amount can be changed by adding an additional function - * parameter. Eg. a falloff factor of 0.75 means each octave will now have - * 75% impact (25% less) of the previous lower octave. Any value between - * 0.0 and 1.0 is valid, however note that values greater than 0.5 might - * result in greater than 1.0 values returned by <b>noise()</b>. - * <br><br> - * By changing these parameters, the signal created by the <b>noise()</b> - * function can be adapted to fit very specific needs and characteristics. - * - * @method noiseDetail - * @param {Number} lod number of octaves to be used by the noise - * @param {Number} falloff falloff factor for each octave - * @example - * <div> - * <code> - * - * var noiseVal; - * var noiseScale=0.02; - * - * function setup() { - * createCanvas(100,100); - * } - * - * function draw() { - * background(0); - * for (var y = 0; y < height; y++) { - * for (var x = 0; x < width/2; x++) { - * noiseDetail(2,0.2); - * noiseVal = noise((mouseX+x) * noiseScale, - * (mouseY+y) * noiseScale); - * stroke(noiseVal*255); - * point(x,y); - * noiseDetail(8,0.65); - * noiseVal = noise((mouseX + x + width/2) * noiseScale, - * (mouseY + y) * noiseScale); - * stroke(noiseVal*255); - * point(x + width/2, y); - * } - * } - * } - * </code> - * </div> - */ -p5.prototype.noiseDetail = function(lod, falloff) { - if (lod>0) { perlin_octaves=lod; } - if (falloff>0) { perlin_amp_falloff=falloff; } -}; - -/** - * Sets the seed value for <b>noise()</b>. By default, <b>noise()</b> - * produces different results each time the program is run. Set the - * <b>value</b> parameter to a constant to return the same pseudo-random - * numbers each time the software is run. - * - * @method noiseSeed - * @param {Number} seed the seed value - * @example - * <div> - * <code>var xoff = 0.0; - * - * function setup() { - * noiseSeed(99); - * stroke(0, 10); - * } - * - * function draw() { - * xoff = xoff + .01; - * var n = noise(xoff) * width; - * line(n, 0, n, height); - * } - * </code> - * </div> - */ -p5.prototype.noiseSeed = function(seed) { - // Linear Congruential Generator - // Variant of a Lehman Generator - var lcg = (function() { - // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes - // m is basically chosen to be large (as it is the max period) - // and for its relationships to a and c - var m = 4294967296, - // a - 1 should be divisible by m's prime factors - a = 1664525, - // c and m should be co-prime - c = 1013904223, - seed, z; - return { - setSeed : function(val) { - // pick a random seed if val is undefined or null - // the >>> 0 casts the seed to an unsigned 32-bit integer - z = seed = (val == null ? Math.random() * m : val) >>> 0; - }, - getSeed : function() { - return seed; - }, - rand : function() { - // define the recurrence relationship - z = (a * z + c) % m; - // return a float in [0, 1) - // if z = m then z / m = 0 therefore (z % m) / m < 1 always - return z / m; - } - }; - }()); - - lcg.setSeed(seed); - perlin = new Array(PERLIN_SIZE + 1); - for (var i = 0; i < PERLIN_SIZE + 1; i++) { - perlin[i] = lcg.rand(); - } -}; - -module.exports = p5; - -},{"../core/core":48}],76:[function(_dereq_,module,exports){ -/** - * @module Math - * @submodule Math - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var polarGeometry = _dereq_('./polargeometry'); -var constants = _dereq_('../core/constants'); - -/** - * A class to describe a two or three dimensional vector, specifically - * a Euclidean (also known as geometric) vector. A vector is an entity - * that has both magnitude and direction. The datatype, however, stores - * the components of the vector (x, y for 2D, and x, y, z for 3D). The magnitude - * and direction can be accessed via the methods mag() and heading(). - * <br><br> - * In many of the p5.js examples, you will see p5.Vector used to describe a - * position, velocity, or acceleration. For example, if you consider a rectangle - * moving across the screen, at any given instant it has a position (a vector - * that points from the origin to its location), a velocity (the rate at which - * the object's position changes per time unit, expressed as a vector), and - * acceleration (the rate at which the object's velocity changes per time - * unit, expressed as a vector). - * <br><br> - * Since vectors represent groupings of values, we cannot simply use - * traditional addition/multiplication/etc. Instead, we'll need to do some - * "vector" math, which is made easy by the methods inside the p5.Vector class. - * - * @class p5.Vector - * @constructor - * @param {Number} [x] x component of the vector - * @param {Number} [y] y component of the vector - * @param {Number} [z] z component of the vector - * @example - * <div> - * <code> - * var v1 = createVector(40, 50); - * var v2 = createVector(40, 50); - * - * ellipse(v1.x, v1.y, 50, 50); - * ellipse(v2.x, v2.y, 50, 50); - * v1.add(v2); - * ellipse(v1.x, v1.y, 50, 50); - * </code> - * </div> - */ -p5.Vector = function() { - var x,y,z; - // This is how it comes in with createVector() - if(arguments[0] instanceof p5) { - // save reference to p5 if passed in - this.p5 = arguments[0]; - x = arguments[1][0] || 0; - y = arguments[1][1] || 0; - z = arguments[1][2] || 0; - // This is what we'll get with new p5.Vector() - } else { - x = arguments[0] || 0; - y = arguments[1] || 0; - z = arguments[2] || 0; - } - /** - * The x component of the vector - * @property x - * @type {Number} - */ - this.x = x; - /** - * The y component of the vector - * @property y - * @type {Number} - */ - this.y = y; - /** - * The z component of the vector - * @property z - * @type {Number} - */ - this.z = z; -}; - -/** - * Returns a string representation of a vector v by calling String(v) - * or v.toString(). This method is useful for logging vectors in the - * console. - * @method toString - * @example - * <div class = "norender"><code> - * function setup() { - * var v = createVector(20,30); - * print(String(v)); // prints "p5.Vector Object : [20, 30, 0]" - * } - * </div></code> - * - */ -p5.Vector.prototype.toString = function p5VectorToString() { - return 'p5.Vector Object : ['+ this.x +', '+ this.y +', '+ this.z + ']'; -}; - -/** - * Sets the x, y, and z component of the vector using two or three separate - * variables, the data from a p5.Vector, or the values from a float array. - * @method set - * - * @param {Number|p5.Vector|Array} [x] the x component of the vector or a - * p5.Vector or an Array - * @param {Number} [y] the y component of the vector - * @param {Number} [z] the z component of the vector - * @example - * <div class="norender"> - * <code> - * function setup() { - * var v = createVector(1, 2, 3); - * v.set(4,5,6); // Sets vector to [4, 5, 6] - * - * var v1 = createVector(0, 0, 0); - * var arr = [1, 2, 3]; - * v1.set(arr); // Sets vector to [1, 2, 3] - * } - * </code> - * </div> - */ -p5.Vector.prototype.set = function (x, y, z) { - if (x instanceof p5.Vector) { - this.x = x.x || 0; - this.y = x.y || 0; - this.z = x.z || 0; - return this; - } - if (x instanceof Array) { - this.x = x[0] || 0; - this.y = x[1] || 0; - this.z = x[2] || 0; - return this; - } - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - return this; -}; - -/** - * Gets a copy of the vector, returns a p5.Vector object. - * - * @method copy - * @return {p5.Vector} the copy of the p5.Vector object - * @example - * <div class="norender"> - * <code> - * var v1 = createVector(1, 2, 3); - * var v2 = v.copy(); - * print(v1.x == v2.x && v1.y == v2.y && v1.z == v2.z); - * // Prints "true" - * </code> - * </div> - */ -p5.Vector.prototype.copy = function () { - if (this.p5) { - return new p5.Vector(this.p5,[this.x, this.y, this.z]); - } else { - return new p5.Vector(this.x,this.y,this.z); - } -}; - -/** - * Adds x, y, and z components to a vector, adds one vector to another, or - * adds two independent vectors together. The version of the method that adds - * two vectors together is a static method and returns a p5.Vector, the others - * acts directly on the vector. See the examples for more context. - * - * @method add - * @chainable - * @param {Number|p5.Vector|Array} x the x component of the vector to be - * added or a p5.Vector or an Array - * @param {Number} [y] the y component of the vector to be - * added - * @param {Number} [z] the z component of the vector to be - * added - * @return {p5.Vector} the p5.Vector object. - * @example - * <div class="norender"> - * <code> - * var v = createVector(1, 2, 3); - * v.add(4,5,6); - * // v's compnents are set to [5, 7, 9] - * </code> - * </div> - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(1, 2, 3); - * var v2 = createVector(2, 3, 4); - * - * var v3 = p5.Vector.add(v1, v2); - * // v3 has components [3, 5, 7] - * </code> - * </div> - */ -p5.Vector.prototype.add = function (x, y, z) { - if (x instanceof p5.Vector) { - this.x += x.x || 0; - this.y += x.y || 0; - this.z += x.z || 0; - return this; - } - if (x instanceof Array) { - this.x += x[0] || 0; - this.y += x[1] || 0; - this.z += x[2] || 0; - return this; - } - this.x += x || 0; - this.y += y || 0; - this.z += z || 0; - return this; -}; - -/** - * Subtracts x, y, and z components from a vector, subtracts one vector from - * another, or subtracts two independent vectors. The version of the method - * that subtracts two vectors is a static method and returns a p5.Vector, the - * other acts directly on the vector. See the examples for more context. - * - * @method sub - * @chainable - * @param {Number|p5.Vector|Array} x the x component of the vector or a - * p5.Vector or an Array - * @param {Number} [y] the y component of the vector - * @param {Number} [z] the z component of the vector - * @return {p5.Vector} p5.Vector object. - * @example - * <div class="norender"> - * <code> - * var v = createVector(4, 5, 6); - * v.sub(1, 1, 1); - * // v's compnents are set to [3, 4, 5] - * </code> - * </div> - * - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(2, 3, 4); - * var v2 = createVector(1, 2, 3); - * - * var v3 = p5.Vector.sub(v1, v2); - * // v3 has compnents [1, 1, 1] - * </code> - * </div> - */ -p5.Vector.prototype.sub = function (x, y, z) { - if (x instanceof p5.Vector) { - this.x -= x.x || 0; - this.y -= x.y || 0; - this.z -= x.z || 0; - return this; - } - if (x instanceof Array) { - this.x -= x[0] || 0; - this.y -= x[1] || 0; - this.z -= x[2] || 0; - return this; - } - this.x -= x || 0; - this.y -= y || 0; - this.z -= z || 0; - return this; -}; - -/** - * Multiply the vector by a scalar. The static version of this method - * creates a new p5.Vector while the non static version acts on the vector - * directly. See the examples for more context. - * - * @method mult - * @chainable - * @param {Number} n the number to multiply with the vector - * @return {p5.Vector} a reference to the p5.Vector object (allow chaining) - * @example - * <div class="norender"> - * <code> - * var v = createVector(1, 2, 3); - * v.mult(2); - * // v's compnents are set to [2, 4, 6] - * </code> - * </div> - * - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(1, 2, 3); - * var v2 = p5.Vector.mult(v1, 2); - * // v2 has compnents [2, 4, 6] - * </code> - * </div> - */ -p5.Vector.prototype.mult = function (n) { - this.x *= n || 0; - this.y *= n || 0; - this.z *= n || 0; - return this; -}; - -/** - * Divide the vector by a scalar. The static version of this method creates a - * new p5.Vector while the non static version acts on the vector directly. - * See the examples for more context. - * - * @method div - * @chainable - * @param {number} n the number to divide the vector by - * @return {p5.Vector} a reference to the p5.Vector object (allow chaining) - * @example - * <div class="norender"> - * <code> - * var v = createVector(6, 4, 2); - * v.div(2); //v's compnents are set to [3, 2, 1] - * </code> - * </div> - * - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(6, 4, 2); - * var v2 = p5.Vector.div(v, 2); - * // v2 has compnents [3, 2, 1] - * </code> - * </div> - */ -p5.Vector.prototype.div = function (n) { - this.x /= n; - this.y /= n; - this.z /= n; - return this; -}; - -/** - * Calculates the magnitude (length) of the vector and returns the result as - * a float (this is simply the equation sqrt(x*x + y*y + z*z).) - * - * @method mag - * @return {Number} magnitude of the vector - * @example - * <div class="norender"> - * <code> - * var v = createVector(20.0, 30.0, 40.0); - * var m = v.mag(10); - * print(m); // Prints "53.85164807134504" - * </code> - * </div> - */ -p5.Vector.prototype.mag = function () { - return Math.sqrt(this.magSq()); -}; - -/** - * Calculates the squared magnitude of the vector and returns the result - * as a float (this is simply the equation <em>(x*x + y*y + z*z)</em>.) - * Faster if the real length is not required in the - * case of comparing vectors, etc. - * - * @method magSq - * @return {number} squared magnitude of the vector - * @example - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(6, 4, 2); - * print(v1.magSq()); // Prints "56" - * </code> - * </div> - */ -p5.Vector.prototype.magSq = function () { - var x = this.x, y = this.y, z = this.z; - return (x * x + y * y + z * z); -}; - -/** - * Calculates the dot product of two vectors. The version of the method - * that computes the dot product of two independent vectors is a static - * method. See the examples for more context. - * - * - * @method dot - * @param {Number|p5.Vector} x x component of the vector or a p5.Vector - * @param {Number} [y] y component of the vector - * @param {Number} [z] z component of the vector - * @return {Number} the dot product - * - * @example - * <div class="norender"> - * <code> - * var v1 = createVector(1, 2, 3); - * var v2 = createVector(2, 3, 4); - * - * print(v1.dot(v2)); // Prints "20" - * </code> - * </div> - * - * <div class="norender"> - * <code> - * //Static method - * var v1 = createVector(1, 2, 3); - * var v2 = createVector(3, 2, 1); - * print (p5.Vector.dot(v1, v2)); // Prints "10" - * </code> - * </div> - */ -p5.Vector.prototype.dot = function (x, y, z) { - if (x instanceof p5.Vector) { - return this.dot(x.x, x.y, x.z); - } - return this.x * (x || 0) + - this.y * (y || 0) + - this.z * (z || 0); -}; - -/** - * Calculates and returns a vector composed of the cross product between - * two vectors. Both the static and non static methods return a new p5.Vector. - * See the examples for more context. - * - * @method cross - * @param {p5.Vector} v p5.Vector to be crossed - * @return {p5.Vector} p5.Vector composed of cross product - * @example - * <div class="norender"> - * <code> - * var v1 = createVector(1, 2, 3); - * var v2 = createVector(1, 2, 3); - * - * v1.cross(v2); // v's components are [0, 0, 0] - * </code> - * </div> - * - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(1, 0, 0); - * var v2 = createVector(0, 1, 0); - * - * var crossProduct = p5.Vector.cross(v1, v2); - * // crossProduct has components [0, 0, 1] - * </code> - * </div> - */ -p5.Vector.prototype.cross = function (v) { - var x = this.y * v.z - this.z * v.y; - var y = this.z * v.x - this.x * v.z; - var z = this.x * v.y - this.y * v.x; - if (this.p5) { - return new p5.Vector(this.p5,[x,y,z]); - } else { - return new p5.Vector(x,y,z); - } -}; - -/** - * Calculates the Euclidean distance between two points (considering a - * point as a vector object). - * - * @method dist - * @param {p5.Vector} v the x, y, and z coordinates of a p5.Vector - * @return {Number} the distance - * @example - * <div class="norender"> - * <code> - * var v1 = createVector(1, 0, 0); - * var v2 = createVector(0, 1, 0); - * - * var distance = v1.dist(v2); // distance is 1.4142... - * </code> - * </div> - * <div class="norender"> - * <code> - * // Static method - * var v1 = createVector(1, 0, 0); - * var v2 = createVector(0, 1, 0); - * - * var distance = p5.Vector.dist(v1,v2); - * // distance is 1.4142... - * </code> - * </div> - */ -p5.Vector.prototype.dist = function (v) { - var d = v.copy().sub(this); - return d.mag(); -}; - -/** - * Normalize the vector to length 1 (make it a unit vector). - * - * @method normalize - * @return {p5.Vector} normalized p5.Vector - * @example - * <div class="norender"> - * <code> - * var v = createVector(10, 20, 2); - * // v has compnents [10.0, 20.0, 2.0] - * v.normalize(); - * // v's compnents are set to - * // [0.4454354, 0.8908708, 0.089087084] - * </code> - * </div> - * - */ -p5.Vector.prototype.normalize = function () { - return this.div(this.mag()); -}; - -/** - * Limit the magnitude of this vector to the value used for the <b>max</b> - * parameter. - * - * @method limit - * @param {Number} max the maximum magnitude for the vector - * @return {p5.Vector} the modified p5.Vector - * @example - * <div class="norender"> - * <code> - * var v = createVector(10, 20, 2); - * // v has compnents [10.0, 20.0, 2.0] - * v.limit(5); - * // v's compnents are set to - * // [2.2271771, 4.4543543, 0.4454354] - * </code> - * </div> - */ -p5.Vector.prototype.limit = function (l) { - var mSq = this.magSq(); - if(mSq > l*l) { - this.div(Math.sqrt(mSq)); //normalize it - this.mult(l); - } - return this; -}; - -/** - * Set the magnitude of this vector to the value used for the <b>len</b> - * parameter. - * - * @method setMag - * @param {number} len the new length for this vector - * @return {p5.Vector} the modified p5.Vector - * @example - * <div class="norender"> - * <code> - * var v1 = createVector(10, 20, 2); - * // v has compnents [10.0, 20.0, 2.0] - * v1.setMag(10); - * // v's compnents are set to [6.0, 8.0, 0.0] - * </code> - * </div> - */ -p5.Vector.prototype.setMag = function (n) { - return this.normalize().mult(n); -}; - -/** - * Calculate the angle of rotation for this vector (only 2D vectors) - * - * @method heading - * @return {Number} the angle of rotation - * @example - * <div class = "norender"><code> - * function setup() { - * var v1 = createVector(30,50); - * print(v1.heading()); // 1.0303768265243125 - * - * var v1 = createVector(40,50); - * print(v1.heading()); // 0.8960553845713439 - * - * var v1 = createVector(30,70); - * print(v1.heading()); // 1.1659045405098132 - * } - * </div></code> - */ -p5.Vector.prototype.heading = function () { - var h = Math.atan2(this.y, this.x); - if (this.p5) { - if (this.p5._angleMode === constants.RADIANS) { - return h; - } else { - return polarGeometry.radiansToDegrees(h); - } - } else { - return h; - } -}; - -/** - * Rotate the vector by an angle (only 2D vectors), magnitude remains the - * same - * - * @method rotate - * @param {number} angle the angle of rotation - * @return {p5.Vector} the modified p5.Vector - * @example - * <div class="norender"> - * <code> - * var v = createVector(10.0, 20.0); - * // v has compnents [10.0, 20.0, 0.0] - * v.rotate(HALF_PI); - * // v's compnents are set to [-20.0, 9.999999, 0.0] - * </code> - * </div> - */ -p5.Vector.prototype.rotate = function (a) { - if (this.p5) { - if (this.p5._angleMode === constants.DEGREES) { - a = polarGeometry.degreesToRadians(a); - } - } - var newHeading = this.heading() + a; - var mag = this.mag(); - this.x = Math.cos(newHeading) * mag; - this.y = Math.sin(newHeading) * mag; - return this; -}; - -/** - * Linear interpolate the vector to another vector - * - * @method lerp - * @param {p5.Vector} x the x component or the p5.Vector to lerp to - * @param {p5.Vector} [y] y the y component - * @param {p5.Vector} [z] z the z component - * @param {Number} amt the amount of interpolation; some value between 0.0 - * (old vector) and 1.0 (new vector). 0.1 is very near - * the new vector. 0.5 is halfway in between. - * @return {p5.Vector} the modified p5.Vector - * @example - * <div class="norender"> - * <code> - * var v = createVector(1, 1, 0); - * - * v.lerp(3, 3, 0, 0.5); // v now has components [2,2,0] - * </code> - * </div> - * - * <div class="norender"> - * <code> - * var v1 = createVector(0, 0, 0); - * var v2 = createVector(100, 100, 0); - * - * var v3 = p5.Vector.lerp(v1, v2, 0.5); - * // v3 has components [50,50,0] - * </code> - * </div> - */ -p5.Vector.prototype.lerp = function (x, y, z, amt) { - if (x instanceof p5.Vector) { - return this.lerp(x.x, x.y, x.z, y); - } - this.x += (x - this.x) * amt || 0; - this.y += (y - this.y) * amt || 0; - this.z += (z - this.z) * amt || 0; - return this; -}; - -/** - * Return a representation of this vector as a float array. This is only - * for temporary use. If used in any other fashion, the contents should be - * copied by using the <b>p5.Vector.copy()</b> method to copy into your own - * array. - * - * @method array - * @return {Array} an Array with the 3 values - * @example - * <div class = "norender"><code> - * function setup() { - * var v = createVector(20,30); - * print(v.array()); // Prints : Array [20, 30, 0] - * } - * </div></code> - * <div class="norender"> - * <code> - * var v = createVector(10.0, 20.0, 30.0); - * var f = v.array(); - * print(f[0]); // Prints "10.0" - * print(f[1]); // Prints "20.0" - * print(f[2]); // Prints "30.0" - * </code> - * </div> - */ -p5.Vector.prototype.array = function () { - return [this.x || 0, this.y || 0, this.z || 0]; -}; - -/** - * Equality check against a p5.Vector - * - * @method equals - * @param {Number|p5.Vector|Array} [x] the x component of the vector or a - * p5.Vector or an Array - * @param {Number} [y] the y component of the vector - * @param {Number} [z] the z component of the vector - * @return {Boolean} whether the vectors are equals - * @example - * <div class = "norender"><code> - * v1 = createVector(5,10,20); - * v2 = createVector(5,10,20); - * v3 = createVector(13,10,19); - * - * print(v1.equals(v2.x,v2.y,v2.z)); // true - * print(v1.equals(v3.x,v3.y,v3.z)); // false - * </div></code> - * <div class="norender"> - * <code> - * var v1 = createVector(10.0, 20.0, 30.0); - * var v2 = createVector(10.0, 20.0, 30.0); - * var v3 = createVector(0.0, 0.0, 0.0); - * print (v1.equals(v2)) // true - * print (v1.equals(v3)) // false - * </code> - * </div> - */ -p5.Vector.prototype.equals = function (x, y, z) { - var a, b, c; - if (x instanceof p5.Vector) { - a = x.x || 0; - b = x.y || 0; - c = x.z || 0; - } else if (x instanceof Array) { - a = x[0] || 0; - b = x[1] || 0; - c = x[2] || 0; - } else { - a = x || 0; - b = y || 0; - c = z || 0; - } - return this.x === a && this.y === b && this.z === c; -}; - - -// Static Methods - - -/** - * Make a new 2D unit vector from an angle - * - * @method fromAngle - * @static - * @param {Number} angle the desired angle - * @return {p5.Vector} the new p5.Vector object - * @example - * <div> - * <code> - * function draw() { - * background (200); - * - * // Create a variable, proportional to the mouseX, - * // varying from 0-360, to represent an angle in degrees. - * angleMode(DEGREES); - * var myDegrees = map(mouseX, 0,width, 0,360); - * - * // Display that variable in an onscreen text. - * // (Note the nfc() function to truncate additional decimal places, - * // and the "\xB0" character for the degree symbol.) - * var readout = "angle = " + nfc(myDegrees,1,1) + "\xB0" - * noStroke(); - * fill (0); - * text (readout, 5, 15); - * - * // Create a p5.Vector using the fromAngle function, - * // and extract its x and y components. - * var v = p5.Vector.fromAngle(radians(myDegrees)); - * var vx = v.x; - * var vy = v.y; - * - * push(); - * translate (width/2, height/2); - * noFill(); - * stroke (150); - * line (0,0, 30,0); - * stroke (0); - * line (0,0, 30*vx, 30*vy); - * pop() - * } - * </code> - * </div> - */ -p5.Vector.fromAngle = function(angle) { - if (this.p5) { - if (this.p5._angleMode === constants.DEGREES) { - angle = polarGeometry.degreesToRadians(angle); - } - } - if (this.p5) { - return new p5.Vector(this.p5,[Math.cos(angle),Math.sin(angle),0]); - } else { - return new p5.Vector(Math.cos(angle),Math.sin(angle),0); - } -}; - -/** - * Make a new 2D unit vector from a random angle - * - * @method random2D - * @static - * @return {p5.Vector} the new p5.Vector object - * @example - * <div class="norender"> - * <code> - * var v = p5.Vector.random2D(); - * // May make v's attributes something like: - * // [0.61554617, -0.51195765, 0.0] or - * // [-0.4695841, -0.14366731, 0.0] or - * // [0.6091097, -0.22805278, 0.0] - * </code> - * </div> - */ -p5.Vector.random2D = function () { - var angle; - // A lot of nonsense to determine if we know about a - // p5 sketch and whether we should make a random angle in degrees or radians - if (this.p5) { - if (this.p5._angleMode === constants.DEGREES) { - angle = this.p5.random(360); - } else { - angle = this.p5.random(constants.TWO_PI); - } - } else { - angle = Math.random()*Math.PI*2; - } - return this.fromAngle(angle); -}; - -/** - * Make a new random 3D unit vector. - * - * @method random3D - * @static - * @return {p5.Vector} the new p5.Vector object - * @example - * <div class="norender"> - * <code> - * var v = p5.Vector.random3D(); - * // May make v's attributes something like: - * // [0.61554617, -0.51195765, 0.599168] or - * // [-0.4695841, -0.14366731, -0.8711202] or - * // [0.6091097, -0.22805278, -0.7595902] - * </code> - * </div> - */ -p5.Vector.random3D = function () { - var angle,vz; - // If we know about p5 - if (this.p5) { - angle = this.p5.random(0,constants.TWO_PI); - vz = this.p5.random(-1,1); - } else { - angle = Math.random()*Math.PI*2; - vz = Math.random()*2-1; - } - var vx = Math.sqrt(1-vz*vz)*Math.cos(angle); - var vy = Math.sqrt(1-vz*vz)*Math.sin(angle); - if (this.p5) { - return new p5.Vector(this.p5,[vx,vy,vz]); - } else { - return new p5.Vector(vx,vy,vz); - } -}; - - -/** - * Adds two vectors together and returns a new one. - * - * @static - * @param {p5.Vector} v1 a p5.Vector to add - * @param {p5.Vector} v2 a p5.Vector to add - * @param {p5.Vector} target if undefined a new vector will be created - * @return {p5.Vector} the resulting p5.Vector - * - */ - -p5.Vector.add = function (v1, v2, target) { - if (!target) { - target = v1.copy(); - } else { - target.set(v1); - } - target.add(v2); - return target; -}; - -/** - * Subtracts one p5.Vector from another and returns a new one. The second - * vector (v2) is subtracted from the first (v1), resulting in v1-v2. - * - * @static - * @param {p5.Vector} v1 a p5.Vector to subtract from - * @param {p5.Vector} v2 a p5.Vector to subtract - * @param {p5.Vector} target if undefined a new vector will be created - * @return {p5.Vector} the resulting p5.Vector - */ - -p5.Vector.sub = function (v1, v2, target) { - if (!target) { - target = v1.copy(); - } else { - target.set(v1); - } - target.sub(v2); - return target; -}; - - -/** - * Multiplies a vector by a scalar and returns a new vector. - * - * @static - * @param {p5.Vector} v the p5.Vector to multiply - * @param {Number} n the scalar - * @param {p5.Vector} target if undefined a new vector will be created - * @return {p5.Vector} the resulting new p5.Vector - */ -p5.Vector.mult = function (v, n, target) { - if (!target) { - target = v.copy(); - } else { - target.set(v); - } - target.mult(n); - return target; -}; - -/** - * Divides a vector by a scalar and returns a new vector. - * - * @static - * @param {p5.Vector} v the p5.Vector to divide - * @param {Number} n the scalar - * @param {p5.Vector} target if undefined a new vector will be created - * @return {p5.Vector} the resulting new p5.Vector - */ -p5.Vector.div = function (v, n, target) { - if (!target) { - target = v.copy(); - } else { - target.set(v); - } - target.div(n); - return target; -}; - - -/** - * Calculates the dot product of two vectors. - * - * @static - * @param {p5.Vector} v1 the first p5.Vector - * @param {p5.Vector} v2 the second p5.Vector - * @return {Number} the dot product - */ -p5.Vector.dot = function (v1, v2) { - return v1.dot(v2); -}; - -/** - * Calculates the cross product of two vectors. - * - * @static - * @param {p5.Vector} v1 the first p5.Vector - * @param {p5.Vector} v2 the second p5.Vector - * @return {Number} the cross product - */ -p5.Vector.cross = function (v1, v2) { - return v1.cross(v2); -}; - -/** - * Calculates the Euclidean distance between two points (considering a - * point as a vector object). - * - * @static - * @param {p5.Vector} v1 the first p5.Vector - * @param {p5.Vector} v2 the second p5.Vector - * @return {Number} the distance - */ -p5.Vector.dist = function (v1,v2) { - return v1.dist(v2); -}; - -/** - * Linear interpolate a vector to another vector and return the result as a - * new vector. - * - * @static - * @param {p5.Vector} v1 a starting p5.Vector - * @param {p5.Vector} v2 the p5.Vector to lerp to - * @param {Number} the amount of interpolation; some value between 0.0 - * (old vector) and 1.0 (new vector). 0.1 is very near - * the new vector. 0.5 is halfway in between. - */ -p5.Vector.lerp = function (v1, v2, amt, target) { - if (!target) { - target = v1.copy(); - } else { - target.set(v1); - } - target.lerp(v2, amt); - return target; -}; - -/** - * Calculates and returns the angle (in radians) between two vectors. - * @method angleBetween - * @static - * @param {p5.Vector} v1 the x, y, and z components of a p5.Vector - * @param {p5.Vector} v2 the x, y, and z components of a p5.Vector - * @return {Number} the angle between (in radians) - * @example - * <div class="norender"> - * <code> - * var v1 = createVector(1, 0, 0); - * var v2 = createVector(0, 1, 0); - * - * var angle = p5.Vector.angleBetween(v1, v2); - * // angle is PI/2 - * </code> - * </div> - */ -p5.Vector.angleBetween = function (v1, v2) { - var angle = Math.acos(v1.dot(v2) / (v1.mag() * v2.mag())); - if (this.p5) { - if (this.p5._angleMode === constants.DEGREES) { - angle = polarGeometry.radiansToDegrees(angle); - } - } - return angle; -}; - -module.exports = p5.Vector; - -},{"../core/constants":47,"../core/core":48,"./polargeometry":77}],77:[function(_dereq_,module,exports){ - -module.exports = { - - degreesToRadians: function(x) { - return 2 * Math.PI * x / 360; - }, - - radiansToDegrees: function(x) { - return 360 * x / (2 * Math.PI); - } - -}; - -},{}],78:[function(_dereq_,module,exports){ -/** - * @module Math - * @submodule Random - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -var seeded = false; - -// Linear Congruential Generator -// Variant of a Lehman Generator -var lcg = (function() { - // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes - // m is basically chosen to be large (as it is the max period) - // and for its relationships to a and c - var m = 4294967296, - // a - 1 should be divisible by m's prime factors - a = 1664525, - // c and m should be co-prime - c = 1013904223, - seed, z; - return { - setSeed : function(val) { - // pick a random seed if val is undefined or null - // the >>> 0 casts the seed to an unsigned 32-bit integer - z = seed = (val == null ? Math.random() * m : val) >>> 0; - }, - getSeed : function() { - return seed; - }, - rand : function() { - // define the recurrence relationship - z = (a * z + c) % m; - // return a float in [0, 1) - // if z = m then z / m = 0 therefore (z % m) / m < 1 always - return z / m; - } - }; -}()); - -/** - * Sets the seed value for random(). - * - * By default, random() produces different results each time the program - * is run. Set the seed parameter to a constant to return the same - * pseudo-random numbers each time the software is run. - * - * @method randomSeed - * @param {Number} seed the seed value - * @example - * <div> - * <code> - * randomSeed(99); - * for (var i=0; i < 100; i++) { - * var r = random(0, 255); - * stroke(r); - * line(i, 0, i, 100); - * } - * </code> - * </div> - */ -p5.prototype.randomSeed = function(seed) { - lcg.setSeed(seed); - seeded = true; -}; - -/** - * Return a random number. - * - * Takes either 0, 1 or 2 arguments. - * If no argument is given, returns a random number between 0 and 1. - * If one argument is given, returns a random number between 0 and the number. - * If two arguments are given, returns a random number between them, - * inclusive. - * - * @method random - * @param {Number} min the lower bound - * @param {Number} max the upper bound - * @return {Number} the random number - * @example - * <div> - * <code> - * for (var i = 0; i < 100; i++) { - * var r = random(50); - * stroke(r*5); - * line(50, i, 50+r, i); - * } - * </code> - * </div> - * <div> - * <code> - * for (var i = 0; i < 100; i++) { - * var r = random(-50, 50); - * line(50,i,50+r,i); - * } - * </code> - * </div> - * <div> - * <code> - * // Get a random element from an array - * var words = [ "apple", "bear", "cat", "dog" ]; - * var index = floor(random(words.length)); // Convert to integer - * text(words[index],10,50); // Displays one of the four words - * </code> - * </div> - */ -p5.prototype.random = function (min, max) { - - var rand; - - if (seeded) { - rand = lcg.rand(); - } else { - rand = Math.random(); - } - - if (arguments.length === 0) { - return rand; - } else - if (arguments.length === 1) { - return rand * min; - } else { - if (min > max) { - var tmp = min; - min = max; - max = tmp; - } - - return rand * (max-min) + min; - } -}; - - -/** - * - * Returns a random number fitting a Gaussian, or - * normal, distribution. There is theoretically no minimum or maximum - * value that randomGaussian() might return. Rather, there is - * just a very low probability that values far from the mean will be - * returned; and a higher probability that numbers near the mean will - * be returned. - * <br><br> - * Takes either 0, 1 or 2 arguments.<br> - * If no args, returns a mean of 0 and standard deviation of 1.<br> - * If one arg, that arg is the mean (standard deviation is 1).<br> - * If two args, first is mean, second is standard deviation. - * - * @method randomGaussian - * @param {Number} mean the mean - * @param {Number} sd the standard deviation - * @return {Number} the random number - * @example - * <div> - * <code>for (var y = 0; y < 100; y++) { - * var x = randomGaussian(50,15); - * line(50, y, x, y); - *} - * </code> - * </div> - * <div> - * <code> - *var distribution = new Array(360); - * - *function setup() { - * createCanvas(100, 100); - * for (var i = 0; i < distribution.length; i++) { - * distribution[i] = floor(randomGaussian(0,15)); - * } - *} - * - *function draw() { - * background(204); - * - * translate(width/2, width/2); - * - * for (var i = 0; i < distribution.length; i++) { - * rotate(TWO_PI/distribution.length); - * stroke(0); - * var dist = abs(distribution[i]); - * line(0, 0, dist, 0); - * } - *} - * </code> - * </div> - */ -var y2; -var previous = false; -p5.prototype.randomGaussian = function(mean, sd) { - var y1,x1,x2,w; - if (previous) { - y1 = y2; - previous = false; - } else { - do { - x1 = this.random(2) - 1; - x2 = this.random(2) - 1; - w = x1 * x1 + x2 * x2; - } while (w >= 1); - w = Math.sqrt((-2 * Math.log(w))/w); - y1 = x1 * w; - y2 = x2 * w; - previous = true; - } - - var m = mean || 0; - var s = sd || 1; - return y1*s + m; -}; - -module.exports = p5; - -},{"../core/core":48}],79:[function(_dereq_,module,exports){ -/** - * @module Math - * @submodule Trigonometry - * @for p5 - * @requires core - * @requires polargeometry - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var polarGeometry = _dereq_('./polargeometry'); -var constants = _dereq_('../core/constants'); - -p5.prototype._angleMode = constants.RADIANS; - -/** - * The inverse of cos(), returns the arc cosine of a value. This function - * expects the values in the range of -1 to 1 and values are returned in - * the range 0 to PI (3.1415927). - * - * @method acos - * @param {Number} value the value whose arc cosine is to be returned - * @return {Number} the arc cosine of the given value - * - * @example - * <div class= “norender"> - * <code> - * var a = PI; - * var c = cos(a); - * var ac = acos(c); - * // Prints: "3.1415927 : -1.0 : 3.1415927" - * println(a + " : " + c + " : " + ac); - * </code> - * </div> - * - * <div class= “norender"> - * <code> - * var a = PI + PI/4.0; - * var c = cos(a); - * var ac = acos(c); - * // Prints: "3.926991 : -0.70710665 : 2.3561943" - * println(a + " : " + c + " : " + ac); - * </code> - * </div> - */ -p5.prototype.acos = function(ratio) { - if (this._angleMode === constants.RADIANS) { - return Math.acos(ratio); - } else { - return polarGeometry.radiansToDegrees(Math.acos(ratio)); - } -}; - -/** - * The inverse of sin(), returns the arc sine of a value. This function - * expects the values in the range of -1 to 1 and values are returned - * in the range -PI/2 to PI/2. - * - * @method asin - * @param {Number} value the value whose arc sine is to be returned - * @return {Number} the arc sine of the given value - * - * @example - * <div class= “norender"> - * <code> - * var a = PI + PI/3; - * var s = sin(a); - * var as = asin(s); - * // Prints: "1.0471976 : 0.86602545 : 1.0471976" - * println(a + " : " + s + " : " + as); - * </code> - * </div> - * - * <div class= “norender"> - * <code> - * var a = PI + PI/3.0; - * var s = sin(a); - * var as = asin(s); - * // Prints: "4.1887903 : -0.86602545 : -1.0471976" - * println(a + " : " + s + " : " + as); - * </code> - * </div> - * - */ -p5.prototype.asin = function(ratio) { - if (this._angleMode === constants.RADIANS) { - return Math.asin(ratio); - } else { - return polarGeometry.radiansToDegrees(Math.asin(ratio)); - } -}; - -/** - * The inverse of tan(), returns the arc tangent of a value. This function - * expects the values in the range of -Infinity to Infinity (exclusive) and - * values are returned in the range -PI/2 to PI/2. - * - * @method atan - * @param {Number} value the value whose arc tangent is to be returned - * @return {Number} the arc tangent of the given value - * - * @example - * <div class= “norender"> - * <code> - * var a = PI + PI/3; - * var t = tan(a); - * var at = atan(t); - * // Prints: "1.0471976 : 1.7320509 : 1.0471976" - * println(a + " : " + t + " : " + at); - * </code> - * </div> - * - * <div class= “norender"> - * <code> - * var a = PI + PI/3.0; - * var t = tan(a); - * var at = atan(t); - * // Prints: "4.1887903 : 1.7320513 : 1.0471977" - * println(a + " : " + t + " : " + at); - * </code> - * </div> - * - */ -p5.prototype.atan = function(ratio) { - if (this._angleMode === constants.RADIANS) { - return Math.atan(ratio); - } else { - return polarGeometry.radiansToDegrees(Math.atan(ratio)); - } -}; - -/** - * Calculates the angle (in radians) from a specified point to the coordinate - * origin as measured from the positive x-axis. Values are returned as a - * float in the range from PI to -PI. The atan2() function is most often used - * for orienting geometry to the position of the cursor. - * <br><br> - * Note: The y-coordinate of the point is the first parameter, and the - * x-coordinate is the second parameter, due the the structure of calculating - * the tangent. - * - * @method atan2 - * @param {Number} y y-coordinate of the point - * @param {Number} x x-coordinate of the point - * @return {Number} the arc tangent of the given point - * - * @example - * <div> - * <code> - * function draw() { - * background(204); - * translate(width/2, height/2); - * var a = atan2(mouseY-height/2, mouseX-width/2); - * rotate(a); - * rect(-30, -5, 60, 10); - * } - * </code> - * </div> - */ -p5.prototype.atan2 = function (y, x) { - if (this._angleMode === constants.RADIANS) { - return Math.atan2(y, x); - } else { - return polarGeometry.radiansToDegrees(Math.atan2(y, x)); - } -}; - -/** - * Calculates the cosine of an angle. This function takes into account the - * current angleMode. Values are returned in the range -1 to 1. - * - * @method cos - * @param {Number} angle the angle - * @return {Number} the cosine of the angle - * - * @example - * <div> - * <code> - * var a = 0.0; - * var inc = TWO_PI/25.0; - * for (var i = 0; i < 25; i++) { - * line(i*4, 50, i*4, 50+cos(a)*40.0); - * a = a + inc; - * } - * </code> - * </div> - * - */ -p5.prototype.cos = function(angle) { - if (this._angleMode === constants.RADIANS) { - return Math.cos(angle); - } else { - return Math.cos(this.radians(angle)); - } -}; - -/** - * Calculates the sine of an angle. This function takes into account the - * current angleMode. Values are returned in the range -1 to 1. - * - * @method sin - * @param {Number} angle the angle - * @return {Number} the sine of the angle - * - * @example - * <div> - * <code> - * var a = 0.0; - * var inc = TWO_PI/25.0; - * for (var i = 0; i < 25; i++) { - * line(i*4, 50, i*4, 50+sin(a)*40.0); - * a = a + inc; - * } - * </code> - * </div> - */ -p5.prototype.sin = function(angle) { - if (this._angleMode === constants.RADIANS) { - return Math.sin(angle); - } else { - return Math.sin(this.radians(angle)); - } -}; - -/** - * Calculates the tangent of an angle. This function takes into account - * the current angleMode. Values are returned in the range -1 to 1. - * - * @method tan - * @param {Number} angle the angle - * @return {Number} the tangent of the angle - * - * @example - * <div> - * <code> - * var a = 0.0; - * var inc = TWO_PI/50.0; - * for (var i = 0; i < 100; i = i+2) { - * line(i, 50, i, 50+tan(a)*2.0); - * a = a + inc; - * } - * </code> - * </div> - * - */ -p5.prototype.tan = function(angle) { - if (this._angleMode === constants.RADIANS) { - return Math.tan(angle); - } else { - return Math.tan(this.radians(angle)); - } -}; - -/** - * Converts a radian measurement to its corresponding value in degrees. - * Radians and degrees are two ways of measuring the same thing. There are - * 360 degrees in a circle and 2*PI radians in a circle. For example, - * 90° = PI/2 = 1.5707964. - * - * @method degrees - * @param {Number} radians the radians value to convert to degrees - * @return {Number} the converted angle - * - * - * @example - * <div class= “norender"> - * <code> - * var rad = PI/4; - * var deg = degrees(rad); - * println(rad + " radians is " + deg + " degrees"); - * // Prints: 45 degrees is 0.7853981633974483 radians - * </code> - * </div> - * - */ -p5.prototype.degrees = function(angle) { - return polarGeometry.radiansToDegrees(angle); -}; - -/** - * Converts a degree measurement to its corresponding value in radians. - * Radians and degrees are two ways of measuring the same thing. There are - * 360 degrees in a circle and 2*PI radians in a circle. For example, - * 90° = PI/2 = 1.5707964. - * - * @method radians - * @param {Number} degrees the degree value to convert to radians - * @return {Number} the converted angle - * - * @example - * <div class= “norender"> - * <code> - * var deg = 45.0; - * var rad = radians(deg); - * println(deg + " degrees is " + rad + " radians"); - * // Prints: 45 degrees is 0.7853981633974483 radians - * </code> - * </div> - */ -p5.prototype.radians = function(angle) { - return polarGeometry.degreesToRadians(angle); -}; - -/** - * Sets the current mode of p5 to given mode. Default mode is RADIANS. - * - * @method angleMode - * @param {Number/Constant} mode either RADIANS or DEGREES - * - * @example - * <div> - * <code> - * function draw(){ - * background(204); - * angleMode(DEGREES); // Change the mode to DEGREES - * var a = atan2(mouseY-height/2, mouseX-width/2); - * translate(width/2, height/2); - * push(); - * rotate(a); - * rect(-20, -5, 40, 10); // Larger rectangle is rotating in degrees - * pop(); - * angleMode(RADIANS); // Change the mode to RADIANS - * rotate(a); // var a stays the same - * rect(-40, -5, 20, 10); // Smaller rectangle is rotating in radians - * } - * </code> - * </div> - * - */ -p5.prototype.angleMode = function(mode) { - if (mode === constants.DEGREES || mode === constants.RADIANS) { - this._angleMode = mode; - } -}; - -module.exports = p5; - -},{"../core/constants":47,"../core/core":48,"./polargeometry":77}],80:[function(_dereq_,module,exports){ -/** - * @module Typography - * @submodule Attributes - * @for p5 - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Sets the current alignment for drawing text. The parameters LEFT, CENTER, - * and RIGHT set the alignment of text in relation to the values for - * the x and y parameters of the text() function. - * - * @method textAlign - * @param {Number/Constant} horizAlign horizontal alignment, either LEFT, - * CENTER, or RIGHT - * @param {Number/Constant} vertAlign vertical alignment, either TOP, - * BOTTOM, CENTER, or BASELINE - * @return {Number} - * @example - * <div> - * <code> - * textSize(16); - * textAlign(RIGHT); - * text("ABCD", 50, 30); - * textAlign(CENTER); - * text("EFGH", 50, 50); - * textAlign(LEFT); - * text("IJKL", 50, 70); - * </code> - * </div> - */ -p5.prototype.textAlign = function(horizAlign, vertAlign) { - return this._renderer.textAlign.apply(this._renderer, arguments); -}; - -/** - * Sets/gets the spacing, in pixels, between lines of text. This - * setting will be used in all subsequent calls to the text() function. - * - * @method textLeading - * @param {Number} leading the size in pixels for spacing between lines - * @return {Object|Number} - * @example - * <div> - * <code> - * // Text to display. The "\n" is a "new line" character - * lines = "L1\nL2\nL3"; - * textSize(12); - * - * textLeading(10); // Set leading to 10 - * text(lines, 10, 25); - * - * textLeading(20); // Set leading to 20 - * text(lines, 40, 25); - * - * textLeading(30); // Set leading to 30 - * text(lines, 70, 25); - * </code> - * </div> - */ -p5.prototype.textLeading = function(theLeading) { - return this._renderer.textLeading.apply(this._renderer, arguments); -}; - -/** - * Sets/gets the current font size. This size will be used in all subsequent - * calls to the text() function. Font size is measured in pixels. - * - * @method textSize - * @param {Number} theSize the size of the letters in units of pixels - * @return {Object|Number} - * @example - * <div> - * <code> - * textSize(12); - * text("Font Size 12", 10, 30); - * textSize(14); - * text("Font Size 14", 10, 60); - * textSize(16); - * text("Font Size 16", 10, 90); - * </code> - * </div> - */ -p5.prototype.textSize = function(theSize) { - return this._renderer.textSize.apply(this._renderer, arguments); -}; - -/** - * Sets/gets the style of the text for system fonts to NORMAL, ITALIC, or BOLD. - * Note: this may be is overridden by CSS styling. For non-system fonts - * (opentype, truetype, etc.) please load styled fonts instead. - * - * @method textStyle - * @param {Number/Constant} theStyle styling for text, either NORMAL, - * ITALIC, or BOLD - * @return {Object|String} - * @example - * <div> - * <code> - * strokeWeight(0); - * textSize(12); - * textStyle(NORMAL); - * text("Font Style Normal", 10, 30); - * textStyle(ITALIC); - * text("Font Style Italic", 10, 60); - * textStyle(BOLD); - * text("Font Style Bold", 10, 90); - * </code> - * </div> - */ -p5.prototype.textStyle = function(theStyle) { - return this._renderer.textStyle.apply(this._renderer, arguments); -}; - -/** - * Calculates and returns the width of any character or text string. - * - * @method textWidth - * @param {String} theText the String of characters to measure - * @return {Number} - * @example - * <div> - * <code> - * textSize(28); - * - * var aChar = 'P'; - * var cWidth = textWidth(aChar); - * text(aChar, 0, 40); - * line(cWidth, 0, cWidth, 50); - * - * var aString = "p5.js"; - * var sWidth = textWidth(aString); - * text(aString, 0, 85); - * line(sWidth, 50, sWidth, 100); - * </code> - * </div> - */ -p5.prototype.textWidth = function(theText) { - return this._renderer.textWidth.apply(this._renderer, arguments); -}; - -/** - * Returns the ascent of the current font at its current size. The ascent - * represents the distance, in pixels, of the tallest character above - * the baseline. - * - * @return {Number} - * @example - * <div> - * <code> - * var base = height * 0.75; - * var scalar = 0.8; // Different for each font - * - * textSize(32); // Set initial text size - * var asc = textAscent() * scalar; // Calc ascent - * line(0, base - asc, width, base - asc); - * text("dp", 0, base); // Draw text on baseline - * - * textSize(64); // Increase text size - * asc = textAscent() * scalar; // Recalc ascent - * line(40, base - asc, width, base - asc); - * text("dp", 40, base); // Draw text on baseline - * </code> - * </div> - */ -p5.prototype.textAscent = function() { - return this._renderer.textAscent(); -}; - -/** - * Returns the descent of the current font at its current size. The descent - * represents the distance, in pixels, of the character with the longest - * descender below the baseline. - * - * @return {Number} - * @example - * <div> - * <code> - * var base = height * 0.75; - * var scalar = 0.8; // Different for each font - * - * textSize(32); // Set initial text size - * var desc = textDescent() * scalar; // Calc ascent - * line(0, base+desc, width, base+desc); - * text("dp", 0, base); // Draw text on baseline - * - * textSize(64); // Increase text size - * desc = textDescent() * scalar; // Recalc ascent - * line(40, base + desc, width, base + desc); - * text("dp", 40, base); // Draw text on baseline - * </code> - * </div> - */ -p5.prototype.textDescent = function() { - return this._renderer.textDescent(); -}; - -/** - * Helper function to measure ascent and descent. - */ -p5.prototype._updateTextMetrics = function() { - return this._renderer._updateTextMetrics(); -}; - -module.exports = p5; - -},{"../core/core":48}],81:[function(_dereq_,module,exports){ -/** - * @module Typography - * @submodule Loading & Displaying - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var constants = _dereq_('../core/constants'); - -_dereq_('../core/error_helpers'); - - -/** - * Draws text to the screen. Displays the information specified in the first - * parameter on the screen in the position specified by the additional - * parameters. A default font will be used unless a font is set with the - * textFont() function and a default size will be used unless a font is set - * with textSize(). Change the color of the text with the fill() function. - * Change the outline of the text with the stroke() and strokeWeight() - * functions. - * <br><br> - * The text displays in relation to the textAlign() function, which gives the - * option to draw to the left, right, and center of the coordinates. - * <br><br> - * The x2 and y2 parameters define a rectangular area to display within and - * may only be used with string data. When these parameters are specified, - * they are interpreted based on the current rectMode() setting. Text that - * does not fit completely within the rectangle specified will not be drawn - * to the screen. - * - * @method text - * @param {String} str the alphanumeric symbols to be displayed - * @param {Number} x x-coordinate of text - * @param {Number} y y-coordinate of text - * @param {Number} x2 by default, the width of the text box, - * see rectMode() for more info - * @param {Number} y2 by default, the height of the text box, - * see rectMode() for more info - * @return {Object} this - * @example - * <div> - * <code> - * textSize(32); - * text("word", 10, 30); - * fill(0, 102, 153); - * text("word", 10, 60); - * fill(0, 102, 153, 51); - * text("word", 10, 90); - * </code> - * </div> - * <div> - * <code> - * s = "The quick brown fox jumped over the lazy dog."; - * fill(50); - * text(s, 10, 10, 70, 80); // Text wraps within text box - * </code> - * </div> - */ -p5.prototype.text = function(str, x, y, maxWidth, maxHeight) { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - this._validateParameters( - 'text', - args, - [ - ['*', 'Number', 'Number'], - ['*', 'Number', 'Number', 'Number', 'Number'] - ] - ); - - return (!(this._renderer._doFill || this._renderer._doStroke)) ? this : - this._renderer.text.apply(this._renderer, arguments); -}; - -/** - * Sets the current font that will be drawn with the text() function. - * - * @method textFont - * @param {Object|String} f a font loaded via loadFont(), or a String - * representing a browser-based dfault font. - * @return {Object} this - * @example - * <div> - * <code> - * fill(0); - * textSize(12); - * textFont("Georgia"); - * text("Georgia", 12, 30); - * textFont("Helvetica"); - * text("Helvetica", 12, 60); - * </code> - * </div> - * <div> - * <code> - * var fontRegular, fontItalic, fontBold; - * function preload() { - * fontRegular = loadFont("assets/Regular.otf"); - * fontItalic = loadFont("assets/Italic.ttf"); - * fontBold = loadFont("assets/Bold.ttf"); - * } - * function setup() { - * background(210); - * fill(0).strokeWeight(0).textSize(10); - * textFont(fontRegular); - * text("Font Style Normal", 10, 30); - * textFont(fontItalic); - * text("Font Style Italic", 10, 50); - * textFont(fontBold); - * text("Font Style Bold", 10, 70); - * } - * </code> - * </div> - */ -p5.prototype.textFont = function(theFont, theSize) { - - if (arguments.length) { - - if (!theFont) { - - throw Error('null font passed to textFont'); - } - - this._renderer._setProperty('_textFont', theFont); - - if (theSize) { - - this._renderer._setProperty('_textSize', theSize); - this._renderer._setProperty('_textLeading', - theSize * constants._DEFAULT_LEADMULT); - } - - return this._renderer._applyTextProperties(); - } - - return this; -}; - -module.exports = p5; - -},{"../core/constants":47,"../core/core":48,"../core/error_helpers":51}],82:[function(_dereq_,module,exports){ -/** - * This module defines the p5.Font class and functions for - * drawing text to the display canvas. - * @module Typography - * @submodule Font - * @requires core - * @requires constants - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); -var constants = _dereq_('../core/constants'); - -/* - * TODO: - * - * API: - * -- textBounds() - * -- getPath() - * -- getPoints() - * - * =========================================== - * -- PFont functions: - * PFont.list() - * - * -- kerning - * -- alignment: justified? - * -- integrate p5.dom? (later) - */ - -/** - * Base class for font handling - * @class p5.Font - * @constructor - * @param {Object} [pInst] pointer to p5 instance - */ -p5.Font = function(p) { - - this.parent = p; - - this.cache = {}; - - /** - * Underlying opentype font implementation - * @property font - */ - this.font = undefined; -}; - -p5.Font.prototype.list = function() { - - // TODO - throw 'not yet implemented'; -}; - -/** - * Returns a tight bounding box for the given text string using this - * font (currently only supports single lines) - * - * @method textBounds - * @param {String} line a line of text - * @param {Number} x x-position - * @param {Number} y y-position - * @param {Number} fontSize font size to use (optional) - * @param {Object} options opentype options (optional) - * - * @return {Object} a rectangle object with properties: x, y, w, h - * - * @example - * <div> - * <code> - * var font; - * var textString = 'Lorem ipsum dolor sit amet.'; - * function preload() { - * font = loadFont('./assets/Regular.otf'); - * }; - * function setup() { - * background(210); - * - * var bbox = font.textBounds(textString, 10, 30, 12); - * fill(255); - * stroke(0); - * rect(bbox.x, bbox.y, bbox.w, bbox.h); - * fill(0); - * noStroke(); - * - * textFont(font); - * textSize(12); - * text(textString, 10, 30); - * }; - * </code> - * </div> - */ -p5.Font.prototype.textBounds = function(str, x, y, fontSize, options) { - - x = x !== undefined ? x : 0; - y = y !== undefined ? y : 0; - fontSize = fontSize || this.parent._renderer._textSize; - - var result = this.cache[cacheKey('textBounds', str, x, y, fontSize)]; - if (!result) { - - var xCoords = [], yCoords = [], self = this, - scale = this._scale(fontSize), minX, minY, maxX, maxY; - - this.font.forEachGlyph(str, x, y, fontSize, options, - function(glyph, gX, gY, gFontSize) { - - xCoords.push(gX); - yCoords.push(gY); - - var gm = glyph.getMetrics(); - - if (glyph.name !== 'space') { - - xCoords.push(gX + (gm.xMax * scale)); - yCoords.push(gY + (-gm.yMin * scale)); - yCoords.push(gY + (-gm.yMax * scale)); - - } else { // NOTE: deals with broken metrics for spaces in opentype.js - - xCoords.push(gX + self.font.charToGlyph(' ').advanceWidth * - self._scale(fontSize)); - } - }); - - minX = Math.max(0, Math.min.apply(null, xCoords)); - minY = Math.max(0, Math.min.apply(null, yCoords)); - maxX = Math.max(0, Math.max.apply(null, xCoords)); - maxY = Math.max(0, Math.max.apply(null, yCoords)); - - result = { - x: minX, - y: minY, - h: maxY - minY, - w: maxX - minX, - advance: minX - x - }; - - this.cache[cacheKey('textBounds', str, x, y, fontSize)] = result; - } - //else console.log('cache-hit'); - - return result; -}; - - -/** - * Computes an array of points following the path for specified text - * - * @param {String} txt a line of text - * @param {Number} x x-position - * @param {Number} y y-position - * @param {Number} fontSize font size to use (optional) - * @param {Object} options an (optional) object that can contain: - * - * <br>sampleFactor - the ratio of path-length to number of samples - * (default=.25); higher values yield more points and are therefore - * more precise - * - * <br>simplifyThreshold - if set to a non-zero value, collinear points will be - * be removed from the polygon; the value represents the threshold angle to use - * when determining whether two edges are collinear - * - * @return {Array} an array of points, each with x, y, alpha (the path angle) - */ -p5.Font.prototype.textToPoints = function(txt, x, y, fontSize, options) { - - var xoff = 0, result = [], glyphs = this._getGlyphs(txt); - - fontSize = fontSize || this.parent._renderer._textSize; - - for (var i = 0; i < glyphs.length; i++) { - - var gpath = glyphs[i].getPath(x, y, fontSize), - paths = splitPaths(gpath.commands); - - for (var j = 0; j < paths.length; j++) { - - var pts = pathToPoints(paths[j], options); - - for (var k = 0; k < pts.length; k++) { - pts[k].x += xoff; - result.push(pts[k]); - } - } - - xoff += glyphs[i].advanceWidth * this._scale(fontSize); - } - - return result; -}; - -// ----------------------------- End API ------------------------------ - -/** - * Returns the set of opentype glyphs for the supplied string. - * - * Note that there is not a strict one-to-one mapping between characters - * and glyphs, so the list of returned glyphs can be larger or smaller - * than the length of the given string. - * - * @param {String} str the string to be converted - * @return {array} the opentype glyphs - */ -p5.Font.prototype._getGlyphs = function(str) { - - return this.font.stringToGlyphs(str); -}; - -/** - * Returns an opentype path for the supplied string and position. - * - * @param {String} line a line of text - * @param {Number} x x-position - * @param {Number} y y-position - * @param {Object} options opentype options (optional) - * @return {Object} the opentype path - */ -p5.Font.prototype._getPath = function(line, x, y, options) { - - var p = this.parent, - ctx = p._renderer.drawingContext, - pos = this._handleAlignment(p, ctx, line, x, y); - - return this.font.getPath(line, pos.x, pos.y, p._renderer._textSize, options); -}; - -/* - * Creates an SVG-formatted path-data string - * (See http://www.w3.org/TR/SVG/paths.html#PathData) - * from the given opentype path or string/position - * - * @param {Object} path an opentype path, OR the following: - * - * @param {String} line a line of text - * @param {Number} x x-position - * @param {Number} y y-position - * @param {Object} options opentype options (optional), set options.decimals - * to set the decimal precision of the path-data - * - * @return {Object} this p5.Font object - */ -p5.Font.prototype._getPathData = function(line, x, y, options) { - - var decimals = 3; - - // create path from string/position - if (typeof line === 'string' && arguments.length > 2) { - - line = this._getPath(line, x, y, options); - } - // handle options specified in 2nd arg - else if (typeof x === 'object') { - - options = x; - } - - // handle svg arguments - if (options && typeof options.decimals === 'number') { - - decimals = options.decimals; - } - - return line.toPathData(decimals); -}; - -/* - * Creates an SVG <path> element, as a string, - * from the given opentype path or string/position - * - * @param {Object} path an opentype path, OR the following: - * - * @param {String} line a line of text - * @param {Number} x x-position - * @param {Number} y y-position - * @param {Object} options opentype options (optional), set options.decimals - * to set the decimal precision of the path-data in the <path> element, - * options.fill to set the fill color for the <path> element, - * options.stroke to set the stroke color for the <path> element, - * options.strokeWidth to set the strokeWidth for the <path> element. - * - * @return {Object} this p5.Font object - */ -p5.Font.prototype._getSVG = function(line, x, y, options) { - - var decimals = 3; - - // create path from string/position - if (typeof line === 'string' && arguments.length > 2) { - - line = this._getPath(line, x, y, options); - } - // handle options specified in 2nd arg - else if (typeof x === 'object') { - - options = x; - } - - // handle svg arguments - if (options) { - if (typeof options.decimals === 'number') { - decimals = options.decimals; - } - if (typeof options.strokeWidth === 'number') { - line.strokeWidth = options.strokeWidth; - } - if (typeof options.fill !== 'undefined') { - line.fill = options.fill; - } - if (typeof options.stroke !== 'undefined') { - line.stroke = options.stroke; - } - } - - return line.toSVG(decimals); -}; - -/* - * Renders an opentype path or string/position - * to the current graphics context - * - * @param {Object} path an opentype path, OR the following: - * - * @param {String} line a line of text - * @param {Number} x x-position - * @param {Number} y y-position - * @param {Object} options opentype options (optional) - * - * @return {Object} this p5.Font object - */ -p5.Font.prototype._renderPath = function(line, x, y, options) { - - var pdata, pg = (options && options.renderer) || this.parent._renderer, - ctx = pg.drawingContext; - - if (typeof line === 'object' && line.commands) { - - pdata = line.commands; - } else { - - //pos = handleAlignment(p, ctx, line, x, y); - pdata = this._getPath(line, x, y, pg._textSize, options).commands; - } - - ctx.beginPath(); - for (var i = 0; i < pdata.length; i += 1) { - - var cmd = pdata[i]; - if (cmd.type === 'M') { - ctx.moveTo(cmd.x, cmd.y); - } else if (cmd.type === 'L') { - ctx.lineTo(cmd.x, cmd.y); - } else if (cmd.type === 'C') { - ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); - } else if (cmd.type === 'Q') { - ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y); - } else if (cmd.type === 'Z') { - ctx.closePath(); - } - } - - // only draw stroke if manually set by user - if (pg._doStroke && pg._strokeSet) { - - ctx.stroke(); - } - - if (pg._doFill) { - - // if fill hasn't been set by user, use default-text-fill - ctx.fillStyle = pg._fillSet ? ctx.fillStyle : constants._DEFAULT_TEXT_FILL; - ctx.fill(); - } - - return this; -}; - -p5.Font.prototype._textWidth = function(str, fontSize) { - - if (str === ' ') { // special case for now - - return this.font.charToGlyph(' ').advanceWidth * this._scale(fontSize); - } - - var bounds = this.textBounds(str, 0, 0, fontSize); - return bounds.w + bounds.advance; -}; - -p5.Font.prototype._textAscent = function(fontSize) { - - return this.font.ascender * this._scale(fontSize); -}; - -p5.Font.prototype._textDescent = function(fontSize) { - - return -this.font.descender * this._scale(fontSize); -}; - -p5.Font.prototype._scale = function(fontSize) { - - return (1 / this.font.unitsPerEm) * (fontSize || - this.parent._renderer._textSize); -}; - -p5.Font.prototype._handleAlignment = function(p, ctx, line, x, y) { - - var textWidth = this._textWidth(line), - textAscent = this._textAscent(), - textDescent = this._textDescent(), - textHeight = textAscent + textDescent; - - if (ctx.textAlign === constants.CENTER) { - x -= textWidth / 2; - } else if (ctx.textAlign === constants.RIGHT) { - x -= textWidth; - } - - if (ctx.textBaseline === constants.TOP) { - y += textHeight; - } else if (ctx.textBaseline === constants._CTX_MIDDLE) { - y += textHeight / 2 - textDescent; - } else if (ctx.textBaseline === constants.BOTTOM) { - y -= textDescent; - } - - return { x: x, y: y }; -}; - -// path-utils - -function pathToPoints(cmds, options) { - - var opts = parseOpts(options, { - sampleFactor: 0.1, - simplifyThreshold: 0, - }); - - var len = pointAtLength(cmds,0,1), // total-length - t = len / (len * opts.sampleFactor), - pts = []; - - for (var i = 0; i < len; i += t) { - pts.push(pointAtLength(cmds, i)); - } - - if (opts.simplifyThreshold) { - /*var count = */simplify(pts, opts.simplifyThreshold); - //console.log('Simplify: removed ' + count + ' pts'); - } - - return pts; -} - -function simplify(pts, angle) { - - angle = (typeof angle === 'undefined') ? 0 : angle; - - var num = 0; - for (var i = pts.length - 1; pts.length > 3 && i >= 0; --i) { - - if (collinear(at(pts, i - 1), at(pts, i), at(pts, i + 1), angle)) { - - // Remove the middle point - pts.splice(i % pts.length, 1); - num++; - } - } - return num; -} - -function splitPaths(cmds) { - - var paths = [], current; - for (var i = 0; i < cmds.length; i++) { - if (cmds[i].type === 'M') { - if (current) { - paths.push(current); - } - current = []; - } - current.push(cmdToArr(cmds[i])); - } - paths.push(current); - - return paths; -} - -function cmdToArr(cmd) { - - var arr = [ cmd.type ]; - if (cmd.type === 'M' || cmd.type === 'L') { // moveto or lineto - arr.push(cmd.x, cmd.y); - } else if (cmd.type === 'C') { - arr.push(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); - } else if (cmd.type === 'Q') { - arr.push(cmd.x1, cmd.y1, cmd.x, cmd.y); - } - // else if (cmd.type === 'Z') { /* no-op */ } - return arr; -} - -function parseOpts(options, defaults) { - - if (typeof options !== 'object') { - options = defaults; - } - else { - for (var key in defaults) { - if (typeof options[key] === 'undefined') { - options[key] = defaults[key]; - } - } - } - return options; -} - -//////////////////////// Helpers //////////////////////////// - -function at(v, i) { - var s = v.length; - return v[i < 0 ? i % s + s : i % s]; -} - -function collinear(a, b, c, thresholdAngle) { - - if (!thresholdAngle) { - return areaTriangle(a, b, c) === 0; - } - - if (typeof collinear.tmpPoint1 === 'undefined') { - collinear.tmpPoint1 = []; - collinear.tmpPoint2 = []; - } - - var ab = collinear.tmpPoint1, bc = collinear.tmpPoint2; - ab.x = b.x - a.x; - ab.y = b.y - a.y; - bc.x = c.x - b.x; - bc.y = c.y - b.y; - - var dot = ab.x * bc.x + ab.y * bc.y, - magA = Math.sqrt(ab.x * ab.x + ab.y * ab.y), - magB = Math.sqrt(bc.x * bc.x + bc.y * bc.y), - angle = Math.acos(dot / (magA * magB)); - - return angle < thresholdAngle; -} - -function areaTriangle(a, b, c) { - return (((b[0] - a[0]) * (c[1] - a[1])) - ((c[0] - a[0]) * (b[1] - a[1]))); -} - -// Portions of below code copyright 2008 Dmitry Baranovskiy (via MIT license) - -function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { - - var t1 = 1 - t, t13 = Math.pow(t1, 3), t12 = Math.pow(t1, 2), t2 = t * t, - t3 = t2 * t, x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + - t3 * p2x, y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + - t3 * p2y, mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), - my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), - nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), - ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), - ax = t1 * p1x + t * c1x, ay = t1 * p1y + t * c1y, - cx = t1 * c2x + t * p2x, cy = t1 * c2y + t * p2y, - alpha = (90 - Math.atan2(mx - nx, my - ny) * 180 / Math.PI); - - if (mx > nx || my < ny) { alpha += 180; } - - return { x: x, y: y, m: { x: mx, y: my }, n: { x: nx, y: ny }, - start: { x: ax, y: ay }, end: { x: cx, y: cy }, alpha: alpha - }; -} - -function getPointAtSegmentLength(p1x,p1y,c1x,c1y,c2x,c2y,p2x,p2y,length) { - return (length == null) ? bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) : - findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, - getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); -} - -function pointAtLength(path, length, istotal) { - path = path2curve(path); - var x, y, p, l, sp = '', subpaths = {}, point, len = 0; - for (var i = 0, ii = path.length; i < ii; i++) { - p = path[i]; - if (p[0] === 'M') { - x = +p[1]; - y = +p[2]; - } else { - l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); - if (len + l > length) { - if (!istotal) { - point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], - p[6], length - len); - return { x: point.x, y: point.y, alpha: point.alpha }; - } - } - len += l; - x = +p[5]; - y = +p[6]; - } - sp += p.shift() + p; - } - subpaths.end = sp; - - point = istotal ? len : findDotsAtSegment - (x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); - - if (point.alpha) { - point = { x: point.x, y: point.y, alpha: point.alpha }; - } - - return point; -} - -function pathToAbsolute(pathArray) { - - var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0; - if (pathArray[0][0] === 'M') { - x = +pathArray[0][1]; - y = +pathArray[0][2]; - mx = x; - my = y; - start++; - res[0] = ['M', x, y]; - } - - var dots,crz = pathArray.length===3 && pathArray[0][0]==='M' && - pathArray[1][0].toUpperCase()==='R' && pathArray[2][0].toUpperCase()==='Z'; - - for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { - res.push(r = []); - pa = pathArray[i]; - if (pa[0] !== String.prototype.toUpperCase.call(pa[0])) { - r[0] = String.prototype.toUpperCase.call(pa[0]); - switch (r[0]) { - case 'A': - r[1] = pa[1]; - r[2] = pa[2]; - r[3] = pa[3]; - r[4] = pa[4]; - r[5] = pa[5]; - r[6] = +(pa[6] + x); - r[7] = +(pa[7] + y); - break; - case 'V': - r[1] = +pa[1] + y; - break; - case 'H': - r[1] = +pa[1] + x; - break; - case 'R': - dots = [x, y].concat(pa.slice(1)); - for (var j = 2, jj = dots.length; j < jj; j++) { - dots[j] = +dots[j] + x; - dots[++j] = +dots[j] + y; - } - res.pop(); - res = res.concat(catmullRom2bezier(dots, crz)); - break; - case 'M': - mx = +pa[1] + x; - my = +pa[2] + y; - break; - default: - for (j = 1, jj = pa.length; j < jj; j++) { - r[j] = +pa[j] + ((j % 2) ? x : y); - } - } - } else if (pa[0] === 'R') { - dots = [x, y].concat(pa.slice(1)); - res.pop(); - res = res.concat(catmullRom2bezier(dots, crz)); - r = ['R'].concat(pa.slice(-2)); - } else { - for (var k = 0, kk = pa.length; k < kk; k++) { - r[k] = pa[k]; - } - } - switch (r[0]) { - case 'Z': - x = mx; - y = my; - break; - case 'H': - x = r[1]; - break; - case 'V': - y = r[1]; - break; - case 'M': - mx = r[r.length - 2]; - my = r[r.length - 1]; - break; - default: - x = r[r.length - 2]; - y = r[r.length - 1]; - } - } - return res; -} - -function path2curve(path, path2) { - - var p = pathToAbsolute(path), p2 = path2 && pathToAbsolute(path2), - attrs = { x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null }, - attrs2 = { x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null }, - - processPath = function(path, d, pcom) { - var nx, ny, tq = { T: 1, Q: 1 }; - if (!path) { return ['C', d.x, d.y, d.x, d.y, d.x, d.y]; } - if (!(path[0] in tq)) { d.qx = d.qy = null; } - switch (path[0]) { - case 'M': - d.X = path[1]; - d.Y = path[2]; - break; - case 'A': - path = ['C'].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); - break; - case 'S': - if (pcom === 'C' || pcom === 'S') { - nx = d.x * 2 - d.bx; - ny = d.y * 2 - d.by; - } else { - nx = d.x; - ny = d.y; - } - path = ['C', nx, ny].concat(path.slice(1)); - break; - case 'T': - if (pcom === 'Q' || pcom === 'T') { - d.qx = d.x * 2 - d.qx; - d.qy = d.y * 2 - d.qy; - } else { - d.qx = d.x; - d.qy = d.y; - } - path = ['C'].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); - break; - case 'Q': - d.qx = path[1]; - d.qy = path[2]; - path = ['C'].concat(q2c(d.x,d.y,path[1],path[2],path[3],path[4])); - break; - case 'L': - path = ['C'].concat(l2c(d.x, d.y, path[1], path[2])); - break; - case 'H': - path = ['C'].concat(l2c(d.x, d.y, path[1], d.y)); - break; - case 'V': - path = ['C'].concat(l2c(d.x, d.y, d.x, path[1])); - break; - case 'Z': - path = ['C'].concat(l2c(d.x, d.y, d.X, d.Y)); - break; - } - return path; - }, - - fixArc = function(pp, i) { - if (pp[i].length > 7) { - pp[i].shift(); - var pi = pp[i]; - while (pi.length) { - pcoms1[i] = 'A'; - if (p2) { pcoms2[i] = 'A'; } - pp.splice(i++, 0, ['C'].concat(pi.splice(0, 6))); - } - pp.splice(i, 1); - ii = Math.max(p.length, p2 && p2.length || 0); - } - }, - - fixM = function(path1, path2, a1, a2, i) { - if (path1 && path2 && path1[i][0] === 'M' && path2[i][0] !== 'M') { - path2.splice(i, 0, ['M', a2.x, a2.y]); - a1.bx = 0; - a1.by = 0; - a1.x = path1[i][1]; - a1.y = path1[i][2]; - ii = Math.max(p.length, p2 && p2.length || 0); - } - }, - - pcoms1 = [], // path commands of original path p - pcoms2 = [], // path commands of original path p2 - pfirst = '', // temporary holder for original path command - pcom = ''; // holder for previous path command of original path - - for (var i = 0, ii = Math.max(p.length, p2 && p2.length || 0); i < ii; i++) { - if (p[i]) { pfirst = p[i][0]; } // save current path command - - if (pfirst !== 'C') { - pcoms1[i] = pfirst; // Save current path command - if (i) { pcom = pcoms1[i - 1]; } // Get previous path command pcom - } - p[i] = processPath(p[i], attrs, pcom); - - if (pcoms1[i] !== 'A' && pfirst === 'C') { pcoms1[i] = 'C'; } - - fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 - - if (p2) { // the same procedures is done to p2 - if (p2[i]) { pfirst = p2[i][0]; } - if (pfirst !== 'C') { - pcoms2[i] = pfirst; - if (i) { pcom = pcoms2[i - 1]; } - } - p2[i] = processPath(p2[i], attrs2, pcom); - - if (pcoms2[i] !== 'A' && pfirst === 'C') { pcoms2[i] = 'C'; } - - fixArc(p2, i); - } - fixM(p, p2, attrs, attrs2, i); - fixM(p2, p, attrs2, attrs, i); - var seg = p[i], seg2 = p2 && p2[i], seglen = seg.length, - seg2len = p2 && seg2.length; - attrs.x = seg[seglen - 2]; - attrs.y = seg[seglen - 1]; - attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x; - attrs.by = parseFloat(seg[seglen - 3]) || attrs.y; - attrs2.bx = p2 && (parseFloat(seg2[seg2len - 4]) || attrs2.x); - attrs2.by = p2 && (parseFloat(seg2[seg2len - 3]) || attrs2.y); - attrs2.x = p2 && seg2[seg2len - 2]; - attrs2.y = p2 && seg2[seg2len - 1]; - } - - return p2 ? [p, p2] : p; -} - -function a2c(x1, y1, rx, ry, angle, lac, sweep_flag, x2, y2, recursive) { - // for more information of where this Math came from visit: - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - var PI = Math.PI, _120 = PI * 120 / 180, f1, f2, cx, cy, - rad = PI / 180 * (+angle || 0), res = [], xy, - rotate = function (x, y, rad) { - var X = x * Math.cos(rad) - y * Math.sin(rad), - Y = x * Math.sin(rad) + y * Math.cos(rad); - return { x: X, y: Y }; - }; - if (!recursive) { - xy = rotate(x1, y1, -rad); - x1 = xy.x; - y1 = xy.y; - xy = rotate(x2, y2, -rad); - x2 = xy.x; - y2 = xy.y; - var x = (x1 - x2) / 2, y = (y1 - y2) / 2, - h = (x * x) / (rx * rx) + (y * y) / (ry * ry); - if (h > 1) { - h = Math.sqrt(h); - rx = h * rx; - ry = h * ry; - } - var rx2 = rx * rx, ry2 = ry * ry, - k = (lac === sweep_flag ? -1 : 1) * Math.sqrt(Math.abs - ((rx2 * ry2 - rx2 * y * y - ry2 * x * x)/(rx2 * y * y + ry2 * x * x))); - - cx = k * rx * y / ry + (x1 + x2) / 2; - cy = k * -ry * x / rx + (y1 + y2) / 2; - f1 = Math.asin(((y1 - cy) / ry).toFixed(9)); - f2 = Math.asin(((y2 - cy) / ry).toFixed(9)); - - f1 = x1 < cx ? PI - f1 : f1; - f2 = x2 < cx ? PI - f2 : f2; - - if (f1 < 0) { f1 = PI * 2 + f1; } - if (f2 < 0) { f2 = PI * 2 + f2; } - - if (sweep_flag && f1 > f2) { - f1 = f1 - PI * 2; - } - if (!sweep_flag && f2 > f1) { - f2 = f2 - PI * 2; - } - } else { - f1 = recursive[0]; - f2 = recursive[1]; - cx = recursive[2]; - cy = recursive[3]; - } - var df = f2 - f1; - if (Math.abs(df) > _120) { - var f2old = f2, x2old = x2, y2old = y2; - f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); - x2 = cx + rx * Math.cos(f2); - y2 = cy + ry * Math.sin(f2); - res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, - [f2, f2old, cx, cy]); - } - df = f2 - f1; - var c1 = Math.cos(f1), - s1 = Math.sin(f1), - c2 = Math.cos(f2), - s2 = Math.sin(f2), - t = Math.tan(df / 4), - hx = 4 / 3 * rx * t, - hy = 4 / 3 * ry * t, - m1 = [x1, y1], - m2 = [x1 + hx * s1, y1 - hy * c1], - m3 = [x2 + hx * s2, y2 - hy * c2], - m4 = [x2, y2]; - m2[0] = 2 * m1[0] - m2[0]; - m2[1] = 2 * m1[1] - m2[1]; - if (recursive) { - return [m2, m3, m4].concat(res); - } else { - res = [m2, m3, m4].concat(res).join().split(','); - var newres = []; - for (var i = 0, ii = res.length; i < ii; i++) { - newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], - res[i + 1], rad).x; - } - return newres; - } -} - -// http://schepers.cc/getting-to-the-point -function catmullRom2bezier(crp, z) { - var d = []; - for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { - var p = [{ - x: +crp[i - 2], - y: +crp[i - 1] - }, { - x: +crp[i], - y: +crp[i + 1] - }, { - x: +crp[i + 2], - y: +crp[i + 3] - }, { - x: +crp[i + 4], - y: +crp[i + 5] - }]; - if (z) { - if (!i) { - p[0] = { - x: +crp[iLen - 2], - y: +crp[iLen - 1] - }; - } else if (iLen - 4 === i) { - p[3] = { - x: +crp[0], - y: +crp[1] - }; - } else if (iLen - 2 === i) { - p[2] = { - x: +crp[0], - y: +crp[1] - }; - p[3] = { - x: +crp[2], - y: +crp[3] - }; - } - } else { - if (iLen - 4 === i) { - p[3] = p[2]; - } else if (!i) { - p[0] = { - x: +crp[i], - y: +crp[i + 1] - }; - } - } - d.push(['C', (-p[0].x + 6 * p[1].x + p[2].x) / 6, (-p[0].y + 6 * p[1].y + - p[2].y) / 6, (p[1].x + 6 * p[2].x - p[3].x) / 6, (p[1].y + 6 * p[2].y - - p[3].y) / 6, p[2].x, p[2].y ]); - } - - return d; -} - -function l2c(x1, y1, x2, y2) { return [x1, y1, x2, y2, x2, y2]; } - -function q2c(x1, y1, ax, ay, x2, y2) { - var _13 = 1 / 3, _23 = 2 / 3; - return [ - _13 * x1 + _23 * ax, _13 * y1 + _23 * ay, - _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2 - ]; -} - -function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { - if (z == null) { z = 1; } - z = z > 1 ? 1 : z < 0 ? 0 : z; - var z2 = z / 2, - n = 12, Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, - -0.7699, 0.7699, -0.9041, 0.9041, -0.9816, 0.9816], - sum = 0, Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, - 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472 ]; - for (var i = 0; i < n; i++) { - var ct = z2 * Tvalues[i] + z2, - xbase = base3(ct, x1, x2, x3, x4), - ybase = base3(ct, y1, y2, y3, y4), - comb = xbase * xbase + ybase * ybase; - sum += Cvalues[i] * Math.sqrt(comb); - } - return z2 * sum; -} - -function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { - if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { - return; - } - var t = 1, step = t / 2, t2 = t - step, l, e = 0.01; - l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); - while (Math.abs(l - ll) > e) { - step /= 2; - t2 += (l < ll ? 1 : -1) * step; - l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); - } - return t2; -} - -function base3(t, p1, p2, p3, p4) { - var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, - t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; - return t * t2 - 3 * p1 + 3 * p2; -} - -function cacheKey() { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) { - args[i] = arguments[i]; - } - i = args.length; - var hash = ''; - while (i--) { - hash += (args[i] === Object(args[i])) ? - JSON.stringify(args[i]) : args[i]; - } - return hash; -} - -module.exports = p5.Font; - -},{"../core/constants":47,"../core/core":48}],83:[function(_dereq_,module,exports){ -/** - * @module Data - * @submodule Array Functions - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Adds a value to the end of an array. Extends the length of - * the array by one. Maps to Array.push(). - * - * @method append - * @param {Array} array Array to append - * @param {any} value to be added to the Array - * @example - * <div class = "norender"><code> - * function setup() { - * - * var myArray = new Array("Mango", "Apple", "Papaya") - * print(myArray) // ["Mango", "Apple", "Papaya"] - * - * append(myArray, "Peach") - * print(myArray) // ["Mango", "Apple", "Papaya", "Peach"] - * - * } - * </div></code> - */ -p5.prototype.append = function(array, value) { - array.push(value); - return array; -}; - -/** - * Copies an array (or part of an array) to another array. The src array is - * copied to the dst array, beginning at the position specified by - * srcPosition and into the position specified by dstPosition. The number of - * elements to copy is determined by length. Note that copying values - * overwrites existing values in the destination array. To append values - * instead of overwriting them, use concat(). - * <br><br> - * The simplified version with only two arguments, arrayCopy(src, dst), - * copies an entire array to another of the same size. It is equivalent to - * arrayCopy(src, 0, dst, 0, src.length). - * <br><br> - * Using this function is far more efficient for copying array data than - * iterating through a for() loop and copying each element individually. - * - * @method arrayCopy - * @param {Array} src the source Array - * @param {Number} [srcPosition] starting position in the source Array - * @param {Array} dst the destination Array - * @param {Number} [dstPosition] starting position in the destination Array - * @param {Number} [length] number of Array elements to be copied - * - * @example - * <div class="norender"><code> - * function setup() { - * - * var src = new Array("A", "B", "C"); - * var dst = new Array( 1 , 2 , 3 ); - * var srcPosition = 1; - * var dstPosition = 0; - * var length = 2; - * - * print(src); // ["A", "B", "C"] - * print(dst); // [ 1 , 2 , 3 ] - * - * arrayCopy(src, srcPosition, dst, dstPosition, length); - * print(dst); // ["B", "C", 3] - * - * } - * </div></code> - */ -p5.prototype.arrayCopy = function( - src, - srcPosition, - dst, - dstPosition, - length) { - - // the index to begin splicing from dst array - var start, - end; - - if (typeof length !== 'undefined') { - - end = Math.min(length, src.length); - start = dstPosition; - src = src.slice(srcPosition, end + srcPosition); - - } else { - - if (typeof dst !== 'undefined') { // src, dst, length - // rename so we don't get confused - end = dst; - end = Math.min(end, src.length); - } else { // src, dst - end = src.length; - } - - start = 0; - // rename so we don't get confused - dst = srcPosition; - src = src.slice(0, end); - } - - // Since we are not returning the array and JavaScript is pass by reference - // we must modify the actual values of the array - // instead of reassigning arrays - Array.prototype.splice.apply(dst, [start, end].concat(src)); - -}; - -/** - * Concatenates two arrays, maps to Array.concat(). Does not modify the - * input arrays. - * - * @method concat - * @param {Array} a first Array to concatenate - * @param {Array} b second Array to concatenate - * @return {Array} concatenated array - * - * @example - * <div class = "norender"><code> - * function setup() { - * var arr1 = new Array("A", "B", "C"); - * var arr2 = new Array( 1 , 2 , 3 ); - * - * print(arr1); // ["A","B","C"] - * print(arr2); // [1,2,3] - * - * var arr3 = concat(arr1, arr2); - * - * print(arr1); // ["A","B","C"] - * print(arr2); // [1,2,3] - * print(arr3); // ["A","B","C",1,2,3] - * - * } - * </div></code> - */ -p5.prototype.concat = function(list0, list1) { - return list0.concat(list1); -}; - -/** - * Reverses the order of an array, maps to Array.reverse() - * - * @method reverse - * @param {Array} list Array to reverse - * @example - * <div class="norender"><code> - * function setup() { - * var myArray = new Array("A", "B", "C"); - * print(myArray); // ["A","B","C"] - * - * reverse(myArray); - * print(myArray); // ["C","B","A"] - * } - * </div></code> - */ -p5.prototype.reverse = function(list) { - return list.reverse(); -}; - -/** - * Decreases an array by one element and returns the shortened array, - * maps to Array.pop(). - * - * @method shorten - * @param {Array} list Array to shorten - * @return {Array} shortened Array - * @example - * <div class = "norender"><code> - * function setup() { - * var myArray = new Array("A", "B", "C"); - * print(myArray); // ["A","B","C"] - * - * var newArray = shorten(myArray); - * print(myArray); // ["A","B","C"] - * print(newArray); // ["A","B"] - * } - * </div></code> - */ -p5.prototype.shorten = function(list) { - list.pop(); - return list; -}; - -/** - * Randomizes the order of the elements of an array. Implements - * <a href="http://Bost.Ocks.org/mike/shuffle/" target=_blank> - * Fisher-Yates Shuffle Algorithm</a>. - * - * @method shuffle - * @param {Array} array Array to shuffle - * @param {Boolean} [bool] modify passed array - * @return {Array} shuffled Array - * @example - * <div><code> - * function setup() { - * var regularArr = ['ABC', 'def', createVector(), TAU, Math.E]; - * print(regularArr); - * shuffle(regularArr, true); // force modifications to passed array - * print(regularArr); - * - * // By default shuffle() returns a shuffled cloned array: - * var newArr = shuffle(regularArr); - * print(regularArr); - * print(newArr); - * } - * </code></div> - */ -p5.prototype.shuffle = function(arr, bool) { - var isView = ArrayBuffer && ArrayBuffer.isView && ArrayBuffer.isView(arr); - arr = bool || isView ? arr : arr.slice(); - - var rnd, tmp, idx = arr.length; - while (idx > 1) { - rnd = Math.random()*idx | 0; - - tmp = arr[--idx]; - arr[idx] = arr[rnd]; - arr[rnd] = tmp; - } - - return arr; -}; - -/** - * Sorts an array of numbers from smallest to largest, or puts an array of - * words in alphabetical order. The original array is not modified; a - * re-ordered array is returned. The count parameter states the number of - * elements to sort. For example, if there are 12 elements in an array and - * count is set to 5, only the first 5 elements in the array will be sorted. - * - * @method sort - * @param {Array} list Array to sort - * @param {Number} [count] number of elements to sort, starting from 0 - * - * @example - * <div class = "norender"><code> - * function setup() { - * var words = new Array("banana", "apple", "pear","lime"); - * print(words); // ["banana", "apple", "pear", "lime"] - * var count = 4; // length of array - * - * sort(words, count); - * print(words); // ["apple", "banana", "lime", "pear"] - * } - * </div></code> - * <div class = "norender"><code> - * function setup() { - * var numbers = new Array(2,6,1,5,14,9,8,12); - * print(numbers); // [2,6,1,5,14,9,8,12] - * var count = 5; // Less than the length of the array - * - * sort(numbers, count); - * print(numbers); // [1,2,5,6,14,9,8,12] - * } - * </div></code> - */ -p5.prototype.sort = function(list, count) { - var arr = count ? list.slice(0, Math.min(count, list.length)) : list; - var rest = count ? list.slice(Math.min(count, list.length)) : []; - if (typeof arr[0] === 'string') { - arr = arr.sort(); - } else { - arr = arr.sort(function(a,b){return a-b;}); - } - return arr.concat(rest); -}; - -/** - * Inserts a value or an array of values into an existing array. The first - * parameter specifies the initial array to be modified, and the second - * parameter defines the data to be inserted. The third parameter is an index - * value which specifies the array position from which to insert data. - * (Remember that array index numbering starts at zero, so the first position - * is 0, the second position is 1, and so on.) - * - * @method splice - * @param {Array} list Array to splice into - * @param {any} value value to be spliced in - * @param {Number} position in the array from which to insert data - * - * @example - * <div class = "norender"><code> - * function setup() { - * var myArray = new Array(0,1,2,3,4); - * var insArray = new Array("A","B","C"); - * print(myArray); // [0,1,2,3,4] - * print(insArray); // ["A","B","C"] - * - * splice(myArray, insArray, 3); - * print(myArray); // [0,1,2,"A","B","C",3,4] - * } - * </div></code> - */ -p5.prototype.splice = function(list, value, index) { - - // note that splice returns spliced elements and not an array - Array.prototype.splice.apply(list, [index, 0].concat(value)); - - return list; -}; - -/** - * Extracts an array of elements from an existing array. The list parameter - * defines the array from which the elements will be copied, and the start - * and count parameters specify which elements to extract. If no count is - * given, elements will be extracted from the start to the end of the array. - * When specifying the start, remember that the first array element is 0. - * This function does not change the source array. - * - * @method subset - * @param {Array} list Array to extract from - * @param {Number} start position to begin - * @param {Number} [count] number of values to extract - * @return {Array} Array of extracted elements - * - * @example - * <div class = "norender"><code> - * function setup() { - * var myArray = new Array(1,2,3,4,5); - * print(myArray); // [1,2,3,4,5] - * - * var sub1 = subset(myArray, 0, 3); - * var sub2 = subset(myArray, 2, 2); - * print(sub1); // [1,2,3] - * print(sub2); // [3,4] - * } - * </div></code> - */ -p5.prototype.subset = function(list, start, count) { - if (typeof count !== 'undefined') { - return list.slice(start, start + count); - } else { - return list.slice(start, list.length); - } -}; - -module.exports = p5; - -},{"../core/core":48}],84:[function(_dereq_,module,exports){ -/** - * @module Data - * @submodule Conversion - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * Converts a string to its floating point representation. The contents of a - * string must resemble a number, or NaN (not a number) will be returned. - * For example, float("1234.56") evaluates to 1234.56, but float("giraffe") - * will return NaN. - * - * @method float - * @param {String} str float string to parse - * @return {Number} floating point representation of string - * @example - * <div><code> - * var str = '20'; - * var diameter = float(str); - * ellipse(width/2, height/2, diameter, diameter); - * </code></div> - */ -p5.prototype.float = function(str) { - return parseFloat(str); -}; - -/** - * Converts a boolean, string, or float to its integer representation. - * When an array of values is passed in, then an int array of the same length - * is returned. - * - * @method int - * @param {String|Boolean|Number|Array} n value to parse - * @return {Number} integer representation of value - * @example - * <div class='norender'><code> - * print(int("10")); // 10 - * print(int(10.31)); // 10 - * print(int(-10)); // -10 - * print(int(true)); // 1 - * print(int(false)); // 0 - * print(int([false, true, "10.3", 9.8])); // [0, 1, 10, 9] - * </code></div> - */ -p5.prototype.int = function(n, radix) { - if (typeof n === 'string') { - radix = radix || 10; - return parseInt(n, radix); - } else if (typeof n === 'number') { - return n | 0; - } else if (typeof n === 'boolean') { - return n ? 1 : 0; - } else if (n instanceof Array) { - return n.map(function(n) { return p5.prototype.int(n, radix); }); - } -}; - -/** - * Converts a boolean, string or number to its string representation. - * When an array of values is passed in, then an array of strings of the same - * length is returned. - * - * @method str - * @param {String|Boolean|Number|Array} n value to parse - * @return {String} string representation of value - * @example - * <div class='norender'><code> - * print(str("10")); // "10" - * print(str(10.31)); // "10.31" - * print(str(-10)); // "-10" - * print(str(true)); // "true" - * print(str(false)); // "false" - * print(str([true, "10.3", 9.8])); // [ "true", "10.3", "9.8" ] - * </code></div> - */ -p5.prototype.str = function(n) { - if (n instanceof Array) { - return n.map(p5.prototype.str); - } else { - return String(n); - } -}; - -/** - * Converts a number or string to its boolean representation. - * For a number, any non-zero value (positive or negative) evaluates to true, - * while zero evaluates to false. For a string, the value "true" evaluates to - * true, while any other value evaluates to false. When an array of number or - * string values is passed in, then a array of booleans of the same length is - * returned. - * - * @method boolean - * @param {String|Boolean|Number|Array} n value to parse - * @return {Boolean} boolean representation of value - * @example - * <div class='norender'><code> - * print(boolean(0)); // false - * print(boolean(1)); // true - * print(boolean("true")); // true - * print(boolean("abcd")); // false - * print(boolean([0, 12, "true"])); // [false, true, false] - * </code></div> - */ -p5.prototype.boolean = function(n) { - if (typeof n === 'number') { - return n !== 0; - } else if (typeof n === 'string') { - return n.toLowerCase() === 'true'; - } else if (typeof n === 'boolean') { - return n; - } else if (n instanceof Array) { - return n.map(p5.prototype.boolean); - } -}; - -/** - * Converts a number, string or boolean to its byte representation. - * A byte can be only a whole number between -128 and 127, so when a value - * outside of this range is converted, it wraps around to the corresponding - * byte representation. When an array of number, string or boolean values is - * passed in, then an array of bytes the same length is returned. - * - * @method byte - * @param {String|Boolean|Number|Array} n value to parse - * @return {Number} byte representation of value - * @example - * <div class='norender'><code> - * print(byte(127)); // 127 - * print(byte(128)); // -128 - * print(byte(23.4)); // 23 - * print(byte("23.4")); // 23 - * print(byte(true)); // 1 - * print(byte([0, 255, "100"])); // [0, -1, 100] - * </code></div> - */ -p5.prototype.byte = function(n) { - var nn = p5.prototype.int(n, 10); - if (typeof nn === 'number') { - return ((nn + 128) % 256) - 128; - } else if (nn instanceof Array) { - return nn.map(p5.prototype.byte); - } -}; - -/** - * Converts a number or string to its corresponding single-character - * string representation. If a string parameter is provided, it is first - * parsed as an integer and then translated into a single-character string. - * When an array of number or string values is passed in, then an array of - * single-character strings of the same length is returned. - * - * @method char - * @param {String|Number|Array} n value to parse - * @return {String} string representation of value - * @example - * <div class='norender'><code> - * print(char(65)); // "A" - * print(char("65")); // "A" - * print(char([65, 66, 67])); // [ "A", "B", "C" ] - * print(join(char([65, 66, 67]), '')); // "ABC" - * </code></div> - */ -p5.prototype.char = function(n) { - if (typeof n === 'number' && !isNaN(n)) { - return String.fromCharCode(n); - } else if (n instanceof Array) { - return n.map(p5.prototype.char); - } else if (typeof n === 'string') { - return p5.prototype.char(parseInt(n, 10)); - } -}; - -/** - * Converts a single-character string to its corresponding integer - * representation. When an array of single-character string values is passed - * in, then an array of integers of the same length is returned. - * - * @method unchar - * @param {String|Array} n value to parse - * @return {Number} integer representation of value - * @example - * <div class='norender'><code> - * print(unchar("A")); // 65 - * print(unchar(["A", "B", "C"])); // [ 65, 66, 67 ] - * print(unchar(split("ABC", ""))); // [ 65, 66, 67 ] - * </code></div> - */ -p5.prototype.unchar = function(n) { - if (typeof n === 'string' && n.length === 1) { - return n.charCodeAt(0); - } else if (n instanceof Array) { - return n.map(p5.prototype.unchar); - } -}; - -/** - * Converts a number to a string in its equivalent hexadecimal notation. If a - * second parameter is passed, it is used to set the number of characters to - * generate in the hexadecimal notation. When an array is passed in, an - * array of strings in hexadecimal notation of the same length is returned. - * - * @method hex - * @param {Number|Array} n value to parse - * @return {String} hexadecimal string representation of value - * @example - * <div class='norender'><code> - * print(hex(255)); // "000000FF" - * print(hex(255, 6)); // "0000FF" - * print(hex([0, 127, 255], 6)); // [ "000000", "00007F", "0000FF" ] - * </code></div> - */ -p5.prototype.hex = function(n, digits) { - digits = (digits === undefined || digits === null) ? digits = 8 : digits; - if (n instanceof Array) { - return n.map(function(n) { return p5.prototype.hex(n, digits); }); - } else if (typeof n === 'number') { - if (n < 0) { - n = 0xFFFFFFFF + n + 1; - } - var hex = Number(n).toString(16).toUpperCase(); - while (hex.length < digits) { - hex = '0' + hex; - } - if (hex.length >= digits) { - hex = hex.substring(hex.length - digits, hex.length); - } - return hex; - } -}; - -/** - * Converts a string representation of a hexadecimal number to its equivalent - * integer value. When an array of strings in hexadecimal notation is passed - * in, an array of integers of the same length is returned. - * - * @method unhex - * @param {String|Array} n value to parse - * @return {Number} integer representation of hexadecimal value - * @example - * <div class='norender'><code> - * print(unhex("A")); // 10 - * print(unhex("FF")); // 255 - * print(unhex(["FF", "AA", "00"])); // [ 255, 170, 0 ] - * </code></div> - */ -p5.prototype.unhex = function(n) { - if (n instanceof Array) { - return n.map(p5.prototype.unhex); - } else { - return parseInt('0x' + n, 16); - } -}; - -module.exports = p5; - -},{"../core/core":48}],85:[function(_dereq_,module,exports){ -/** - * @module Data - * @submodule String Functions - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -//return p5; //LM is this a mistake? - -/** - * Combines an array of Strings into one String, each separated by the - * character(s) used for the separator parameter. To join arrays of ints or - * floats, it's necessary to first convert them to Strings using nf() or - * nfs(). - * - * @method join - * @param {Array} list array of Strings to be joined - * @param {String} separator String to be placed between each item - * @return {String} joined String - * @example - * <div> - * <code> - * var array = ["Hello", "world!"] - * var separator = " " - * var message = join(array, separator); - * text(message, 5, 50); - * </code> - * </div> - */ -p5.prototype.join = function(list, separator) { - return list.join(separator); -}; - -/** - * This function is used to apply a regular expression to a piece of text, - * and return matching groups (elements found inside parentheses) as a - * String array. If there are no matches, a null value will be returned. - * If no groups are specified in the regular expression, but the sequence - * matches, an array of length 1 (with the matched text as the first element - * of the array) will be returned. - * <br><br> - * To use the function, first check to see if the result is null. If the - * result is null, then the sequence did not match at all. If the sequence - * did match, an array is returned. - * <br><br> - * If there are groups (specified by sets of parentheses) in the regular - * expression, then the contents of each will be returned in the array. - * Element [0] of a regular expression match returns the entire matching - * string, and the match groups start at element [1] (the first group is [1], - * the second [2], and so on). - * - * @method match - * @param {String} str the String to be searched - * @param {String} regexp the regexp to be used for matching - * @return {Array} Array of Strings found - * @example - * <div> - * <code> - * var string = "Hello p5js*!" - * var regexp = "p5js\\*" - * var match = match(string, regexp); - * text(match, 5, 50); - * </code> - * </div> - */ -p5.prototype.match = function(str, reg) { - return str.match(reg); -}; - -/** - * This function is used to apply a regular expression to a piece of text, - * and return a list of matching groups (elements found inside parentheses) - * as a two-dimensional String array. If there are no matches, a null value - * will be returned. If no groups are specified in the regular expression, - * but the sequence matches, a two dimensional array is still returned, but - * the second dimension is only of length one. - * <br><br> - * To use the function, first check to see if the result is null. If the - * result is null, then the sequence did not match at all. If the sequence - * did match, a 2D array is returned. - * <br><br> - * If there are groups (specified by sets of parentheses) in the regular - * expression, then the contents of each will be returned in the array. - * Assuming a loop with counter variable i, element [i][0] of a regular - * expression match returns the entire matching string, and the match groups - * start at element [i][1] (the first group is [i][1], the second [i][2], - * and so on). - * - * @method matchAll - * @param {String} str the String to be searched - * @param {String} regexp the regexp to be used for matching - * @return {Array} 2d Array of Strings found - * @example - * <div class="norender"> - * <code> - * var string = "Hello p5js*! Hello world!" - * var regexp = "Hello" - * matchAll(string, regexp); - * </code> - * </div> - - */ -p5.prototype.matchAll = function(str, reg) { - var re = new RegExp(reg, 'g'); - var match = re.exec(str); - var matches = []; - while (match !== null) { - matches.push(match); - // matched text: match[0] - // match start: match.index - // capturing group n: match[n] - match = re.exec(str); - } - return matches; -}; - -/** - * Utility function for formatting numbers into strings. There are two - * versions: one for formatting floats, and one for formatting ints. - * The values for the digits, left, and right parameters should always - * be positive integers. - * - * @method nf - * @param {Number|Array} num the Number to format - * @param {Number} [left] number of digits to the left of the - * decimal point - * @param {Number} [right] number of digits to the right of the - * decimal point - * @return {String|Array} formatted String - * @example - * <div> - * <code> - * function setup() { - * background(200); - * var num = 112.53106115; - * - * noStroke(); - * fill(0); - * textSize(14); - * // Draw formatted numbers - * text(nf(num, 5, 2), 10, 20); - * - * text(nf(num, 4, 3), 10, 55); - * - * text(nf(num, 3, 6), 10, 85); - * - * // Draw dividing lines - * stroke(120); - * line(0, 30, width, 30); - * line(0, 65, width, 65); - * } - * </code> - * </div> - */ -p5.prototype.nf = function () { - if (arguments[0] instanceof Array) { - var a = arguments[1]; - var b = arguments[2]; - return arguments[0].map(function (x) { - return doNf(x, a, b); - }); - } - else{ - var typeOfFirst = Object.prototype.toString.call(arguments[0]); - if(typeOfFirst === '[object Arguments]'){ - if(arguments[0].length===3){ - return this.nf(arguments[0][0],arguments[0][1],arguments[0][2]); - } - else if(arguments[0].length===2){ - return this.nf(arguments[0][0],arguments[0][1]); - } - else{ - return this.nf(arguments[0][0]); - } - } - else { - return doNf.apply(this, arguments); - } - } -}; - -function doNf() { - var num = arguments[0]; - var neg = num < 0; - var n = neg ? num.toString().substring(1) : num.toString(); - var decimalInd = n.indexOf('.'); - var intPart = decimalInd !== -1 ? n.substring(0, decimalInd) : n; - var decPart = decimalInd !== -1 ? n.substring(decimalInd + 1) : ''; - var str = neg ? '-' : ''; - if (arguments.length === 3) { - var decimal = ''; - if(decimalInd !== -1 || arguments[2] - decPart.length > 0){ - decimal = '.'; - } - if (decPart.length > arguments[2]) { - decPart = decPart.substring(0, arguments[2]); - } - for (var i = 0; i < arguments[1] - intPart.length; i++) { - str += '0'; - } - str += intPart; - str += decimal; - str += decPart; - for (var j = 0; j < arguments[2] - decPart.length; j++) { - str += '0'; - } - return str; - } - else { - for (var k = 0; k < Math.max(arguments[1] - intPart.length, 0); k++) { - str += '0'; - } - str += n; - return str; - } -} - -/** - * Utility function for formatting numbers into strings and placing - * appropriate commas to mark units of 1000. There are two versions: one - * for formatting ints, and one for formatting an array of ints. The value - * for the right parameter should always be a positive integer. - * - * @method nfc - * @param {Number|Array} num the Number to format - * @param {Number} [right] number of digits to the right of the - * decimal point - * @return {String|Array} formatted String - * @example - * <div> - * <code> - * function setup() { - * background(200); - * var num = 11253106.115; - * var numArr = new Array(1,1,2); - * - * noStroke(); - * fill(0); - * textSize(12); - * - * // Draw formatted numbers - * text(nfc(num, 4, 2), 10, 30); - * text(nfc(numArr, 2, 1), 10, 80); - * - * // Draw dividing line - * stroke(120); - * line(0, 50, width, 50); - * } - * </code> - * </div> - */ -p5.prototype.nfc = function () { - if (arguments[0] instanceof Array) { - var a = arguments[1]; - return arguments[0].map(function (x) { - return doNfc(x, a); - }); - } else { - return doNfc.apply(this, arguments); - } -}; -function doNfc() { - var num = arguments[0].toString(); - var dec = num.indexOf('.'); - var rem = dec !== -1 ? num.substring(dec) : ''; - var n = dec !== -1 ? num.substring(0, dec) : num; - n = n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); - if (arguments[1] === 0) { - rem = ''; - } - else if(arguments[1] !== undefined){ - if(arguments[1] > rem.length){ - rem+= dec === -1 ? '.' : ''; - var len = arguments[1] - rem.length + 1; - for(var i =0; i< len; i++){ - rem += '0'; - } - } - else{ - rem = rem.substring(0, arguments[1] + 1); - } - } - return n + rem; -} - -/** - * Utility function for formatting numbers into strings. Similar to nf() but - * puts a "+" in front of positive numbers and a "-" in front of negative - * numbers. There are two versions: one for formatting floats, and one for - * formatting ints. The values for left, and right parameters - * should always be positive integers. - * - * @method nfp - * @param {Number|Array} num the Number to format - * @param {Number} [left] number of digits to the left of the decimal - * point - * @param {Number} [right] number of digits to the right of the - * decimal point - * @return {String|Array} formatted String - * @example - * <div> - * <code> - * function setup() { - * background(200); - * var num1 = 11253106.115; - * var num2 = -11253106.115; - * - * noStroke(); - * fill(0); - * textSize(12); - * - * // Draw formatted numbers - * text(nfp(num1, 4, 2), 10, 30); - * text(nfp(num2, 4, 2), 10, 80); - * - * // Draw dividing line - * stroke(120); - * line(0, 50, width, 50); - * } - * </code> - * </div> - */ -p5.prototype.nfp = function() { - var nfRes = this.nf.apply(this, arguments); - if (nfRes instanceof Array) { - return nfRes.map(addNfp); - } else { - return addNfp(nfRes); - } -}; - -function addNfp() { - return ( - parseFloat(arguments[0]) > 0) ? - '+'+arguments[0].toString() : - arguments[0].toString(); -} - -/** - * Utility function for formatting numbers into strings. Similar to nf() but - * puts a " " (space) in front of positive numbers and a "-" in front of - * negative numbers. There are two versions: one for formatting floats, and - * one for formatting ints. The values for the digits, left, and right - * parameters should always be positive integers. - * - * @method nfs - * @param {Number|Array} num the Number to format - * @param {Number} [left] number of digits to the left of the decimal - * point - * @param {Number} [right] number of digits to the right of the - * decimal point - * @return {String|Array} formatted String - * @example - * <div> - * <code> - * function setup() { - * background(200); - * var num1 = 11253106.115; - * var num2 = -11253106.115; - * - * noStroke(); - * fill(0); - * textSize(12); - * // Draw formatted numbers - * text(nfs(num1, 4, 2), 10, 30); - * - * text(nfs(num2, 4, 2), 10, 80); - * - * // Draw dividing line - * stroke(120); - * line(0, 50, width, 50); - * } - * </code> - * </div> - */ -p5.prototype.nfs = function() { - var nfRes = this.nf.apply(this, arguments); - if (nfRes instanceof Array) { - return nfRes.map(addNfs); - } else { - return addNfs(nfRes); - } -}; - -function addNfs() { - return ( - parseFloat(arguments[0]) > 0) ? - ' '+arguments[0].toString() : - arguments[0].toString(); -} - -/** - * The split() function maps to String.split(), it breaks a String into - * pieces using a character or string as the delimiter. The delim parameter - * specifies the character or characters that mark the boundaries between - * each piece. A String[] array is returned that contains each of the pieces. - * - * The splitTokens() function works in a similar fashion, except that it - * splits using a range of characters instead of a specific character or - * sequence. - * - * @method split - * @param {String} value the String to be split - * @param {String} delim the String used to separate the data - * @return {Array} Array of Strings - * @example - * <div> - * <code> - * var names = "Pat,Xio,Alex" - * var splitString = split(names, ","); - * text(splitString[0], 5, 30); - * text(splitString[1], 5, 50); - * text(splitString[2], 5, 70); - * </code> - * </div> - */ -p5.prototype.split = function(str, delim) { - return str.split(delim); -}; - -/** - * The splitTokens() function splits a String at one or many character - * delimiters or "tokens." The delim parameter specifies the character or - * characters to be used as a boundary. - * <br><br> - * If no delim characters are specified, any whitespace character is used to - * split. Whitespace characters include tab (\t), line feed (\n), carriage - * return (\r), form feed (\f), and space. - * - * @method splitTokens - * @param {String} value the String to be split - * @param {String} [delim] list of individual Strings that will be used as - * separators - * @return {Array} Array of Strings - * @example - * <div class = "norender"> - * <code> - * function setup() { - * var myStr = "Mango, Banana, Lime"; - * var myStrArr = splitTokens(myStr, ","); - * - * print(myStrArr); // prints : ["Mango"," Banana"," Lime"] - * } - * </code> - * </div> - */ -p5.prototype.splitTokens = function() { - var d,sqo,sqc,str; - str = arguments[1]; - if (arguments.length > 1) { - sqc = /\]/g.exec(str); - sqo = /\[/g.exec(str); - if ( sqo && sqc ) { - str = str.slice(0, sqc.index) + str.slice(sqc.index+1); - sqo = /\[/g.exec(str); - str = str.slice(0, sqo.index) + str.slice(sqo.index+1); - d = new RegExp('[\\['+str+'\\]]','g'); - } else if ( sqc ) { - str = str.slice(0, sqc.index) + str.slice(sqc.index+1); - d = new RegExp('[' + str + '\\]]', 'g'); - } else if(sqo) { - str = str.slice(0, sqo.index) + str.slice(sqo.index+1); - d = new RegExp('[' + str + '\\[]', 'g'); - } else { - d = new RegExp('[' + str + ']', 'g'); - } - } else { - d = /\s/g; - } - return arguments[0].split(d).filter(function(n){return n;}); -}; - -/** - * Removes whitespace characters from the beginning and end of a String. In - * addition to standard whitespace characters such as space, carriage return, - * and tab, this function also removes the Unicode "nbsp" character. - * - * @method trim - * @param {String|Array} [str] a String or Array of Strings to be trimmed - * @return {String|Array} a trimmed String or Array of Strings - * @example - * <div> - * <code> - * var string = trim(" No new lines\n "); - * text(string +" here", 2, 50); - * </code> - * </div> - */ -p5.prototype.trim = function(str) { - if (str instanceof Array) { - return str.map(this.trim); - } else { - return str.trim(); - } -}; - -module.exports = p5; - -},{"../core/core":48}],86:[function(_dereq_,module,exports){ -/** - * @module Input - * @submodule Time & Date - * @for p5 - * @requires core - */ - -'use strict'; - -var p5 = _dereq_('../core/core'); - -/** - * p5.js communicates with the clock on your computer. The day() function - * returns the current day as a value from 1 - 31. - * - * @method day - * @return {Number} the current day - * @example - * <div> - * <code> - * var day = day(); - * text("Current day: \n" + day, 5, 50); - * </code> - * </div> - */ -p5.prototype.day = function() { - return new Date().getDate(); -}; - -/** - * p5.js communicates with the clock on your computer. The hour() function - * returns the current hour as a value from 0 - 23. - * - * @method hour - * @return {Number} the current hour - * @example - * <div> - * <code> - * var hour = hour(); - * text("Current hour:\n" + hour, 5, 50); - * </code> - * </div> - */ -p5.prototype.hour = function() { - return new Date().getHours(); -}; - -/** - * p5.js communicates with the clock on your computer. The minute() function - * returns the current minute as a value from 0 - 59. - * - * @method minute - * @return {Number} the current minute - * @example - * <div> - * <code> - * var minute = minute(); - * text("Current minute: \n" + minute, 5, 50); - * </code> - * </div> - */ -p5.prototype.minute = function() { - return new Date().getMinutes(); -}; - -/** - * Returns the number of milliseconds (thousandths of a second) since - * starting the program. This information is often used for timing events and - * animation sequences. - * - * @method millis - * @return {Number} the number of milliseconds since starting the program - * @example - * <div> - * <code> - * var millisecond = millis(); - * text("Milliseconds \nrunning: \n" + millisecond, 5, 40); - * </code> - * </div> - */ -p5.prototype.millis = function() { - return window.performance.now(); -}; - -/** - * p5.js communicates with the clock on your computer. The month() function - * returns the current month as a value from 1 - 12. - * - * @method month - * @return {Number} the current month - * @example - * <div> - * <code> - * var month = month(); - * text("Current month: \n" + month, 5, 50); - * </code> - * </div> - */ -p5.prototype.month = function() { - return new Date().getMonth() + 1; //January is 0! -}; - -/** - * p5.js communicates with the clock on your computer. The second() function - * returns the current second as a value from 0 - 59. - * - * @method second - * @return {Number} the current second - * @example - * <div> - * <code> - * var second = second(); - * text("Current second: \n" + second, 5, 50); - * </code> - * </div> - */ -p5.prototype.second = function() { - return new Date().getSeconds(); -}; - -/** - * p5.js communicates with the clock on your computer. The year() function - * returns the current year as an integer (2014, 2015, 2016, etc). - * - * @method year - * @return {Number} the current year - * @example - * <div> - * <code> - * var year = year(); - * text("Current year: \n" + year, 5, 50); - * </code> - * </div> - */ -p5.prototype.year = function() { - return new Date().getFullYear(); -}; - -module.exports = p5; - -},{"../core/core":48}]},{},[39])(39) -});
\ No newline at end of file diff --git a/js/processing.js b/js/processing.js deleted file mode 100644 index 4cebd06..0000000 --- a/js/processing.js +++ /dev/null @@ -1,21748 +0,0 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ -// build script for generating processing.js - -var Browser = { - isDomPresent: true, - navigator: navigator, - window: window, - document: document, - ajax: function(url) { - var xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); - if (xhr.overrideMimeType) { - xhr.overrideMimeType("text/plain"); - } - xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); - xhr.send(null); - // failed request? - if (xhr.status !== 200 && xhr.status !== 0) { throw ("XMLHttpRequest failed, status code " + xhr.status); } - return xhr.responseText; - } -}; - -window.Processing = require('./src/')(Browser); - -},{"./src/":28}],2:[function(require,module,exports){ -module.exports={ - "name": "processing-js", - "version": "1.4.16", - "author": "Processing.js", - "repository": { - "type": "git", - "url": "git@github.com/processing-js/processing-js.git" - }, - "main": "processing.min.js", - "bugs": "https://github.com/processing-js/processing-js/issues", - "devDependencies": { - "argv": "~0.0.2", - "browserify": "^11.0.1", - "express": "~3.3.3", - "node-minify": "~0.7.3", - "nunjucks": "~0.1.9", - "open": "0.0.3", - "grunt": "~0.4.1", - "grunt-cli": "~0.1.8", - "grunt-contrib-jshint": "~0.4.3" - }, - "scripts": { - "test": "node test", - "start": "browserify build.js -o processing.js && node minify" - }, - "license": "MIT" -} - -},{}],3:[function(require,module,exports){ -/** -* A ObjectIterator is an iterator wrapper for objects. If passed object contains -* the iterator method, the object instance will be replaced by the result returned by -* this method call. If passed object is an array, the ObjectIterator instance iterates -* through its items. -* -* @param {Object} obj The object to be iterated. -*/ -module.exports = function ObjectIterator(obj) { - if (obj instanceof Array) { - // iterate through array items - var index = -1; - this.hasNext = function() { - return ++index < obj.length; - }; - this.next = function() { - return obj[index]; - }; - } else if (obj.iterator instanceof Function) { - return obj.iterator(); - } else { - throw "Unable to iterate: " + obj; - } -}; - -},{}],4:[function(require,module,exports){ -/** - * Processing.js environment constants - */ -module.exports = { - X: 0, - Y: 1, - Z: 2, - - R: 3, - G: 4, - B: 5, - A: 6, - - U: 7, - V: 8, - - NX: 9, - NY: 10, - NZ: 11, - - EDGE: 12, - - // Stroke - SR: 13, - SG: 14, - SB: 15, - SA: 16, - - SW: 17, - - // Transformations (2D and 3D) - TX: 18, - TY: 19, - TZ: 20, - - VX: 21, - VY: 22, - VZ: 23, - VW: 24, - - // Material properties - AR: 25, - AG: 26, - AB: 27, - - DR: 3, - DG: 4, - DB: 5, - DA: 6, - - SPR: 28, - SPG: 29, - SPB: 30, - - SHINE: 31, - - ER: 32, - EG: 33, - EB: 34, - - BEEN_LIT: 35, - - VERTEX_FIELD_COUNT: 36, - - // Renderers - P2D: 1, - JAVA2D: 1, - WEBGL: 2, - P3D: 2, - OPENGL: 2, - PDF: 0, - DXF: 0, - - // Platform IDs - OTHER: 0, - WINDOWS: 1, - MAXOSX: 2, - LINUX: 3, - - EPSILON: 0.0001, - - MAX_FLOAT: 3.4028235e+38, - MIN_FLOAT: -3.4028235e+38, - MAX_INT: 2147483647, - MIN_INT: -2147483648, - - PI: Math.PI, - TWO_PI: 2 * Math.PI, - TAU: 2 * Math.PI, - HALF_PI: Math.PI / 2, - THIRD_PI: Math.PI / 3, - QUARTER_PI: Math.PI / 4, - - DEG_TO_RAD: Math.PI / 180, - RAD_TO_DEG: 180 / Math.PI, - - WHITESPACE: " \t\n\r\f\u00A0", - - // Color modes - RGB: 1, - ARGB: 2, - HSB: 3, - ALPHA: 4, - CMYK: 5, - - // Image file types - TIFF: 0, - TARGA: 1, - JPEG: 2, - GIF: 3, - - // Filter/convert types - BLUR: 11, - GRAY: 12, - INVERT: 13, - OPAQUE: 14, - POSTERIZE: 15, - THRESHOLD: 16, - ERODE: 17, - DILATE: 18, - - // Blend modes - REPLACE: 0, - BLEND: 1 << 0, - ADD: 1 << 1, - SUBTRACT: 1 << 2, - LIGHTEST: 1 << 3, - DARKEST: 1 << 4, - DIFFERENCE: 1 << 5, - EXCLUSION: 1 << 6, - MULTIPLY: 1 << 7, - SCREEN: 1 << 8, - OVERLAY: 1 << 9, - HARD_LIGHT: 1 << 10, - SOFT_LIGHT: 1 << 11, - DODGE: 1 << 12, - BURN: 1 << 13, - - // Color component bit masks - ALPHA_MASK: 0xff000000, - RED_MASK: 0x00ff0000, - GREEN_MASK: 0x0000ff00, - BLUE_MASK: 0x000000ff, - - // Projection matrices - CUSTOM: 0, - ORTHOGRAPHIC: 2, - PERSPECTIVE: 3, - - // Shapes - POINT: 2, - POINTS: 2, - LINE: 4, - LINES: 4, - TRIANGLE: 8, - TRIANGLES: 9, - TRIANGLE_STRIP: 10, - TRIANGLE_FAN: 11, - QUAD: 16, - QUADS: 16, - QUAD_STRIP: 17, - POLYGON: 20, - PATH: 21, - RECT: 30, - ELLIPSE: 31, - ARC: 32, - SPHERE: 40, - BOX: 41, - - GROUP: 0, - PRIMITIVE: 1, - //PATH: 21, // shared with Shape PATH - GEOMETRY: 3, - - // Shape Vertex - VERTEX: 0, - BEZIER_VERTEX: 1, - CURVE_VERTEX: 2, - BREAK: 3, - CLOSESHAPE: 4, - - // Shape closing modes - OPEN: 1, - CLOSE: 2, - - // Shape drawing modes - CORNER: 0, // Draw mode convention to use (x, y) to (width, height) - CORNERS: 1, // Draw mode convention to use (x1, y1) to (x2, y2) coordinates - RADIUS: 2, // Draw mode from the center, and using the radius - CENTER_RADIUS: 2, // Deprecated! Use RADIUS instead - CENTER: 3, // Draw from the center, using second pair of values as the diameter - DIAMETER: 3, // Synonym for the CENTER constant. Draw from the center - CENTER_DIAMETER: 3, // Deprecated! Use DIAMETER instead - - // Text vertical alignment modes - BASELINE: 0, // Default vertical alignment for text placement - TOP: 101, // Align text to the top - BOTTOM: 102, // Align text from the bottom, using the baseline - - // UV Texture coordinate modes - NORMAL: 1, - NORMALIZED: 1, - IMAGE: 2, - - // Text placement modes - MODEL: 4, - SHAPE: 5, - - // Stroke modes - SQUARE: 'butt', - ROUND: 'round', - PROJECT: 'square', - MITER: 'miter', - BEVEL: 'bevel', - - // Lighting modes - AMBIENT: 0, - DIRECTIONAL: 1, - //POINT: 2, Shared with Shape constant - SPOT: 3, - - // Key constants - - // Both key and keyCode will be equal to these values - BACKSPACE: 8, - TAB: 9, - ENTER: 10, - RETURN: 13, - ESC: 27, - DELETE: 127, - CODED: 0xffff, - - // p.key will be CODED and p.keyCode will be this value - SHIFT: 16, - CONTROL: 17, - ALT: 18, - CAPSLK: 20, - PGUP: 33, - PGDN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - F1: 112, - F2: 113, - F3: 114, - F4: 115, - F5: 116, - F6: 117, - F7: 118, - F8: 119, - F9: 120, - F10: 121, - F11: 122, - F12: 123, - NUMLK: 144, - META: 157, - INSERT: 155, - - // Cursor types - ARROW: 'default', - CROSS: 'crosshair', - HAND: 'pointer', - MOVE: 'move', - TEXT: 'text', - WAIT: 'wait', - NOCURSOR: "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), auto", - - // Hints - DISABLE_OPENGL_2X_SMOOTH: 1, - ENABLE_OPENGL_2X_SMOOTH: -1, - ENABLE_OPENGL_4X_SMOOTH: 2, - ENABLE_NATIVE_FONTS: 3, - DISABLE_DEPTH_TEST: 4, - ENABLE_DEPTH_TEST: -4, - ENABLE_DEPTH_SORT: 5, - DISABLE_DEPTH_SORT: -5, - DISABLE_OPENGL_ERROR_REPORT: 6, - ENABLE_OPENGL_ERROR_REPORT: -6, - ENABLE_ACCURATE_TEXTURES: 7, - DISABLE_ACCURATE_TEXTURES: -7, - HINT_COUNT: 10, - - // PJS defined constants - SINCOS_LENGTH: 720, // every half degree - PRECISIONB: 15, // fixed point precision is limited to 15 bits!! - PRECISIONF: 1 << 15, - PREC_MAXVAL: (1 << 15) - 1, - PREC_ALPHA_SHIFT: 24 - 15, - PREC_RED_SHIFT: 16 - 15, - NORMAL_MODE_AUTO: 0, - NORMAL_MODE_SHAPE: 1, - NORMAL_MODE_VERTEX: 2, - MAX_LIGHTS: 8 -}; - -},{}],5:[function(require,module,exports){ -// the logger for println() -module.exports = function PjsConsole(document) { - var e = { BufferMax: 200 }, - style = document.createElement("style"), - added = false; - - style.textContent = [ - ".pjsconsole.hidden {", - " display: none!important;", - "}" - ].join('\n'); - - e.wrapper = document.createElement("div"); - style.textContent += [ - "", - ".pjsconsole {", - " opacity: .75;", - " display: block;", - " position: fixed;", - " bottom: 0px;", - " left: 0px;", - " right: 0px;", - " height: 50px;", - " background-color: #aaa;", - "}" - ].join('\n'); - e.wrapper.classList.add("pjsconsole"); - - e.dragger = document.createElement("div"); - style.textContent += [ - "", - ".pjsconsole .dragger {", - " display: block;", - " border: 3px black raised;", - " cursor: n-resize;", - " position: absolute;", - " top: 0px;", - " left: 0px;", - " right: 0px;", - " height: 5px;", - " background-color: #333;", - "}" - ].join('\n'); - e.dragger.classList.add("dragger"); - - e.closer = document.createElement("div"); - style.textContent += [ - "", - ".pjsconsole .closer {", - " opacity: .5;", - " display: block;", - " border: 3px black raised;", - " position: absolute;", - " top: 10px;", - " right: 30px;", - " height: 20px;", - " width: 20px;", - " background-color: #ddd;", - " color: #000;", - " line-height: 20px;", - " text-align: center;", - " cursor: pointer", - "}" - ].join('\n'); - e.closer.classList.add("closer"); - e.closer.innerHTML = "✖"; - - e.javaconsole = document.createElement("div"); - style.textContent += [ - "", - ".pjsconsole .console {", - " overflow-x: auto;", - " display: block;", - " position: absolute;", - " left: 10px;", - " right: 0px;", - " bottom: 5px;", - " top: 10px;", - " overflow-y: scroll;", - " height: 40px;", - "}" - ].join('\n'); - e.javaconsole.setAttribute("class", "console"); - - e.wrapper.appendChild(e.dragger); - e.wrapper.appendChild(e.javaconsole); - e.wrapper.appendChild(e.closer); - - e.dragger.onmousedown = function (t) { - e.divheight = e.wrapper.style.height; - if (document.selection) document.selection.empty(); - else window.getSelection().removeAllRanges(); - var n = t.screenY; - window.onmousemove = function (t) { - e.wrapper.style.height = parseFloat(e.divheight) + (n - t.screenY) + "px"; - e.javaconsole.style.height = parseFloat(e.divheight) + (n - t.screenY) - 10 + "px"; - }; - window.onmouseup = function (t) { - if (document.selection) document.selection.empty(); - else window.getSelection().removeAllRanges(); - e.wrapper.style.height = parseFloat(e.divheight) + (n - t.screenY) + "px"; - e.javaconsole.style.height = parseFloat(e.divheight) + (n - t.screenY) - 10 + "px"; - window.onmousemove = null; - window.onmouseup = null; - }; - }; - - e.BufferArray = []; - - e.print = e.log = function () { - var args = Array.prototype.slice.call(arguments); - t = args.map(function(t, idx) { return t + (idx+1 === args.length ? "" : " "); }).join(''); - if (e.BufferArray[e.BufferArray.length - 1]) e.BufferArray[e.BufferArray.length - 1] += (t) + ""; - else e.BufferArray.push(t); - e.javaconsole.innerHTML = e.BufferArray.join(''); - e.showconsole(); - }; - - e.println = function () { - if(!added) { - document.body.appendChild(style); - document.body.appendChild(e.wrapper); - added = true; - } - var args = Array.prototype.slice.call(arguments); - args.push('<br>'); - e.print.apply(e, args); - if (e.BufferArray.length > e.BufferMax) { - e.BufferArray.splice(0, 1); - } else { - e.javaconsole.scrollTop = e.javaconsole.scrollHeight; - } - }; - - e.showconsole = function () { e.wrapper.classList.remove("hidden"); }; - e.hideconsole = function () { e.wrapper.classList.add("hidden"); }; - - e.closer.onclick = function () { e.hideconsole(); }; - - e.hideconsole(); - - return e; -}; - -},{}],6:[function(require,module,exports){ -/** - * Processing.js default scope - */ -module.exports = function(options) { - - // Building defaultScope. Changing of the prototype protects - // internal Processing code from the changes in defaultScope - function DefaultScope() {} - DefaultScope.prototype = options.PConstants; - - var defaultScope = new DefaultScope(); - - // copy over all known Object types and helper objects - Object.keys(options).forEach(function(prop) { - defaultScope[prop] = options[prop]; - }); - - //////////////////////////////////////////////////////////////////////////// - // Class inheritance helper methods - //////////////////////////////////////////////////////////////////////////// - - defaultScope.defineProperty = function(obj, name, desc) { - if("defineProperty" in Object) { - Object.defineProperty(obj, name, desc); - } else { - if (desc.hasOwnProperty("get")) { - obj.__defineGetter__(name, desc.get); - } - if (desc.hasOwnProperty("set")) { - obj.__defineSetter__(name, desc.set); - } - } - }; - - /** - * class overloading, part 1 - */ - function overloadBaseClassFunction(object, name, basefn) { - if (!object.hasOwnProperty(name) || typeof object[name] !== 'function') { - // object method is not a function or just inherited from Object.prototype - object[name] = basefn; - return; - } - var fn = object[name]; - if ("$overloads" in fn) { - // the object method already overloaded (see defaultScope.addMethod) - // let's just change a fallback method - fn.$defaultOverload = basefn; - return; - } - if (!("$overloads" in basefn) && fn.length === basefn.length) { - // special case when we just overriding the method - return; - } - var overloads, defaultOverload; - if ("$overloads" in basefn) { - // let's inherit base class overloads to speed up things - overloads = basefn.$overloads.slice(0); - overloads[fn.length] = fn; - defaultOverload = basefn.$defaultOverload; - } else { - overloads = []; - overloads[basefn.length] = basefn; - overloads[fn.length] = fn; - defaultOverload = fn; - } - var hubfn = function() { - var fn = hubfn.$overloads[arguments.length] || - ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? - hubfn.$overloads[hubfn.$methodArgsIndex] : null) || - hubfn.$defaultOverload; - return fn.apply(this, arguments); - }; - hubfn.$overloads = overloads; - if ("$methodArgsIndex" in basefn) { - hubfn.$methodArgsIndex = basefn.$methodArgsIndex; - } - hubfn.$defaultOverload = defaultOverload; - hubfn.name = name; - object[name] = hubfn; - } - - /** - * class overloading, part 2 - */ - - function extendClass(subClass, baseClass) { - function extendGetterSetter(propertyName) { - defaultScope.defineProperty(subClass, propertyName, { - get: function() { - return baseClass[propertyName]; - }, - set: function(v) { - baseClass[propertyName]=v; - }, - enumerable: true - }); - } - - var properties = []; - for (var propertyName in baseClass) { - if (typeof baseClass[propertyName] === 'function') { - overloadBaseClassFunction(subClass, propertyName, baseClass[propertyName]); - } else if(propertyName.charAt(0) !== "$" && !(propertyName in subClass)) { - // Delaying the properties extension due to the IE9 bug (see #918). - properties.push(propertyName); - } - } - while (properties.length > 0) { - extendGetterSetter(properties.shift()); - } - - subClass.$super = baseClass; - } - - /** - * class overloading, part 3 - */ - defaultScope.extendClassChain = function(base) { - var path = [base]; - for (var self = base.$upcast; self; self = self.$upcast) { - extendClass(self, base); - path.push(self); - base = self; - } - while (path.length > 0) { - path.pop().$self=base; - } - }; - - // static - defaultScope.extendStaticMembers = function(derived, base) { - extendClass(derived, base); - }; - - // interface - defaultScope.extendInterfaceMembers = function(derived, base) { - extendClass(derived, base); - }; - - /** - * Java methods and JavaScript functions differ enough that - * we need a special function to make sure it all links up - * as classical hierarchical class chains. - */ - defaultScope.addMethod = function(object, name, fn, hasMethodArgs) { - var existingfn = object[name]; - if (existingfn || hasMethodArgs) { - var args = fn.length; - // builds the overload methods table - if ("$overloads" in existingfn) { - existingfn.$overloads[args] = fn; - } else { - var hubfn = function() { - var fn = hubfn.$overloads[arguments.length] || - ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? - hubfn.$overloads[hubfn.$methodArgsIndex] : null) || - hubfn.$defaultOverload; - return fn.apply(this, arguments); - }; - var overloads = []; - if (existingfn) { - overloads[existingfn.length] = existingfn; - } - overloads[args] = fn; - hubfn.$overloads = overloads; - hubfn.$defaultOverload = existingfn || fn; - if (hasMethodArgs) { - hubfn.$methodArgsIndex = args; - } - hubfn.name = name; - object[name] = hubfn; - } - } else { - object[name] = fn; - } - }; - - // internal helper function - function isNumericalJavaType(type) { - if (typeof type !== "string") { - return false; - } - return ["byte", "int", "char", "color", "float", "long", "double"].indexOf(type) !== -1; - } - - /** - * Java's arrays are pre-filled when declared with - * an initial size, but no content. JS arrays are not. - */ - defaultScope.createJavaArray = function(type, bounds) { - var result = null, - defaultValue = null; - if (typeof type === "string") { - if (type === "boolean") { - defaultValue = false; - } else if (isNumericalJavaType(type)) { - defaultValue = 0; - } - } - if (typeof bounds[0] === 'number') { - var itemsCount = 0 | bounds[0]; - if (bounds.length <= 1) { - result = []; - result.length = itemsCount; - for (var i = 0; i < itemsCount; ++i) { - result[i] = defaultValue; - } - } else { - result = []; - var newBounds = bounds.slice(1); - for (var j = 0; j < itemsCount; ++j) { - result.push(defaultScope.createJavaArray(type, newBounds)); - } - } - } - return result; - }; - - // screenWidth and screenHeight are shared by all instances. - // and return the width/height of the browser's viewport. - defaultScope.defineProperty(defaultScope, 'screenWidth', - { get: function() { return window.innerWidth; } }); - - defaultScope.defineProperty(defaultScope, 'screenHeight', - { get: function() { return window.innerHeight; } }); - - return defaultScope; -}; - -},{}],7:[function(require,module,exports){ -/** - * Finalise the Processing.js object. - */ -module.exports = function finalizeProcessing(Processing, options) { - - // unpack options - var window = options.window, - document = options.document, - XMLHttpRequest = window.XMLHttpRequest, - noop = options.noop, - isDOMPresent = options.isDOMPresent, - version = options.version, - undef; - - // versioning - Processing.version = (version ? version : "@DEV-VERSION@"); - - // Share lib space - Processing.lib = {}; - - /** - * External libraries can be added to the global Processing - * objects with the `registerLibrary` function. - */ - Processing.registerLibrary = function(name, library) { - Processing.lib[name] = library; - if(library.hasOwnProperty("init")) { - library.init(defaultScope); - } - }; - - /** - * This is the object that acts as our version of PApplet. - * This can be called as Processing.Sketch() or as - * Processing.Sketch(function) in which case the function - * must be an already-compiled-to-JS sketch function. - */ - Processing.Sketch = function(attachFunction) { - this.attachFunction = attachFunction; - this.options = { - pauseOnBlur: false, - globalKeyEvents: false - }; - - /* Optional Sketch event hooks: - * onLoad - parsing/preloading is done, before sketch starts - * onSetup - setup() has been called, before first draw() - * onPause - noLoop() has been called, pausing draw loop - * onLoop - loop() has been called, resuming draw loop - * onFrameStart - draw() loop about to begin - * onFrameEnd - draw() loop finished - * onExit - exit() done being called - */ - this.onLoad = noop; - this.onSetup = noop; - this.onPause = noop; - this.onLoop = noop; - this.onFrameStart = noop; - this.onFrameEnd = noop; - this.onExit = noop; - - this.params = {}; - this.imageCache = { - pending: 0, - images: {}, - // Opera requires special administration for preloading - operaCache: {}, - // Specify an optional img arg if the image is already loaded in the DOM, - // otherwise href will get loaded. - add: function(href, img) { - // Prevent muliple loads for an image, in case it gets - // preloaded more than once, or is added via JS and then preloaded. - if (this.images[href]) { - return; - } - - if (!isDOMPresent) { - this.images[href] = null; - } - - // No image in the DOM, kick-off a background load - if (!img) { - img = new Image(); - img.onload = (function(owner) { - return function() { - owner.pending--; - }; - }(this)); - this.pending++; - img.src = href; - } - - this.images[href] = img; - - // Opera will not load images until they are inserted into the DOM. - if (window.opera) { - var div = document.createElement("div"); - div.appendChild(img); - // we can't use "display: none", since that makes it invisible, and thus not load - div.style.position = "absolute"; - div.style.opacity = 0; - div.style.width = "1px"; - div.style.height= "1px"; - if (!this.operaCache[href]) { - document.body.appendChild(div); - this.operaCache[href] = div; - } - } - } - }; - - this.sourceCode = undefined; - this.attach = function(processing) { - // either attachFunction or sourceCode must be present on attach - if(typeof this.attachFunction === "function") { - this.attachFunction(processing); - } else if(this.sourceCode) { - var func = ((new Function("return (" + this.sourceCode + ");"))()); - func(processing); - this.attachFunction = func; - } else { - throw "Unable to attach sketch to the processing instance"; - } - }; - - this.toString = function() { - var i; - var code = "((function(Sketch) {\n"; - code += "var sketch = new Sketch(\n" + this.sourceCode + ");\n"; - for(i in this.options) { - if(this.options.hasOwnProperty(i)) { - var value = this.options[i]; - code += "sketch.options." + i + " = " + - (typeof value === 'string' ? '\"' + value + '\"' : "" + value) + ";\n"; - } - } - for(i in this.imageCache) { - if(this.options.hasOwnProperty(i)) { - code += "sketch.imageCache.add(\"" + i + "\");\n"; - } - } - // TODO serialize fonts - code += "return sketch;\n})(Processing.Sketch))"; - return code; - }; - }; - - /** - * aggregate all source code into a single file, then rewrite that - * source and bind to canvas via new Processing(canvas, sourcestring). - * @param {CANVAS} canvas The html canvas element to bind to - * @param {String[]} source The array of files that must be loaded - */ - var loadSketchFromSources = Processing.loadSketchFromSources = function(canvas, sources) { - var code = [], errors = [], sourcesCount = sources.length, loaded = 0; - - function ajaxAsync(url, callback) { - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - var error; - if (xhr.status !== 200 && xhr.status !== 0) { - error = "Invalid XHR status " + xhr.status; - } else if (xhr.responseText === "") { - // Give a hint when loading fails due to same-origin issues on file:/// urls - if ( ("withCredentials" in new XMLHttpRequest()) && - (new XMLHttpRequest()).withCredentials === false && - window.location.protocol === "file:" ) { - error = "XMLHttpRequest failure, possibly due to a same-origin policy violation. You can try loading this page in another browser, or load it from http://localhost using a local webserver. See the Processing.js README for a more detailed explanation of this problem and solutions."; - } else { - error = "File is empty."; - } - } - - callback(xhr.responseText, error); - } - }; - xhr.open("GET", url, true); - if (xhr.overrideMimeType) { - xhr.overrideMimeType("application/json"); - } - xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); // no cache - xhr.send(null); - } - - function loadBlock(index, filename) { - function callback(block, error) { - code[index] = block; - ++loaded; - if (error) { - errors.push(filename + " ==> " + error); - } - if (loaded === sourcesCount) { - if (errors.length === 0) { - // This used to throw, but it was constantly getting in the way of debugging where things go wrong! - return new Processing(canvas, code.join("\n")); - } else { - throw "Processing.js: Unable to load pjs sketch files: " + errors.join("\n"); - } - } - } - if (filename.charAt(0) === '#') { - // trying to get script from the element - var scriptElement = document.getElementById(filename.substring(1)); - if (scriptElement) { - callback(scriptElement.text || scriptElement.textContent); - } else { - callback("", "Unable to load pjs sketch: element with id \'" + filename.substring(1) + "\' was not found"); - } - return; - } - - ajaxAsync(filename, callback); - } - - for (var i = 0; i < sourcesCount; ++i) { - loadBlock(i, sources[i]); - } - }; - - /** - * Automatic initialization function. - */ - var init = function() { - document.removeEventListener('DOMContentLoaded', init, false); - var i; - - // before running through init, clear the instances list, to prevent - // sketch duplication when page content is dynamically swapped without - // swapping out processing.js - while (Processing.instances.length > 0) { - for (i = Processing.instances.length - 1; i >= 0; i--) { - if (Processing.instances[i]) { - Processing.instances[i].exit(); - } - } - } - - var canvas = document.getElementsByTagName('canvas'), - filenames; - - for (i = 0, l = canvas.length; i < l; i++) { - // datasrc and data-src are deprecated. - var processingSources = canvas[i].getAttribute('data-processing-sources'); - if (processingSources === null) { - // Temporary fallback for datasrc and data-src - processingSources = canvas[i].getAttribute('data-src'); - if (processingSources === null) { - processingSources = canvas[i].getAttribute('datasrc'); - } - } - if (processingSources) { - filenames = processingSources.split(/\s+/g); - for (var j = 0; j < filenames.length;) { - if (filenames[j]) { - j++; - } else { - filenames.splice(j, 1); - } - } - loadSketchFromSources(canvas[i], filenames); - } - } - - // also process all <script>-indicated sketches, if there are any - var s, last, source, instance, - nodelist = document.getElementsByTagName('script'), - scripts=[]; - - // snapshot the DOM, as the nodelist is only a DOM view, and is - // updated instantly when a script element is added or removed. - for (s = nodelist.length - 1; s >= 0; s--) { - scripts.push(nodelist[s]); - } - - // iterate over all script elements to see if they contain Processing code - for (s = 0, last = scripts.length; s < last; s++) { - var script = scripts[s]; - if (!script.getAttribute) { - continue; - } - - var type = script.getAttribute("type"); - if (type && (type.toLowerCase() === "text/processing" || type.toLowerCase() === "application/processing")) { - var target = script.getAttribute("data-processing-target"); - canvas = undef; - if (target) { - canvas = document.getElementById(target); - } else { - var nextSibling = script.nextSibling; - while (nextSibling && nextSibling.nodeType !== 1) { - nextSibling = nextSibling.nextSibling; - } - if (nextSibling && nextSibling.nodeName.toLowerCase() === "canvas") { - canvas = nextSibling; - } - } - - if (canvas) { - if (script.getAttribute("src")) { - filenames = script.getAttribute("src").split(/\s+/); - loadSketchFromSources(canvas, filenames); - continue; - } - source = script.textContent || script.text; - instance = new Processing(canvas, source); - } - } - } - }; - - /** - * automatic loading of all sketches on the page - */ - document.addEventListener('DOMContentLoaded', init, false); - - /** - * Make Processing run through init after already having - * been set up for a page. This function exists mostly for pages - * that swap content in/out without reloading a page. - */ - Processing.reload = init; - - /** - * Disable the automatic loading of all sketches on the page. - * This will work as long as it's issued before DOMContentLoaded. - */ - Processing.disableInit = function() { - document.removeEventListener('DOMContentLoaded', init, false); - }; - - // done. - return Processing; -}; - -},{}],8:[function(require,module,exports){ -/** - * Returns Java equals() result for two objects. If the first object - * has the "equals" function, it preforms the call of this function. - * Otherwise the method uses the JavaScript === operator. - * - * @param {Object} obj The first object. - * @param {Object} other The second object. - * - * @returns {boolean} true if the objects are equal. - */ -module.exports = function virtEquals(obj, other) { - if (obj === null || other === null) { - return (obj === null) && (other === null); - } - if (typeof (obj) === "string") { - return obj === other; - } - if (typeof(obj) !== "object") { - return obj === other; - } - if (obj.equals instanceof Function) { - return obj.equals(other); - } - return obj === other; -}; - -},{}],9:[function(require,module,exports){ -/** - * Returns Java hashCode() result for the object. If the object has the "hashCode" function, - * it preforms the call of this function. Otherwise it uses/creates the "$id" property, - * which is used as the hashCode. - * - * @param {Object} obj The object. - * @returns {int} The object's hash code. - */ -module.exports = function virtHashCode(obj, undef) { - if (typeof(obj) === "string") { - var hash = 0; - for (var i = 0; i < obj.length; ++i) { - hash = (hash * 31 + obj.charCodeAt(i)) & 0xFFFFFFFF; - } - return hash; - } - if (typeof(obj) !== "object") { - return obj & 0xFFFFFFFF; - } - if (obj.hashCode instanceof Function) { - return obj.hashCode(); - } - if (obj.$id === undef) { - obj.$id = ((Math.floor(Math.random() * 0x10000) - 0x8000) << 16) | Math.floor(Math.random() * 0x10000); - } - return obj.$id; -}; - -},{}],10:[function(require,module,exports){ -/** - * An ArrayList stores a variable number of objects. - * - * @param {int} initialCapacity optional defines the initial capacity of the list, it's empty by default - * - * @returns {ArrayList} new ArrayList object - */ -module.exports = function(options) { - var virtHashCode = options.virtHashCode, - virtEquals = options.virtEquals; - - function Iterator(array) { - var index = -1; - this.hasNext = function() { - return (index + 1) < array.length; - }; - - this.next = function() { - return array[++index]; - }; - - this.remove = function() { - array.splice(index--, 1); - }; - } - - function ArrayList(a) { - var array = []; - - if (a && a.toArray) { - array = a.toArray(); - } - - /** - * @member ArrayList - * ArrayList.get() Returns the element at the specified position in this list. - * - * @param {int} i index of element to return - * - * @returns {Object} the element at the specified position in this list. - */ - this.get = function(i) { - return array[i]; - }; - /** - * @member ArrayList - * ArrayList.contains() Returns true if this list contains the specified element. - * - * @param {Object} item element whose presence in this List is to be tested. - * - * @returns {boolean} true if the specified element is present; false otherwise. - */ - this.contains = function(item) { - return this.indexOf(item)>-1; - }; - /** - * @member ArrayList - * ArrayList.indexOf() Returns the position this element takes in the list, or -1 if the element is not found. - * - * @param {Object} item element whose position in this List is to be tested. - * - * @returns {int} the list position that the first match for this element holds in the list, or -1 if it is not in the list. - */ - this.indexOf = function(item) { - for (var i = 0, len = array.length; i < len; ++i) { - if (virtEquals(item, array[i])) { - return i; - } - } - return -1; - }; - /** - * @member ArrayList - * ArrayList.lastIndexOf() Returns the index of the last occurrence of the specified element in this list, - * or -1 if this list does not contain the element. More formally, returns the highest index i such that - * (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index. - * - * @param {Object} item element to search for. - * - * @returns {int} the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element. - */ - this.lastIndexOf = function(item) { - for (var i = array.length-1; i >= 0; --i) { - if (virtEquals(item, array[i])) { - return i; - } - } - return -1; - }; - /** - * @member ArrayList - * ArrayList.add() Adds the specified element to this list. - * - * @param {int} index optional index at which the specified element is to be inserted - * @param {Object} object element to be added to the list - */ - this.add = function() { - if (arguments.length === 1) { - array.push(arguments[0]); // for add(Object) - } else if (arguments.length === 2) { - var arg0 = arguments[0]; - if (typeof arg0 === 'number') { - if (arg0 >= 0 && arg0 <= array.length) { - array.splice(arg0, 0, arguments[1]); // for add(i, Object) - } else { - throw(arg0 + " is not a valid index"); - } - } else { - throw(typeof arg0 + " is not a number"); - } - } else { - throw("Please use the proper number of parameters."); - } - }; - /** - * @member ArrayList - * ArrayList.addAll(collection) appends all of the elements in the specified - * Collection to the end of this list, in the order that they are returned by - * the specified Collection's Iterator. - * - * When called as addAll(index, collection) the elements are inserted into - * this list at the position indicated by index. - * - * @param {index} Optional; specifies the position the colletion should be inserted at - * @param {collection} Any iterable object (ArrayList, HashMap.keySet(), etc.) - * @throws out of bounds error for negative index, or index greater than list size. - */ - this.addAll = function(arg1, arg2) { - // addAll(int, Collection) - var it; - if (typeof arg1 === "number") { - if (arg1 < 0 || arg1 > array.length) { - throw("Index out of bounds for addAll: " + arg1 + " greater or equal than " + array.length); - } - it = new ObjectIterator(arg2); - while (it.hasNext()) { - array.splice(arg1++, 0, it.next()); - } - } - // addAll(Collection) - else { - it = new ObjectIterator(arg1); - while (it.hasNext()) { - array.push(it.next()); - } - } - }; - /** - * @member ArrayList - * ArrayList.set() Replaces the element at the specified position in this list with the specified element. - * - * @param {int} index index of element to replace - * @param {Object} object element to be stored at the specified position - */ - this.set = function() { - if (arguments.length === 2) { - var arg0 = arguments[0]; - if (typeof arg0 === 'number') { - if (arg0 >= 0 && arg0 < array.length) { - array.splice(arg0, 1, arguments[1]); - } else { - throw(arg0 + " is not a valid index."); - } - } else { - throw(typeof arg0 + " is not a number"); - } - } else { - throw("Please use the proper number of parameters."); - } - }; - - /** - * @member ArrayList - * ArrayList.size() Returns the number of elements in this list. - * - * @returns {int} the number of elements in this list - */ - this.size = function() { - return array.length; - }; - - /** - * @member ArrayList - * ArrayList.clear() Removes all of the elements from this list. The list will be empty after this call returns. - */ - this.clear = function() { - array.length = 0; - }; - - /** - * @member ArrayList - * ArrayList.remove() Removes an element either based on index, if the argument is a number, or - * by equality check, if the argument is an object. - * - * @param {int|Object} item either the index of the element to be removed, or the element itself. - * - * @returns {Object|boolean} If removal is by index, the element that was removed, or null if nothing was removed. If removal is by object, true if removal occurred, otherwise false. - */ - this.remove = function(item) { - if (typeof item === 'number') { - return array.splice(item, 1)[0]; - } - item = this.indexOf(item); - if (item > -1) { - array.splice(item, 1); - return true; - } - return false; - }; - - /** - * @member ArrayList - * ArrayList.removeAll Removes from this List all of the elements from - * the current ArrayList which are present in the passed in paramater ArrayList 'c'. - * Shifts any succeeding elements to the left (reduces their index). - * - * @param {ArrayList} the ArrayList to compare to the current ArrayList - * - * @returns {boolean} true if the ArrayList had an element removed; false otherwise - */ - this.removeAll = function(c) { - var i, x, item, - newList = new ArrayList(); - newList.addAll(this); - this.clear(); - // For every item that exists in the original ArrayList and not in the c ArrayList - // copy it into the empty 'this' ArrayList to create the new 'this' Array. - for (i = 0, x = 0; i < newList.size(); i++) { - item = newList.get(i); - if (!c.contains(item)) { - this.add(x++, item); - } - } - if (this.size() < newList.size()) { - return true; - } - return false; - }; - - /** - * @member ArrayList - * ArrayList.isEmpty() Tests if this list has no elements. - * - * @returns {boolean} true if this list has no elements; false otherwise - */ - this.isEmpty = function() { - return !array.length; - }; - - /** - * @member ArrayList - * ArrayList.clone() Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.) - * - * @returns {ArrayList} a clone of this ArrayList instance - */ - this.clone = function() { - return new ArrayList(this); - }; - - /** - * @member ArrayList - * ArrayList.toArray() Returns an array containing all of the elements in this list in the correct order. - * - * @returns {Object[]} Returns an array containing all of the elements in this list in the correct order - */ - this.toArray = function() { - return array.slice(0); - }; - - this.iterator = function() { - return new Iterator(array); - }; - } - - return ArrayList; -}; - -},{}],11:[function(require,module,exports){ -module.exports = (function(charMap, undef) { - - var Char = function(chr) { - if (typeof chr === 'string' && chr.length === 1) { - this.code = chr.charCodeAt(0); - } else if (typeof chr === 'number') { - this.code = chr; - } else if (chr instanceof Char) { - this.code = chr; - } else { - this.code = NaN; - } - return (charMap[this.code] === undef) ? charMap[this.code] = this : charMap[this.code]; - }; - - Char.prototype.toString = function() { - return String.fromCharCode(this.code); - }; - - Char.prototype.valueOf = function() { - return this.code; - }; - - return Char; -}({})); - -},{}],12:[function(require,module,exports){ -/** -* A HashMap stores a collection of objects, each referenced by a key. This is similar to an Array, only -* instead of accessing elements with a numeric index, a String is used. (If you are familiar with -* associative arrays from other languages, this is the same idea.) -* -* @param {int} initialCapacity defines the initial capacity of the map, it's 16 by default -* @param {float} loadFactor the load factor for the map, the default is 0.75 -* @param {Map} m gives the new HashMap the same mappings as this Map -*/ -module.exports = function(options) { - var virtHashCode = options.virtHashCode, - virtEquals = options.virtEquals; - - /** - * @member HashMap - * A HashMap stores a collection of objects, each referenced by a key. This is similar to an Array, only - * instead of accessing elements with a numeric index, a String is used. (If you are familiar with - * associative arrays from other languages, this is the same idea.) - * - * @param {int} initialCapacity defines the initial capacity of the map, it's 16 by default - * @param {float} loadFactor the load factor for the map, the default is 0.75 - * @param {Map} m gives the new HashMap the same mappings as this Map - */ - function HashMap() { - if (arguments.length === 1 && arguments[0] instanceof HashMap) { - return arguments[0].clone(); - } - - var initialCapacity = arguments.length > 0 ? arguments[0] : 16; - var loadFactor = arguments.length > 1 ? arguments[1] : 0.75; - var buckets = []; - buckets.length = initialCapacity; - var count = 0; - var hashMap = this; - - function getBucketIndex(key) { - var index = virtHashCode(key) % buckets.length; - return index < 0 ? buckets.length + index : index; - } - function ensureLoad() { - if (count <= loadFactor * buckets.length) { - return; - } - var allEntries = []; - for (var i = 0; i < buckets.length; ++i) { - if (buckets[i] !== undefined) { - allEntries = allEntries.concat(buckets[i]); - } - } - var newBucketsLength = buckets.length * 2; - buckets = []; - buckets.length = newBucketsLength; - for (var j = 0; j < allEntries.length; ++j) { - var index = getBucketIndex(allEntries[j].key); - var bucket = buckets[index]; - if (bucket === undefined) { - buckets[index] = bucket = []; - } - bucket.push(allEntries[j]); - } - } - - function Iterator(conversion, removeItem) { - var bucketIndex = 0; - var itemIndex = -1; - var endOfBuckets = false; - var currentItem; - - function findNext() { - while (!endOfBuckets) { - ++itemIndex; - if (bucketIndex >= buckets.length) { - endOfBuckets = true; - } else if (buckets[bucketIndex] === undefined || itemIndex >= buckets[bucketIndex].length) { - itemIndex = -1; - ++bucketIndex; - } else { - return; - } - } - } - - /* - * @member Iterator - * Checks if the Iterator has more items - */ - this.hasNext = function() { - return !endOfBuckets; - }; - - /* - * @member Iterator - * Return the next Item - */ - this.next = function() { - currentItem = conversion(buckets[bucketIndex][itemIndex]); - findNext(); - return currentItem; - }; - - /* - * @member Iterator - * Remove the current item - */ - this.remove = function() { - if (currentItem !== undefined) { - removeItem(currentItem); - --itemIndex; - findNext(); - } - }; - - findNext(); - } - - function Set(conversion, isIn, removeItem) { - this.clear = function() { - hashMap.clear(); - }; - - this.contains = function(o) { - return isIn(o); - }; - - this.containsAll = function(o) { - var it = o.iterator(); - while (it.hasNext()) { - if (!this.contains(it.next())) { - return false; - } - } - return true; - }; - - this.isEmpty = function() { - return hashMap.isEmpty(); - }; - - this.iterator = function() { - return new Iterator(conversion, removeItem); - }; - - this.remove = function(o) { - if (this.contains(o)) { - removeItem(o); - return true; - } - return false; - }; - - this.removeAll = function(c) { - var it = c.iterator(); - var changed = false; - while (it.hasNext()) { - var item = it.next(); - if (this.contains(item)) { - removeItem(item); - changed = true; - } - } - return true; - }; - - this.retainAll = function(c) { - var it = this.iterator(); - var toRemove = []; - while (it.hasNext()) { - var entry = it.next(); - if (!c.contains(entry)) { - toRemove.push(entry); - } - } - for (var i = 0; i < toRemove.length; ++i) { - removeItem(toRemove[i]); - } - return toRemove.length > 0; - }; - - this.size = function() { - return hashMap.size(); - }; - - this.toArray = function() { - var result = []; - var it = this.iterator(); - while (it.hasNext()) { - result.push(it.next()); - } - return result; - }; - } - - function Entry(pair) { - this._isIn = function(map) { - return map === hashMap && (pair.removed === undefined); - }; - - this.equals = function(o) { - return virtEquals(pair.key, o.getKey()); - }; - - this.getKey = function() { - return pair.key; - }; - - this.getValue = function() { - return pair.value; - }; - - this.hashCode = function(o) { - return virtHashCode(pair.key); - }; - - this.setValue = function(value) { - var old = pair.value; - pair.value = value; - return old; - }; - } - - this.clear = function() { - count = 0; - buckets = []; - buckets.length = initialCapacity; - }; - - this.clone = function() { - var map = new HashMap(); - map.putAll(this); - return map; - }; - - this.containsKey = function(key) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undefined) { - return false; - } - for (var i = 0; i < bucket.length; ++i) { - if (virtEquals(bucket[i].key, key)) { - return true; - } - } - return false; - }; - - this.containsValue = function(value) { - for (var i = 0; i < buckets.length; ++i) { - var bucket = buckets[i]; - if (bucket === undefined) { - continue; - } - for (var j = 0; j < bucket.length; ++j) { - if (virtEquals(bucket[j].value, value)) { - return true; - } - } - } - return false; - }; - - this.entrySet = function() { - return new Set( - - function(pair) { - return new Entry(pair); - }, - - function(pair) { - return (pair instanceof Entry) && pair._isIn(hashMap); - }, - - function(pair) { - return hashMap.remove(pair.getKey()); - }); - }; - - this.get = function(key) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undefined) { - return null; - } - for (var i = 0; i < bucket.length; ++i) { - if (virtEquals(bucket[i].key, key)) { - return bucket[i].value; - } - } - return null; - }; - - this.isEmpty = function() { - return count === 0; - }; - - this.keySet = function() { - return new Set( - // get key from pair - function(pair) { - return pair.key; - }, - // is-in test - function(key) { - return hashMap.containsKey(key); - }, - // remove from hashmap by key - function(key) { - return hashMap.remove(key); - } - ); - }; - - this.values = function() { - return new Set( - // get value from pair - function(pair) { - return pair.value; - }, - // is-in test - function(value) { - return hashMap.containsValue(value); - }, - // remove from hashmap by value - function(value) { - return hashMap.removeByValue(value); - } - ); - }; - - this.put = function(key, value) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undefined) { - ++count; - buckets[index] = [{ - key: key, - value: value - }]; - ensureLoad(); - return null; - } - for (var i = 0; i < bucket.length; ++i) { - if (virtEquals(bucket[i].key, key)) { - var previous = bucket[i].value; - bucket[i].value = value; - return previous; - } - } - ++count; - bucket.push({ - key: key, - value: value - }); - ensureLoad(); - return null; - }; - - this.putAll = function(m) { - var it = m.entrySet().iterator(); - while (it.hasNext()) { - var entry = it.next(); - this.put(entry.getKey(), entry.getValue()); - } - }; - - this.remove = function(key) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undefined) { - return null; - } - for (var i = 0; i < bucket.length; ++i) { - if (virtEquals(bucket[i].key, key)) { - --count; - var previous = bucket[i].value; - bucket[i].removed = true; - if (bucket.length > 1) { - bucket.splice(i, 1); - } else { - buckets[index] = undefined; - } - return previous; - } - } - return null; - }; - - this.removeByValue = function(value) { - var bucket, i, ilen, pair; - for (bucket in buckets) { - if (buckets.hasOwnProperty(bucket)) { - for (i = 0, ilen = buckets[bucket].length; i < ilen; i++) { - pair = buckets[bucket][i]; - // removal on values is based on identity, not equality - if (pair.value === value) { - buckets[bucket].splice(i, 1); - return true; - } - } - } - } - return false; - }; - - this.size = function() { - return count; - }; - } - - return HashMap; -}; - -},{}],13:[function(require,module,exports){ -// module export -module.exports = function(options,undef) { - var window = options.Browser.window, - document = options.Browser.document, - noop = options.noop; - - /** - * [internal function] computeFontMetrics() calculates various metrics for text - * placement. Currently this function computes the ascent, descent and leading - * (from "lead", used for vertical space) values for the currently active font. - */ - function computeFontMetrics(pfont) { - var emQuad = 250, - correctionFactor = pfont.size / emQuad, - canvas = document.createElement("canvas"); - canvas.width = 2*emQuad; - canvas.height = 2*emQuad; - canvas.style.opacity = 0; - var cfmFont = pfont.getCSSDefinition(emQuad+"px", "normal"), - ctx = canvas.getContext("2d"); - ctx.font = cfmFont; - - // Size the canvas using a string with common max-ascent and max-descent letters. - // Changing the canvas dimensions resets the context, so we must reset the font. - var protrusions = "dbflkhyjqpg"; - canvas.width = ctx.measureText(protrusions).width; - ctx.font = cfmFont; - - // for text lead values, we meaure a multiline text container. - var leadDiv = document.createElement("div"); - leadDiv.style.position = "absolute"; - leadDiv.style.opacity = 0; - leadDiv.style.fontFamily = '"' + pfont.name + '"'; - leadDiv.style.fontSize = emQuad + "px"; - leadDiv.innerHTML = protrusions + "<br/>" + protrusions; - document.body.appendChild(leadDiv); - - var w = canvas.width, - h = canvas.height, - baseline = h/2; - - // Set all canvas pixeldata values to 255, with all the content - // data being 0. This lets us scan for data[i] != 255. - ctx.fillStyle = "white"; - ctx.fillRect(0, 0, w, h); - ctx.fillStyle = "black"; - ctx.fillText(protrusions, 0, baseline); - var pixelData = ctx.getImageData(0, 0, w, h).data; - - // canvas pixel data is w*4 by h*4, because R, G, B and A are separate, - // consecutive values in the array, rather than stored as 32 bit ints. - var i = 0, - w4 = w * 4, - len = pixelData.length; - - // Finding the ascent uses a normal, forward scanline - while (++i < len && pixelData[i] === 255) { - noop(); - } - var ascent = Math.round(i / w4); - - // Finding the descent uses a reverse scanline - i = len - 1; - while (--i > 0 && pixelData[i] === 255) { - noop(); - } - var descent = Math.round(i / w4); - - // set font metrics - pfont.ascent = correctionFactor * (baseline - ascent); - pfont.descent = correctionFactor * (descent - baseline); - - // Then we try to get the real value from the browser - if (document.defaultView.getComputedStyle) { - var leadDivHeight = document.defaultView.getComputedStyle(leadDiv,null).getPropertyValue("height"); - leadDivHeight = correctionFactor * leadDivHeight.replace("px",""); - if (leadDivHeight >= pfont.size * 2) { - pfont.leading = Math.round(leadDivHeight/2); - } - } - document.body.removeChild(leadDiv); - - // if we're caching, cache the context used for this pfont - if (pfont.caching) { - return ctx; - } - } - - /** - * Constructor for a system or from-file (non-SVG) font. - */ - function PFont(name, size) { - // according to the P5 API, new PFont() is legal (albeit completely useless) - if (name === undef) { - name = ""; - } - this.name = name; - if (size === undef) { - size = 0; - } - this.size = size; - this.glyph = false; - this.ascent = 0; - this.descent = 0; - // For leading, the "safe" value uses the standard TEX ratio - this.leading = 1.2 * size; - - // Note that an italic, bold font must used "... Bold Italic" - // in P5. "... Italic Bold" is treated as normal/normal. - var illegalIndicator = name.indexOf(" Italic Bold"); - if (illegalIndicator !== -1) { - name = name.substring(0, illegalIndicator); - } - - // determine font style - this.style = "normal"; - var italicsIndicator = name.indexOf(" Italic"); - if (italicsIndicator !== -1) { - name = name.substring(0, italicsIndicator); - this.style = "italic"; - } - - // determine font weight - this.weight = "normal"; - var boldIndicator = name.indexOf(" Bold"); - if (boldIndicator !== -1) { - name = name.substring(0, boldIndicator); - this.weight = "bold"; - } - - // determine font-family name - this.family = "sans-serif"; - if (name !== undef) { - switch(name) { - case "sans-serif": - case "serif": - case "monospace": - case "fantasy": - case "cursive": - this.family = name; - break; - default: - this.family = '"' + name + '", sans-serif'; - break; - } - } - // Calculate the ascent/descent/leading value based on - // how the browser renders this font. - this.context2d = computeFontMetrics(this); - this.css = this.getCSSDefinition(); - if (this.context2d) { - this.context2d.font = this.css; - } - } - - /** - * regulates whether or not we're caching the canvas - * 2d context for quick text width computation. - */ - PFont.prototype.caching = true; - - /** - * This function generates the CSS "font" string for this PFont - */ - PFont.prototype.getCSSDefinition = function(fontSize, lineHeight) { - if(fontSize===undef) { - fontSize = this.size + "px"; - } - if(lineHeight===undef) { - lineHeight = this.leading + "px"; - } - // CSS "font" definition: font-style font-variant font-weight font-size/line-height font-family - var components = [this.style, "normal", this.weight, fontSize + "/" + lineHeight, this.family]; - return components.join(" "); - }; - - /** - * Rely on the cached context2d measureText function. - */ - PFont.prototype.measureTextWidth = function(string) { - return this.context2d.measureText(string).width; - }; - - /** - * FALLBACK FUNCTION -- replaces Pfont.prototype.measureTextWidth - * when the font cache becomes too large. This contructs a new - * canvas 2d context object for calling measureText on. - */ - PFont.prototype.measureTextWidthFallback = function(string) { - var canvas = document.createElement("canvas"), - ctx = canvas.getContext("2d"); - ctx.font = this.css; - return ctx.measureText(string).width; - }; - - /** - * Global "loaded fonts" list, internal to PFont - */ - PFont.PFontCache = { length: 0 }; - - /** - * This function acts as single access point for getting and caching - * fonts across all sketches handled by an instance of Processing.js - */ - PFont.get = function(fontName, fontSize) { - // round fontSize to one decimal point - fontSize = ((fontSize*10)+0.5|0)/10; - var cache = PFont.PFontCache, - idx = fontName+"/"+fontSize; - if (!cache[idx]) { - cache[idx] = new PFont(fontName, fontSize); - cache.length++; - - // FALLBACK FUNCTIONALITY 1: - // If the cache has become large, switch over from full caching - // to caching only the static metrics for each new font request. - if (cache.length === 50) { - PFont.prototype.measureTextWidth = PFont.prototype.measureTextWidthFallback; - PFont.prototype.caching = false; - // clear contexts stored for each cached font - var entry; - for (entry in cache) { - if (entry !== "length") { - cache[entry].context2d = null; - } - } - return new PFont(fontName, fontSize); - } - - // FALLBACK FUNCTIONALITY 2: - // If the cache has become too large, switch off font caching entirely. - if (cache.length === 400) { - PFont.PFontCache = {}; - PFont.get = PFont.getFallback; - return new PFont(fontName, fontSize); - } - } - return cache[idx]; - }; - - /** - * FALLBACK FUNCTION -- replaces PFont.get when the font cache - * becomes too large. This function bypasses font caching entirely. - */ - PFont.getFallback = function(fontName, fontSize) { - return new PFont(fontName, fontSize); - }; - - /** - * Lists all standard fonts. Due to browser limitations, this list is - * not the system font list, like in P5, but the CSS "genre" list. - */ - PFont.list = function() { - return ["sans-serif", "serif", "monospace", "fantasy", "cursive"]; - }; - - /** - * Loading external fonts through @font-face rules is handled by PFont, - * to ensure fonts loaded in this way are globally available. - */ - PFont.preloading = { - // template element used to compare font sizes - template: {}, - // indicates whether or not the reference tiny font has been loaded - initialized: false, - // load the reference tiny font via a css @font-face rule - initialize: function() { - var generateTinyFont = function() { - var encoded = "#E3KAI2wAgT1MvMg7Eo3VmNtYX7ABi3CxnbHlm" + - "7Abw3kaGVhZ7ACs3OGhoZWE7A53CRobXR47AY3" + - "AGbG9jYQ7G03Bm1heH7ABC3CBuYW1l7Ae3AgcG" + - "9zd7AI3AE#B3AQ2kgTY18PPPUACwAg3ALSRoo3" + - "#yld0xg32QAB77#E777773B#E3C#I#Q77773E#" + - "Q7777777772CMAIw7AB77732B#M#Q3wAB#g3B#" + - "E#E2BB//82BB////w#B7#gAEg3E77x2B32B#E#" + - "Q#MTcBAQ32gAe#M#QQJ#E32M#QQJ#I#g32Q77#"; - var expand = function(input) { - return "AAAAAAAA".substr(~~input ? 7-input : 6); - }; - return encoded.replace(/[#237]/g, expand); - }; - var fontface = document.createElement("style"); - fontface.setAttribute("type","text/css"); - fontface.innerHTML = "@font-face {\n" + - ' font-family: "PjsEmptyFont";' + "\n" + - " src: url('data:application/x-font-ttf;base64,"+generateTinyFont()+"')\n" + - " format('truetype');\n" + - "}"; - document.head.appendChild(fontface); - - // set up the template element - var element = document.createElement("span"); - element.style.cssText = 'position: absolute; top: -1000; left: 0; opacity: 0; font-family: "PjsEmptyFont", fantasy;'; - element.innerHTML = "AAAAAAAA"; - document.body.appendChild(element); - this.template = element; - - this.initialized = true; - }, - // Shorthand function to get the computed width for an element. - getElementWidth: function(element) { - return document.defaultView.getComputedStyle(element,"").getPropertyValue("width"); - }, - // time taken so far in attempting to load a font - timeAttempted: 0, - // returns false if no fonts are pending load, or true otherwise. - pending: function(intervallength) { - if (!this.initialized) { - this.initialize(); - } - var element, - computedWidthFont, - computedWidthRef = this.getElementWidth(this.template); - for (var i = 0; i < this.fontList.length; i++) { - // compares size of text in pixels. if equal, custom font is not yet loaded - element = this.fontList[i]; - computedWidthFont = this.getElementWidth(element); - if (this.timeAttempted < 4000 && computedWidthFont === computedWidthRef) { - this.timeAttempted += intervallength; - return true; - } else { - document.body.removeChild(element); - this.fontList.splice(i--, 1); - this.timeAttempted = 0; - } - } - // if there are no more fonts to load, pending is false - if (this.fontList.length === 0) { - return false; - } - // We should have already returned before getting here. - // But, if we do get here, length!=0 so fonts are pending. - return true; - }, - // fontList contains elements to compare font sizes against a template - fontList: [], - // addedList contains the fontnames of all the fonts loaded via @font-face - addedList: {}, - // adds a font to the font cache - // creates an element using the font, to start loading the font, - // and compare against a default font to see if the custom font is loaded - add: function(fontSrc) { - if (!this.initialized) { - this.initialize(); - } - // fontSrc can be a string or a javascript object - // acceptable fonts are .ttf, .otf, and data uri - var fontName = (typeof fontSrc === 'object' ? fontSrc.fontFace : fontSrc), - fontUrl = (typeof fontSrc === 'object' ? fontSrc.url : fontSrc); - - // check whether we already created the @font-face rule for this font - if (this.addedList[fontName]) { - return; - } - - // if we didn't, create the @font-face rule - var style = document.createElement("style"); - style.setAttribute("type","text/css"); - style.innerHTML = "@font-face{\n font-family: '" + fontName + "';\n src: url('" + fontUrl + "');\n}\n"; - document.head.appendChild(style); - this.addedList[fontName] = true; - - // also create the element to load and compare the new font - var element = document.createElement("span"); - element.style.cssText = "position: absolute; top: 0; left: 0; opacity: 0;"; - element.style.fontFamily = '"' + fontName + '", "PjsEmptyFont", fantasy'; - element.innerHTML = "AAAAAAAA"; - document.body.appendChild(element); - this.fontList.push(element); - } - }; - - return PFont; -}; -},{}],14:[function(require,module,exports){ -module.exports = function(options, undef) { - - // FIXME: hack - var p = options.p; - - /** - * PMatrix2D is a 3x2 affine matrix implementation. The constructor accepts another PMatrix2D or a list of six float elements. - * If no parameters are provided the matrix is set to the identity matrix. - * - * @param {PMatrix2D} matrix the initial matrix to set to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fifth element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - var PMatrix2D = function() { - if (arguments.length === 0) { - this.reset(); - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - this.set(arguments[0].array()); - } else if (arguments.length === 6) { - this.set(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); - } - }; - - /** - * PMatrix2D methods - */ - PMatrix2D.prototype = { - /** - * @member PMatrix2D - * The set() function sets the matrix elements. The function accepts either another PMatrix2D, an array of elements, or a list of six floats. - * - * @param {PMatrix2D} matrix the matrix to set this matrix to - * @param {float[]} elements an array of elements to set this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fith element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - set: function() { - if (arguments.length === 6) { - var a = arguments; - this.set([a[0], a[1], a[2], - a[3], a[4], a[5]]); - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - this.elements = arguments[0].array(); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - this.elements = arguments[0].slice(); - } - }, - /** - * @member PMatrix2D - * The get() function returns a copy of this PMatrix2D. - * - * @return {PMatrix2D} a copy of this PMatrix2D - */ - get: function() { - var outgoing = new PMatrix2D(); - outgoing.set(this.elements); - return outgoing; - }, - /** - * @member PMatrix2D - * The reset() function sets this PMatrix2D to the identity matrix. - */ - reset: function() { - this.set([1, 0, 0, 0, 1, 0]); - }, - /** - * @member PMatrix2D - * The array() function returns a copy of the element values. - * @addon - * - * @return {float[]} returns a copy of the element values - */ - array: function array() { - return this.elements.slice(); - }, - /** - * @member PMatrix2D - * The translate() function translates this matrix by moving the current coordinates to the location specified by tx and ty. - * - * @param {float} tx the x-axis coordinate to move to - * @param {float} ty the y-axis coordinate to move to - */ - translate: function(tx, ty) { - this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this.elements[2]; - this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this.elements[5]; - }, - /** - * @member PMatrix2D - * The invTranslate() function translates this matrix by moving the current coordinates to the negative location specified by tx and ty. - * - * @param {float} tx the x-axis coordinate to move to - * @param {float} ty the y-axis coordinate to move to - */ - invTranslate: function(tx, ty) { - this.translate(-tx, -ty); - }, - /** - * @member PMatrix2D - * The transpose() function is not used in processingjs. - */ - transpose: function() { - // Does nothing in Processing. - }, - /** - * @member PMatrix2D - * The mult() function multiplied this matrix. - * If two array elements are passed in the function will multiply a two element vector against this matrix. - * If target is null or not length four, a new float array will be returned. - * The values for vec and target can be the same (though that's less efficient). - * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix. - * - * @param {PVector} source, target the PVectors used to multiply this matrix - * @param {float[]} source, target the arrays used to multiply this matrix - * - * @return {PVector|float[]} returns a PVector or an array representing the new matrix - */ - mult: function(source, target) { - var x, y; - if (source instanceof PVector) { - x = source.x; - y = source.y; - if (!target) { - target = new PVector(); - } - } else if (source instanceof Array) { - x = source[0]; - y = source[1]; - if (!target) { - target = []; - } - } - if (target instanceof Array) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2]; - target[1] = this.elements[3] * x + this.elements[4] * y + this.elements[5]; - } else if (target instanceof PVector) { - target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2]; - target.y = this.elements[3] * x + this.elements[4] * y + this.elements[5]; - target.z = 0; - } - return target; - }, - /** - * @member PMatrix2D - * The multX() function calculates the x component of a vector from a transformation. - * - * @param {float} x the x component of the vector being transformed - * @param {float} y the y component of the vector being transformed - * - * @return {float} returnes the result of the calculation - */ - multX: function(x, y) { - return (x * this.elements[0] + y * this.elements[1] + this.elements[2]); - }, - /** - * @member PMatrix2D - * The multY() function calculates the y component of a vector from a transformation. - * - * @param {float} x the x component of the vector being transformed - * @param {float} y the y component of the vector being transformed - * - * @return {float} returnes the result of the calculation - */ - multY: function(x, y) { - return (x * this.elements[3] + y * this.elements[4] + this.elements[5]); - }, - /** - * @member PMatrix2D - * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewX: function(angle) { - this.apply(1, 0, 1, angle, 0, 0); - }, - /** - * @member PMatrix2D - * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewY: function(angle) { - this.apply(1, 0, 1, 0, angle, 0); - }, - /** - * @member PMatrix2D - * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - shearX: function(angle) { - this.apply(1, 0, 1, Math.tan(angle) , 0, 0); - }, - /** - * @member PMatrix2D - * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - shearY: function(angle) { - this.apply(1, 0, 1, 0, Math.tan(angle), 0); - }, - /** - * @member PMatrix2D - * The determinant() function calvculates the determinant of this matrix. - * - * @return {float} the determinant of the matrix - */ - determinant: function() { - return (this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3]); - }, - /** - * @member PMatrix2D - * The invert() function inverts this matrix - * - * @return {boolean} true if successful - */ - invert: function() { - var d = this.determinant(); - if (Math.abs( d ) > PConstants.MIN_INT) { - var old00 = this.elements[0]; - var old01 = this.elements[1]; - var old02 = this.elements[2]; - var old10 = this.elements[3]; - var old11 = this.elements[4]; - var old12 = this.elements[5]; - this.elements[0] = old11 / d; - this.elements[3] = -old10 / d; - this.elements[1] = -old01 / d; - this.elements[4] = old00 / d; - this.elements[2] = (old01 * old12 - old11 * old02) / d; - this.elements[5] = (old10 * old02 - old00 * old12) / d; - return true; - } - return false; - }, - /** - * @member PMatrix2D - * The scale() function increases or decreases the size of a shape by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions. - * This is equivalent to a two parameter call. - * - * @param {float} sx the amount to scale on the x-axis - * @param {float} sy the amount to scale on the y-axis - */ - scale: function(sx, sy) { - if (sx && !sy) { - sy = sx; - } - if (sx && sy) { - this.elements[0] *= sx; - this.elements[1] *= sy; - this.elements[3] *= sx; - this.elements[4] *= sy; - } - }, - /** - * @member PMatrix2D - * The invScale() function decreases or increases the size of a shape by contracting and expanding vertices. When only one parameter is specified scale will occur in all dimensions. - * This is equivalent to a two parameter call. - * - * @param {float} sx the amount to scale on the x-axis - * @param {float} sy the amount to scale on the y-axis - */ - invScale: function(sx, sy) { - if (sx && !sy) { - sy = sx; - } - this.scale(1 / sx, 1 / sy); - }, - /** - * @member PMatrix2D - * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix2D or a list of floats can be passed in. - * - * @param {PMatrix2D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fith element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - apply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - source = arguments[0].array(); - } else if (arguments.length === 6) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - - var result = [0, 0, this.elements[2], - 0, 0, this.elements[5]]; - var e = 0; - for (var row = 0; row < 2; row++) { - for (var col = 0; col < 3; col++, e++) { - result[e] += this.elements[row * 3 + 0] * source[col + 0] + - this.elements[row * 3 + 1] * source[col + 3]; - } - } - this.elements = result.slice(); - }, - /** - * @member PMatrix2D - * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix2D or elements of a matrix can be passed in. - * - * @param {PMatrix2D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fith element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - preApply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - source = arguments[0].array(); - } else if (arguments.length === 6) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - var result = [0, 0, source[2], - 0, 0, source[5]]; - result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1]; - result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4]; - result[0] = this.elements[0] * source[0] + this.elements[3] * source[1]; - result[3] = this.elements[0] * source[3] + this.elements[3] * source[4]; - result[1] = this.elements[1] * source[0] + this.elements[4] * source[1]; - result[4] = this.elements[1] * source[3] + this.elements[4] * source[4]; - this.elements = result.slice(); - }, - /** - * @member PMatrix2D - * The rotate() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotate: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - var temp1 = this.elements[0]; - var temp2 = this.elements[1]; - this.elements[0] = c * temp1 + s * temp2; - this.elements[1] = -s * temp1 + c * temp2; - temp1 = this.elements[3]; - temp2 = this.elements[4]; - this.elements[3] = c * temp1 + s * temp2; - this.elements[4] = -s * temp1 + c * temp2; - }, - /** - * @member PMatrix2D - * The rotateZ() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateZ: function(angle) { - this.rotate(angle); - }, - /** - * @member PMatrix2D - * The invRotateZ() function rotates the matrix in opposite direction. - * - * @param {float} angle the angle of rotation in radiants - */ - invRotateZ: function(angle) { - this.rotateZ(angle - Math.PI); - }, - /** - * @member PMatrix2D - * The print() function prints out the elements of this matrix - */ - print: function() { - var digits = printMatrixHelper(this.elements); - var output = "" + p.nfs(this.elements[0], digits, 4) + " " + - p.nfs(this.elements[1], digits, 4) + " " + - p.nfs(this.elements[2], digits, 4) + "\n" + - p.nfs(this.elements[3], digits, 4) + " " + - p.nfs(this.elements[4], digits, 4) + " " + - p.nfs(this.elements[5], digits, 4) + "\n\n"; - p.println(output); - } - }; - - return PMatrix2D; -}; - -},{}],15:[function(require,module,exports){ -module.exports = function(options, undef) { - - // FIXME: hack - var p = options.p; - - /** - * PMatrix3D is a 4x4 matrix implementation. The constructor accepts another PMatrix3D or a list of six or sixteen float elements. - * If no parameters are provided the matrix is set to the identity matrix. - */ - var PMatrix3D = function() { - // When a matrix is created, it is set to an identity matrix - this.reset(); - }; - - /** - * PMatrix3D methods - */ - PMatrix3D.prototype = { - /** - * @member PMatrix2D - * The set() function sets the matrix elements. The function accepts either another PMatrix3D, an array of elements, or a list of six or sixteen floats. - * - * @param {PMatrix3D} matrix the initial matrix to set to - * @param {float[]} elements an array of elements to set this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - */ - set: function() { - if (arguments.length === 16) { - this.elements = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) { - this.elements = arguments[0].array(); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - this.elements = arguments[0].slice(); - } - }, - /** - * @member PMatrix3D - * The get() function returns a copy of this PMatrix3D. - * - * @return {PMatrix3D} a copy of this PMatrix3D - */ - get: function() { - var outgoing = new PMatrix3D(); - outgoing.set(this.elements); - return outgoing; - }, - /** - * @member PMatrix3D - * The reset() function sets this PMatrix3D to the identity matrix. - */ - reset: function() { - this.elements = [1,0,0,0, - 0,1,0,0, - 0,0,1,0, - 0,0,0,1]; - }, - /** - * @member PMatrix3D - * The array() function returns a copy of the element values. - * @addon - * - * @return {float[]} returns a copy of the element values - */ - array: function array() { - return this.elements.slice(); - }, - /** - * @member PMatrix3D - * The translate() function translates this matrix by moving the current coordinates to the location specified by tx, ty, and tz. - * - * @param {float} tx the x-axis coordinate to move to - * @param {float} ty the y-axis coordinate to move to - * @param {float} tz the z-axis coordinate to move to - */ - translate: function(tx, ty, tz) { - if (tz === undef) { - tz = 0; - } - - this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2]; - this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6]; - this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10]; - this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + tz * this.elements[14]; - }, - /** - * @member PMatrix3D - * The transpose() function transpose this matrix. - */ - transpose: function() { - var temp = this.elements[4]; - this.elements[4] = this.elements[1]; - this.elements[1] = temp; - - temp = this.elements[8]; - this.elements[8] = this.elements[2]; - this.elements[2] = temp; - - temp = this.elements[6]; - this.elements[6] = this.elements[9]; - this.elements[9] = temp; - - temp = this.elements[3]; - this.elements[3] = this.elements[12]; - this.elements[12] = temp; - - temp = this.elements[7]; - this.elements[7] = this.elements[13]; - this.elements[13] = temp; - - temp = this.elements[11]; - this.elements[11] = this.elements[14]; - this.elements[14] = temp; - }, - /** - * @member PMatrix3D - * The mult() function multiplied this matrix. - * If two array elements are passed in the function will multiply a two element vector against this matrix. - * If target is null or not length four, a new float array will be returned. - * The values for vec and target can be the same (though that's less efficient). - * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix. - * - * @param {PVector} source, target the PVectors used to multiply this matrix - * @param {float[]} source, target the arrays used to multiply this matrix - * - * @return {PVector|float[]} returns a PVector or an array representing the new matrix - */ - mult: function(source, target) { - var x, y, z, w; - if (source instanceof PVector) { - x = source.x; - y = source.y; - z = source.z; - w = 1; - if (!target) { - target = new PVector(); - } - } else if (source instanceof Array) { - x = source[0]; - y = source[1]; - z = source[2]; - w = source[3] || 1; - - if ( !target || (target.length !== 3 && target.length !== 4) ) { - target = [0, 0, 0]; - } - } - - if (target instanceof Array) { - if (target.length === 3) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - } else if (target.length === 4) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w; - target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w; - target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w; - target[3] = this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w; - } - } - if (target instanceof PVector) { - target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - target.y = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - target.z = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - } - return target; - }, - /** - * @member PMatrix3D - * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix3D or elements of a matrix can be passed in. - * - * @param {PMatrix3D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - */ - preApply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) { - source = arguments[0].array(); - } else if (arguments.length === 16) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - - var result = [0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0]; - var e = 0; - for (var row = 0; row < 4; row++) { - for (var col = 0; col < 4; col++, e++) { - result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] * - source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] + - this.elements[col + 12] * source[row * 4 + 3]; - } - } - this.elements = result.slice(); - }, - /** - * @member PMatrix3D - * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix3D or a list of floats can be passed in. - * - * @param {PMatrix3D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - */ - apply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) { - source = arguments[0].array(); - } else if (arguments.length === 16) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - - var result = [0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0]; - var e = 0; - for (var row = 0; row < 4; row++) { - for (var col = 0; col < 4; col++, e++) { - result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] * - source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] + - this.elements[row * 4 + 3] * source[col + 12]; - } - } - this.elements = result.slice(); - }, - /** - * @member PMatrix3D - * The rotate() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotate: function(angle, v0, v1, v2) { - if (!v1) { - this.rotateZ(angle); - } else { - // TODO should make sure this vector is normalized - var c = Math.cos(angle); - var s = Math.sin(angle); - var t = 1.0 - c; - - this.apply((t * v0 * v0) + c, - (t * v0 * v1) - (s * v2), - (t * v0 * v2) + (s * v1), - 0, - (t * v0 * v1) + (s * v2), - (t * v1 * v1) + c, - (t * v1 * v2) - (s * v0), - 0, - (t * v0 * v2) - (s * v1), - (t * v1 * v2) + (s * v0), - (t * v2 * v2) + c, - 0, - 0, 0, 0, 1); - } - }, - /** - * @member PMatrix3D - * The invApply() function applies the inverted matrix to this matrix. - * - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - * - * @return {boolean} returns true if the operation was successful. - */ - invApply: function() { - if (inverseCopy === undef) { - inverseCopy = new PMatrix3D(); - } - var a = arguments; - inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], - a[9], a[10], a[11], a[12], a[13], a[14], a[15]); - - if (!inverseCopy.invert()) { - return false; - } - this.preApply(inverseCopy); - return true; - }, - /** - * @member PMatrix3D - * The rotateZ() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateX: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]); - }, - /** - * @member PMatrix3D - * The rotateY() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateY: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - this.apply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]); - }, - /** - * @member PMatrix3D - * The rotateZ() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateZ: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); - }, - /** - * @member PMatrix3D - * The scale() function increases or decreases the size of a matrix by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions. - * This is equivalent to a three parameter call. - * - * @param {float} sx the amount to scale on the x-axis - * @param {float} sy the amount to scale on the y-axis - * @param {float} sz the amount to scale on the z-axis - */ - scale: function(sx, sy, sz) { - if (sx && !sy && !sz) { - sy = sz = sx; - } else if (sx && sy && !sz) { - sz = 1; - } - - if (sx && sy && sz) { - this.elements[0] *= sx; - this.elements[1] *= sy; - this.elements[2] *= sz; - this.elements[4] *= sx; - this.elements[5] *= sy; - this.elements[6] *= sz; - this.elements[8] *= sx; - this.elements[9] *= sy; - this.elements[10] *= sz; - this.elements[12] *= sx; - this.elements[13] *= sy; - this.elements[14] *= sz; - } - }, - /** - * @member PMatrix3D - * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewX: function(angle) { - var t = Math.tan(angle); - this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - /** - * @member PMatrix3D - * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewY: function(angle) { - var t = Math.tan(angle); - this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - /** - * @member PMatrix3D - * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of shear specified in radians - */ - shearX: function(angle) { - var t = Math.tan(angle); - this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - /** - * @member PMatrix3D - * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of shear specified in radians - */ - shearY: function(angle) { - var t = Math.tan(angle); - this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - multX: function(x, y, z, w) { - if (!z) { - return this.elements[0] * x + this.elements[1] * y + this.elements[3]; - } - if (!w) { - return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - } - return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w; - }, - multY: function(x, y, z, w) { - if (!z) { - return this.elements[4] * x + this.elements[5] * y + this.elements[7]; - } - if (!w) { - return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - } - return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w; - }, - multZ: function(x, y, z, w) { - if (!w) { - return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - } - return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w; - }, - multW: function(x, y, z, w) { - if (!w) { - return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15]; - } - return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w; - }, - /** - * @member PMatrix3D - * The invert() function inverts this matrix - * - * @return {boolean} true if successful - */ - invert: function() { - var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this.elements[4]; - var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this.elements[4]; - var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this.elements[4]; - var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this.elements[5]; - var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this.elements[5]; - var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this.elements[6]; - var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this.elements[12]; - var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * this.elements[12]; - var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * this.elements[12]; - var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * this.elements[13]; - var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * this.elements[13]; - var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * this.elements[14]; - - // Determinant - var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0; - - // Account for a very small value - // return false if not successful. - if (Math.abs(fDet) <= 1e-9) { - return false; - } - - var kInv = []; - kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elements[7] * fB3; - kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elements[7] * fB1; - kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elements[7] * fB0; - kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.elements[6] * fB0; - kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elements[3] * fB3; - kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elements[3] * fB1; - kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elements[3] * fB0; - kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.elements[2] * fB0; - kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elements[15] * fA3; - kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elements[15] * fA1; - kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.elements[15] * fA0; - kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.elements[14] * fA0; - kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.elements[11] * fA3; - kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.elements[11] * fA1; - kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.elements[11] * fA0; - kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.elements[10] * fA0; - - // Inverse using Determinant - var fInvDet = 1.0 / fDet; - kInv[0] *= fInvDet; - kInv[1] *= fInvDet; - kInv[2] *= fInvDet; - kInv[3] *= fInvDet; - kInv[4] *= fInvDet; - kInv[5] *= fInvDet; - kInv[6] *= fInvDet; - kInv[7] *= fInvDet; - kInv[8] *= fInvDet; - kInv[9] *= fInvDet; - kInv[10] *= fInvDet; - kInv[11] *= fInvDet; - kInv[12] *= fInvDet; - kInv[13] *= fInvDet; - kInv[14] *= fInvDet; - kInv[15] *= fInvDet; - - this.elements = kInv.slice(); - return true; - }, - toString: function() { - var str = ""; - for (var i = 0; i < 15; i++) { - str += this.elements[i] + ", "; - } - str += this.elements[15]; - return str; - }, - /** - * @member PMatrix3D - * The print() function prints out the elements of this matrix - */ - print: function() { - var digits = printMatrixHelper(this.elements); - - var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) + - " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs(this.elements[3], digits, 4) + - "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + - " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) + - "\n" + p.nfs(this.elements[8], digits, 4) + " " + p.nfs(this.elements[9], digits, 4) + - " " + p.nfs(this.elements[10], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) + - "\n" + p.nfs(this.elements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) + - " " + p.nfs(this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n\n"; - p.println(output); - }, - invTranslate: function(tx, ty, tz) { - this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1); - }, - invRotateX: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]); - }, - invRotateY: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]); - }, - invRotateZ: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); - }, - invScale: function(x, y, z) { - this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]); - } - }; - - return PMatrix3D; -}; -},{}],16:[function(require,module,exports){ -module.exports = function(options) { - var PConstants = options.PConstants, - PMatrix2D = options.PMatrix2D, - PMatrix3D = options.PMatrix3D; - - /** - * Datatype for storing shapes. Processing can currently load and display SVG (Scalable Vector Graphics) shapes. - * Before a shape is used, it must be loaded with the <b>loadShape()</b> function. The <b>shape()</b> function is used to draw the shape to the display window. - * The <b>PShape</b> object contain a group of methods, linked below, that can operate on the shape data. - * <br><br>The <b>loadShape()</b> method supports SVG files created with Inkscape and Adobe Illustrator. - * It is not a full SVG implementation, but offers some straightforward support for handling vector data. - * - * @param {int} family the shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY - * - * @see #shape() - * @see #loadShape() - * @see #shapeMode() - */ - var PShape = function(family) { - this.family = family || PConstants.GROUP; - this.visible = true; - this.style = true; - this.children = []; - this.nameTable = []; - this.params = []; - this.name = ""; - this.image = null; //type PImage - this.matrix = null; - this.kind = null; - this.close = null; - this.width = null; - this.height = null; - this.parent = null; - }; - /** - * PShape methods - * missing: findChild(), apply(), contains(), findChild(), getPrimitive(), getParams(), getVertex() , getVertexCount(), - * getVertexCode() , getVertexCodes() , getVertexCodeCount(), getVertexX(), getVertexY(), getVertexZ() - */ - PShape.prototype = { - /** - * @member PShape - * The isVisible() function returns a boolean value "true" if the image is set to be visible, "false" if not. This is modified with the <b>setVisible()</b> parameter. - * <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file. - * For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator. - * - * @return {boolean} returns "true" if the image is set to be visible, "false" if not - */ - isVisible: function(){ - return this.visible; - }, - /** - * @member PShape - * The setVisible() function sets the shape to be visible or invisible. This is determined by the value of the <b>visible</b> parameter. - * <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file. - * For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator. - * - * @param {boolean} visible "false" makes the shape invisible and "true" makes it visible - */ - setVisible: function (visible){ - this.visible = visible; - }, - /** - * @member PShape - * The disableStyle() function disables the shape's style data and uses Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints. - * Overrides this shape's style information and uses PGraphics styles and colors. Identical to ignoreStyles(true). Also disables styles for all child shapes. - */ - disableStyle: function(){ - this.style = false; - for(var i = 0, j=this.children.length; i<j; i++) { - this.children[i].disableStyle(); - } - }, - /** - * @member PShape - * The enableStyle() function enables the shape's style data and ignores Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints. - */ - enableStyle: function(){ - this.style = true; - for(var i = 0, j=this.children.length; i<j; i++) { - this.children[i].enableStyle(); - } - }, - /** - * @member PShape - * The getFamily function returns the shape type - * - * @return {int} the shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY - */ - getFamily: function(){ - return this.family; - }, - /** - * @member PShape - * The getWidth() function gets the width of the drawing area (not necessarily the shape boundary). - */ - getWidth: function(){ - return this.width; - }, - /** - * @member PShape - * The getHeight() function gets the height of the drawing area (not necessarily the shape boundary). - */ - getHeight: function(){ - return this.height; - }, - /** - * @member PShape - * The setName() function sets the name of the shape - * - * @param {String} name the name of the shape - */ - setName: function(name){ - this.name = name; - }, - /** - * @member PShape - * The getName() function returns the name of the shape - * - * @return {String} the name of the shape - */ - getName: function(){ - return this.name; - }, - /** - * @member PShape - * Called by the following (the shape() command adds the g) - * PShape s = loadShapes("blah.svg"); - * shape(s); - */ - draw: function(renderContext) { - if(!renderContext) { - throw "render context missing for draw() in PShape"; - } - if (this.visible) { - this.pre(renderContext); - this.drawImpl(renderContext); - this.post(renderContext); - } - }, - /** - * @member PShape - * the drawImpl() function draws the SVG document. - */ - drawImpl: function(renderContext) { - if (this.family === PConstants.GROUP) { - this.drawGroup(renderContext); - } else if (this.family === PConstants.PRIMITIVE) { - this.drawPrimitive(renderContext); - } else if (this.family === PConstants.GEOMETRY) { - this.drawGeometry(renderContext); - } else if (this.family === PConstants.PATH) { - this.drawPath(renderContext); - } - }, - /** - * @member PShape - * The drawPath() function draws the <path> part of the SVG document. - */ - drawPath: function(renderContext) { - var i, j; - if (this.vertices.length === 0) { return; } - renderContext.beginShape(); - if (this.vertexCodes.length === 0) { // each point is a simple vertex - if (this.vertices[0].length === 2) { // drawing 2D vertices - for (i = 0, j = this.vertices.length; i < j; i++) { - renderContext.vertex(this.vertices[i][0], this.vertices[i][1]); - } - } else { // drawing 3D vertices - for (i = 0, j = this.vertices.length; i < j; i++) { - renderContext.vertex(this.vertices[i][0], - this.vertices[i][1], - this.vertices[i][2]); - } - } - } else { // coded set of vertices - var index = 0; - if (this.vertices[0].length === 2) { // drawing a 2D path - for (i = 0, j = this.vertexCodes.length; i < j; i++) { - if (this.vertexCodes[i] === PConstants.VERTEX) { - renderContext.vertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index].moveTo); - renderContext.breakShape = false; - index++; - } else if (this.vertexCodes[i] === PConstants.BEZIER_VERTEX) { - renderContext.bezierVertex(this.vertices[index+0][0], - this.vertices[index+0][1], - this.vertices[index+1][0], - this.vertices[index+1][1], - this.vertices[index+2][0], - this.vertices[index+2][1]); - index += 3; - } else if (this.vertexCodes[i] === PConstants.CURVE_VERTEX) { - renderContext.curveVertex(this.vertices[index][0], - this.vertices[index][1]); - index++; - } else if (this.vertexCodes[i] === PConstants.BREAK) { - renderContext.breakShape = true; - } - } - } else { // drawing a 3D path - for (i = 0, j = this.vertexCodes.length; i < j; i++) { - if (this.vertexCodes[i] === PConstants.VERTEX) { - renderContext.vertex(this.vertices[index][0], - this.vertices[index][1], - this.vertices[index][2]); - if (this.vertices[index].moveTo === true) { - vertArray[vertArray.length-1].moveTo = true; - } else if (this.vertices[index].moveTo === false) { - vertArray[vertArray.length-1].moveTo = false; - } - renderContext.breakShape = false; - } else if (this.vertexCodes[i] === PConstants.BEZIER_VERTEX) { - renderContext.bezierVertex(this.vertices[index+0][0], - this.vertices[index+0][1], - this.vertices[index+0][2], - this.vertices[index+1][0], - this.vertices[index+1][1], - this.vertices[index+1][2], - this.vertices[index+2][0], - this.vertices[index+2][1], - this.vertices[index+2][2]); - index += 3; - } else if (this.vertexCodes[i] === PConstants.CURVE_VERTEX) { - renderContext.curveVertex(this.vertices[index][0], - this.vertices[index][1], - this.vertices[index][2]); - index++; - } else if (this.vertexCodes[i] === PConstants.BREAK) { - renderContext.breakShape = true; - } - } - } - } - renderContext.endShape(this.close ? PConstants.CLOSE : PConstants.OPEN); - }, - /** - * @member PShape - * The drawGeometry() function draws the geometry part of the SVG document. - */ - drawGeometry: function(renderContext) { - var i, j; - renderContext.beginShape(this.kind); - if (this.style) { - for (i = 0, j = this.vertices.length; i < j; i++) { - renderContext.vertex(this.vertices[i]); - } - } else { - for (i = 0, j = this.vertices.length; i < j; i++) { - var vert = this.vertices[i]; - if (vert[2] === 0) { - renderContext.vertex(vert[0], vert[1]); - } else { - renderContext.vertex(vert[0], vert[1], vert[2]); - } - } - } - renderContext.endShape(); - }, - /** - * @member PShape - * The drawGroup() function draws the <g> part of the SVG document. - */ - drawGroup: function(renderContext) { - for (var i = 0, j = this.children.length; i < j; i++) { - this.children[i].draw(renderContext); - } - }, - /** - * @member PShape - * The drawPrimitive() function draws SVG document shape elements. These can be point, line, triangle, quad, rect, ellipse, arc, box, or sphere. - */ - drawPrimitive: function(renderContext) { - if (this.kind === PConstants.POINT) { - renderContext.point(this.params[0], this.params[1]); - } else if (this.kind === PConstants.LINE) { - if (this.params.length === 4) { // 2D - renderContext.line(this.params[0], this.params[1], - this.params[2], this.params[3]); - } else { // 3D - renderContext.line(this.params[0], this.params[1], this.params[2], - this.params[3], this.params[4], this.params[5]); - } - } else if (this.kind === PConstants.TRIANGLE) { - renderContext.triangle(this.params[0], this.params[1], - this.params[2], this.params[3], - this.params[4], this.params[5]); - } else if (this.kind === PConstants.QUAD) { - renderContext.quad(this.params[0], this.params[1], - this.params[2], this.params[3], - this.params[4], this.params[5], - this.params[6], this.params[7]); - } else if (this.kind === PConstants.RECT) { - if (this.image !== null) { - var imMode = imageModeConvert; - renderContext.imageMode(PConstants.CORNER); - renderContext.image(this.image, - this.params[0], - this.params[1], - this.params[2], - this.params[3]); - imageModeConvert = imMode; - } else { - var rcMode = renderContext.curRectMode; - renderContext.rectMode(PConstants.CORNER); - renderContext.rect(this.params[0], - this.params[1], - this.params[2], - this.params[3]); - renderContext.curRectMode = rcMode; - } - } else if (this.kind === PConstants.ELLIPSE) { - var elMode = renderContext.curEllipseMode; - renderContext.ellipseMode(PConstants.CORNER); - renderContext.ellipse(this.params[0], - this.params[1], - this.params[2], - this.params[3]); - renderContext.curEllipseMode = elMode; - } else if (this.kind === PConstants.ARC) { - var eMode = curEllipseMode; - renderContext.ellipseMode(PConstants.CORNER); - renderContext.arc(this.params[0], - this.params[1], - this.params[2], - this.params[3], - this.params[4], - this.params[5]); - curEllipseMode = eMode; - } else if (this.kind === PConstants.BOX) { - if (this.params.length === 1) { - renderContext.box(this.params[0]); - } else { - renderContext.box(this.params[0], this.params[1], this.params[2]); - } - } else if (this.kind === PConstants.SPHERE) { - renderContext.sphere(this.params[0]); - } - }, - /** - * @member PShape - * The pre() function performs the preparations before the SVG is drawn. This includes doing transformations and storing previous styles. - */ - pre: function(renderContext) { - if (this.matrix) { - renderContext.pushMatrix(); - renderContext.transform(this.matrix); - } - if (this.style) { - renderContext.pushStyle(); - this.styles(renderContext); - } - }, - /** - * @member PShape - * The post() function performs the necessary actions after the SVG is drawn. This includes removing transformations and removing added styles. - */ - post: function(renderContext) { - if (this.matrix) { - renderContext.popMatrix(); - } - if (this.style) { - renderContext.popStyle(); - } - }, - /** - * @member PShape - * The styles() function changes the Processing's current styles - */ - styles: function(renderContext) { - if (this.stroke) { - renderContext.stroke(this.strokeColor); - renderContext.strokeWeight(this.strokeWeight); - renderContext.strokeCap(this.strokeCap); - renderContext.strokeJoin(this.strokeJoin); - } else { - renderContext.noStroke(); - } - - if (this.fill) { - renderContext.fill(this.fillColor); - - } else { - renderContext.noFill(); - } - }, - /** - * @member PShape - * The getChild() function extracts a child shape from a parent shape. Specify the name of the shape with the <b>target</b> parameter or the - * layer position of the shape to get with the <b>index</b> parameter. - * The shape is returned as a <b>PShape</b> object, or <b>null</b> is returned if there is an error. - * - * @param {String} target the name of the shape to get - * @param {int} index the layer position of the shape to get - * - * @return {PShape} returns a child element of a shape as a PShape object or null if there is an error - */ - getChild: function(child) { - var i, j; - if (typeof child === 'number') { - return this.children[child]; - } - var found; - if(child === "" || this.name === child){ - return this; - } - if(this.nameTable.length > 0) { - for(i = 0, j = this.nameTable.length; i < j || found; i++) { - if(this.nameTable[i].getName === child) { - found = this.nameTable[i]; - break; - } - } - if (found) { return found; } - } - for(i = 0, j = this.children.length; i < j; i++) { - found = this.children[i].getChild(child); - if(found) { return found; } - } - return null; - }, - /** - * @member PShape - * The getChildCount() returns the number of children - * - * @return {int} returns a count of children - */ - getChildCount: function () { - return this.children.length; - }, - /** - * @member PShape - * The addChild() adds a child to the PShape. - * - * @param {PShape} child the child to add - */ - addChild: function( child ) { - this.children.push(child); - child.parent = this; - if (child.getName() !== null) { - this.addName(child.getName(), child); - } - }, - /** - * @member PShape - * The addName() functions adds a shape to the name lookup table. - * - * @param {String} name the name to be added - * @param {PShape} shape the shape - */ - addName: function(name, shape) { - if (this.parent !== null) { - this.parent.addName( name, shape ); - } else { - this.nameTable.push( [name, shape] ); - } - }, - /** - * @member PShape - * The translate() function specifies an amount to displace the shape. The <b>x</b> parameter specifies left/right translation, the <b>y</b> parameter specifies up/down translation, and the <b>z</b> parameter specifies translations toward/away from the screen. - * Subsequent calls to the method accumulates the effect. For example, calling <b>translate(50, 0)</b> and then <b>translate(20, 0)</b> is the same as <b>translate(70, 0)</b>. - * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run. - * <br><br>Using this method with the <b>z</b> parameter requires using the P3D or OPENGL parameter in combination with size. - * - * @param {int|float} x left/right translation - * @param {int|float} y up/down translation - * @param {int|float} z forward/back translation - * - * @see PMatrix2D#translate - * @see PMatrix3D#translate - */ - translate: function() { - if(arguments.length === 2) - { - this.checkMatrix(2); - this.matrix.translate(arguments[0], arguments[1]); - } else { - this.checkMatrix(3); - this.matrix.translate(arguments[0], arguments[1], 0); - } - }, - /** - * @member PShape - * The checkMatrix() function makes sure that the shape's matrix is 1) not null, and 2) has a matrix - * that can handle <em>at least</em> the specified number of dimensions. - * - * @param {int} dimensions the specified number of dimensions - */ - checkMatrix: function(dimensions) { - if(this.matrix === null) { - if(dimensions === 2) { - this.matrix = new PMatrix2D(); - } else { - this.matrix = new PMatrix3D(); - } - }else if(dimensions === 3 && this.matrix instanceof PMatrix2D) { - this.matrix = new PMatrix3D(); - } - }, - /** - * @member PShape - * The rotateX() function rotates a shape around the x-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method. - * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction. - * Subsequent calls to the method accumulates the effect. For example, calling <b>rotateX(HALF_PI)</b> and then <b>rotateX(HALF_PI)</b> is the same as <b>rotateX(PI)</b>. - * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run. - * <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above. - * - * @param {float}angle angle of rotation specified in radians - * - * @see PMatrix3D#rotateX - */ - rotateX: function(angle) { - this.rotate(angle, 1, 0, 0); - }, - /** - * @member PShape - * The rotateY() function rotates a shape around the y-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method. - * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction. - * Subsequent calls to the method accumulates the effect. For example, calling <b>rotateY(HALF_PI)</b> and then <b>rotateY(HALF_PI)</b> is the same as <b>rotateY(PI)</b>. - * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run. - * <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above. - * - * @param {float}angle angle of rotation specified in radians - * - * @see PMatrix3D#rotateY - */ - rotateY: function(angle) { - this.rotate(angle, 0, 1, 0); - }, - /** - * @member PShape - * The rotateZ() function rotates a shape around the z-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method. - * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction. - * Subsequent calls to the method accumulates the effect. For example, calling <b>rotateZ(HALF_PI)</b> and then <b>rotateZ(HALF_PI)</b> is the same as <b>rotateZ(PI)</b>. - * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run. - * <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above. - * - * @param {float}angle angle of rotation specified in radians - * - * @see PMatrix3D#rotateZ - */ - rotateZ: function(angle) { - this.rotate(angle, 0, 0, 1); - }, - /** - * @member PShape - * The rotate() function rotates a shape the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method. - * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction. - * Transformations apply to everything that happens after and subsequent calls to the method accumulates the effect. - * For example, calling <b>rotate(HALF_PI)</b> and then <b>rotate(HALF_PI)</b> is the same as <b>rotate(PI)</b>. - * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run. - * If optional parameters x,y,z are supplied, the rotate is about the point (x, y, z). - * - * @param {float}angle angle of rotation specified in radians - * @param {float}x x-coordinate of the point - * @param {float}y y-coordinate of the point - * @param {float}z z-coordinate of the point - * @see PMatrix2D#rotate - * @see PMatrix3D#rotate - */ - rotate: function() { - if(arguments.length === 1){ - this.checkMatrix(2); - this.matrix.rotate(arguments[0]); - } else { - this.checkMatrix(3); - this.matrix.rotate(arguments[0], - arguments[1], - arguments[2], - arguments[3]); - } - }, - /** - * @member PShape - * The scale() function increases or decreases the size of a shape by expanding and contracting vertices. Shapes always scale from the relative origin of their bounding box. - * Scale values are specified as decimal percentages. For example, the method call <b>scale(2.0)</b> increases the dimension of a shape by 200%. - * Subsequent calls to the method multiply the effect. For example, calling <b>scale(2.0)</b> and then <b>scale(1.5)</b> is the same as <b>scale(3.0)</b>. - * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run. - * <br><br>Using this fuction with the <b>z</b> parameter requires passing P3D or OPENGL into the size() parameter. - * - * @param {float}s percentage to scale the object - * @param {float}x percentage to scale the object in the x-axis - * @param {float}y percentage to scale the object in the y-axis - * @param {float}z percentage to scale the object in the z-axis - * - * @see PMatrix2D#scale - * @see PMatrix3D#scale - */ - scale: function() { - if(arguments.length === 2) { - this.checkMatrix(2); - this.matrix.scale(arguments[0], arguments[1]); - } else if (arguments.length === 3) { - this.checkMatrix(2); - this.matrix.scale(arguments[0], arguments[1], arguments[2]); - } else { - this.checkMatrix(2); - this.matrix.scale(arguments[0]); - } - }, - /** - * @member PShape - * The resetMatrix() function resets the matrix - * - * @see PMatrix2D#reset - * @see PMatrix3D#reset - */ - resetMatrix: function() { - this.checkMatrix(2); - this.matrix.reset(); - }, - /** - * @member PShape - * The applyMatrix() function multiplies this matrix by another matrix of type PMatrix3D or PMatrix2D. - * Individual elements can also be provided - * - * @param {PMatrix3D|PMatrix2D} matrix the matrix to multiply by - * - * @see PMatrix2D#apply - * @see PMatrix3D#apply - */ - applyMatrix: function(matrix) { - if (arguments.length === 1) { - this.applyMatrix(matrix.elements[0], - matrix.elements[1], 0, - matrix.elements[2], - matrix.elements[3], - matrix.elements[4], 0, - matrix.elements[5], - 0, 0, 1, 0, - 0, 0, 0, 1); - } else if (arguments.length === 6) { - this.checkMatrix(2); - this.matrix.apply(arguments[0], arguments[1], arguments[2], 0, - arguments[3], arguments[4], arguments[5], 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - - } else if (arguments.length === 16) { - this.checkMatrix(3); - this.matrix.apply(arguments[0], - arguments[1], - arguments[2], - arguments[3], - arguments[4], - arguments[5], - arguments[6], - arguments[7], - arguments[8], - arguments[9], - arguments[10], - arguments[11], - arguments[12], - arguments[13], - arguments[14], - arguments[15]); - } - } - }; - - return PShape; -}; -},{}],17:[function(require,module,exports){ -/** - * SVG stands for Scalable Vector Graphics, a portable graphics format. It is - * a vector format so it allows for infinite resolution and relatively small - * file sizes. Most modern media software can view SVG files, including Adobe - * products, Firefox, etc. Illustrator and Inkscape can edit SVG files. - * - * @param {PApplet} parent typically use "this" - * @param {String} filename name of the SVG file to load - * @param {XMLElement} xml an XMLElement element - * @param {PShapeSVG} parent the parent PShapeSVG - * - * @see PShape - */ -module.exports = function(options) { - var CommonFunctions = options.CommonFunctions, - PConstants = options.PConstants, - PShape = options.PShape, - XMLElement = options.XMLElement, - colors = options.colors; - - var PShapeSVG = function() { - PShape.call(this); // PShape is the base class. - if (arguments.length === 1) { // xml element coming in - this.element = arguments[0]; - - // set values to their defaults according to the SVG spec - this.vertexCodes = []; - this.vertices = []; - this.opacity = 1; - - this.stroke = false; - this.strokeColor = PConstants.ALPHA_MASK; - this.strokeWeight = 1; - this.strokeCap = PConstants.SQUARE; // BUTT in svg spec - this.strokeJoin = PConstants.MITER; - this.strokeGradient = null; - this.strokeGradientPaint = null; - this.strokeName = null; - this.strokeOpacity = 1; - - this.fill = true; - this.fillColor = PConstants.ALPHA_MASK; - this.fillGradient = null; - this.fillGradientPaint = null; - this.fillName = null; - this.fillOpacity = 1; - - if (this.element.getName() !== "svg") { - throw("root is not <svg>, it's <" + this.element.getName() + ">"); - } - } - else if (arguments.length === 2) { - if (typeof arguments[1] === 'string') { - if (arguments[1].indexOf(".svg") > -1) { //its a filename - this.element = new XMLElement(true, arguments[1]); - // set values to their defaults according to the SVG spec - this.vertexCodes = []; - this.vertices = []; - this.opacity = 1; - - this.stroke = false; - this.strokeColor = PConstants.ALPHA_MASK; - this.strokeWeight = 1; - this.strokeCap = PConstants.SQUARE; // BUTT in svg spec - this.strokeJoin = PConstants.MITER; - this.strokeGradient = ""; - this.strokeGradientPaint = ""; - this.strokeName = ""; - this.strokeOpacity = 1; - - this.fill = true; - this.fillColor = PConstants.ALPHA_MASK; - this.fillGradient = null; - this.fillGradientPaint = null; - this.fillOpacity = 1; - - } - } else { // XMLElement - if (arguments[0]) { // PShapeSVG - this.element = arguments[1]; - this.vertexCodes = arguments[0].vertexCodes.slice(); - this.vertices = arguments[0].vertices.slice(); - - this.stroke = arguments[0].stroke; - this.strokeColor = arguments[0].strokeColor; - this.strokeWeight = arguments[0].strokeWeight; - this.strokeCap = arguments[0].strokeCap; - this.strokeJoin = arguments[0].strokeJoin; - this.strokeGradient = arguments[0].strokeGradient; - this.strokeGradientPaint = arguments[0].strokeGradientPaint; - this.strokeName = arguments[0].strokeName; - - this.fill = arguments[0].fill; - this.fillColor = arguments[0].fillColor; - this.fillGradient = arguments[0].fillGradient; - this.fillGradientPaint = arguments[0].fillGradientPaint; - this.fillName = arguments[0].fillName; - this.strokeOpacity = arguments[0].strokeOpacity; - this.fillOpacity = arguments[0].fillOpacity; - this.opacity = arguments[0].opacity; - } - } - } - - this.name = this.element.getStringAttribute("id"); - var displayStr = this.element.getStringAttribute("display", "inline"); - this.visible = displayStr !== "none"; - var str = this.element.getAttribute("transform"); - if (str) { - this.matrix = this.parseMatrix(str); - } - // not proper parsing of the viewBox, but will cover us for cases where - // the width and height of the object is not specified - var viewBoxStr = this.element.getStringAttribute("viewBox"); - if ( viewBoxStr !== null ) { - var viewBox = viewBoxStr.split(" "); - this.width = viewBox[2]; - this.height = viewBox[3]; - } - - // TODO if viewbox is not same as width/height, then use it to scale - // the original objects. for now, viewbox only used when width/height - // are empty values (which by the spec means w/h of "100%" - var unitWidth = this.element.getStringAttribute("width"); - var unitHeight = this.element.getStringAttribute("height"); - if (unitWidth !== null) { - this.width = this.parseUnitSize(unitWidth); - this.height = this.parseUnitSize(unitHeight); - } else { - if ((this.width === 0) || (this.height === 0)) { - // For the spec, the default is 100% and 100%. For purposes - // here, insert a dummy value because this is prolly just a - // font or something for which the w/h doesn't matter. - this.width = 1; - this.height = 1; - - //show warning - throw("The width and/or height is not " + - "readable in the <svg> tag of this file."); - } - } - this.parseColors(this.element); - this.parseChildren(this.element); - - }; - /** - * PShapeSVG methods are inherited from the PShape prototype - */ - PShapeSVG.prototype = new PShape(); - /** - * @member PShapeSVG - * The parseMatrix() function parses the specified SVG matrix into a PMatrix2D. Note that PMatrix2D - * is rotated relative to the SVG definition, so parameters are rearranged - * here. More about the transformation matrices in - * <a href="http://www.w3.org/TR/SVG/coords.html#TransformAttribute">this section</a> - * of the SVG documentation. - * - * @param {String} str text of the matrix param. - * - * @return {PMatrix2D} a PMatrix2D - */ - PShapeSVG.prototype.parseMatrix = (function() { - function getCoords(s) { - var m = []; - s.replace(/\((.*?)\)/, (function() { - return function(all, params) { - // get the coordinates that can be separated by spaces or a comma - m = params.replace(/,+/g, " ").split(/\s+/); - }; - }())); - return m; - } - - return function(str) { - this.checkMatrix(2); - var pieces = []; - str.replace(/\s*(\w+)\((.*?)\)/g, function(all) { - // get a list of transform definitions - pieces.push(CommonFunctions.trim(all)); - }); - if (pieces.length === 0) { - return null; - } - - for (var i = 0, j = pieces.length; i < j; i++) { - var m = getCoords(pieces[i]); - - if (pieces[i].indexOf("matrix") !== -1) { - this.matrix.set(m[0], m[2], m[4], m[1], m[3], m[5]); - } else if (pieces[i].indexOf("translate") !== -1) { - var tx = m[0]; - var ty = (m.length === 2) ? m[1] : 0; - this.matrix.translate(tx,ty); - } else if (pieces[i].indexOf("scale") !== -1) { - var sx = m[0]; - var sy = (m.length === 2) ? m[1] : m[0]; - this.matrix.scale(sx,sy); - } else if (pieces[i].indexOf("rotate") !== -1) { - var angle = m[0]; - if (m.length === 1) { - this.matrix.rotate(CommonFunctions.radians(angle)); - } else if (m.length === 3) { - this.matrix.translate(m[1], m[2]); - this.matrix.rotate(CommonFunctions.radians(m[0])); - this.matrix.translate(-m[1], -m[2]); - } - } else if (pieces[i].indexOf("skewX") !== -1) { - this.matrix.skewX(parseFloat(m[0])); - } else if (pieces[i].indexOf("skewY") !== -1) { - this.matrix.skewY(m[0]); - } else if (pieces[i].indexOf("shearX") !== -1) { - this.matrix.shearX(m[0]); - } else if (pieces[i].indexOf("shearY") !== -1) { - this.matrix.shearY(m[0]); - } - } - return this.matrix; - }; - }()); - - /** - * @member PShapeSVG - * The parseChildren() function parses the specified XMLElement - * - * @param {XMLElement}element the XMLElement to parse - */ - PShapeSVG.prototype.parseChildren = function(element) { - var newelement = element.getChildren(); - var base = new PShape(); - var i, j; - for (i = 0, j = newelement.length; i < j; i++) { - var kid = this.parseChild(newelement[i]); - if (kid) { - base.addChild(kid); - } - } - for (i = 0, j = base.children.length; i < j; i++) { - this.children.push(base.children[i]); - } - }; - /** - * @member PShapeSVG - * The getName() function returns the name - * - * @return {String} the name - */ - PShapeSVG.prototype.getName = function() { - return this.name; - }; - /** - * @member PShapeSVG - * The parseChild() function parses a child XML element. - * - * @param {XMLElement} elem the element to parse - * - * @return {PShape} the newly created PShape - */ - PShapeSVG.prototype.parseChild = function( elem ) { - var name = elem.getName(); - var shape; - if (name === "g") { - shape = new PShapeSVG(this, elem); - } else if (name === "defs") { - // generally this will contain gradient info, so may - // as well just throw it into a group element for parsing - shape = new PShapeSVG(this, elem); - } else if (name === "line") { - shape = new PShapeSVG(this, elem); - shape.parseLine(); - } else if (name === "circle") { - shape = new PShapeSVG(this, elem); - shape.parseEllipse(true); - } else if (name === "ellipse") { - shape = new PShapeSVG(this, elem); - shape.parseEllipse(false); - } else if (name === "rect") { - shape = new PShapeSVG(this, elem); - shape.parseRect(); - } else if (name === "polygon") { - shape = new PShapeSVG(this, elem); - shape.parsePoly(true); - } else if (name === "polyline") { - shape = new PShapeSVG(this, elem); - shape.parsePoly(false); - } else if (name === "path") { - shape = new PShapeSVG(this, elem); - shape.parsePath(); - } else if (name === "radialGradient") { - //return new RadialGradient(this, elem); - unimplemented('PShapeSVG.prototype.parseChild, name = radialGradient'); - } else if (name === "linearGradient") { - //return new LinearGradient(this, elem); - unimplemented('PShapeSVG.prototype.parseChild, name = linearGradient'); - } else if (name === "text") { - unimplemented('PShapeSVG.prototype.parseChild, name = text'); - } else if (name === "filter") { - unimplemented('PShapeSVG.prototype.parseChild, name = filter'); - } else if (name === "mask") { - unimplemented('PShapeSVG.prototype.parseChild, name = mask'); - } else { - // ignoring - } - return shape; - }; - /** - * @member PShapeSVG - * The parsePath() function parses the <path> element of the svg file - * A path is defined by including a path element which contains a d="(path data)" attribute, where the d attribute contains - * the moveto, line, curve (both cubic and quadratic Beziers), arc and closepath instructions. - **/ - PShapeSVG.prototype.parsePath = function() { - this.family = PConstants.PATH; - this.kind = 0; - var pathDataChars = []; - var c; - //change multiple spaces and commas to single space - var pathData = CommonFunctions.trim(this.element.getStringAttribute("d").replace(/[\s,]+/g,' ')); - if (pathData === null) { - return; - } - pathData = pathData.split(''); - var cx = 0, - cy = 0, - ctrlX = 0, - ctrlY = 0, - ctrlX1 = 0, - ctrlX2 = 0, - ctrlY1 = 0, - ctrlY2 = 0, - endX = 0, - endY = 0, - ppx = 0, - ppy = 0, - px = 0, - py = 0, - i = 0, - valOf = 0; - var str = ""; - var tmpArray = []; - var flag = false; - var lastInstruction; - var command; - var j, k; - while (i< pathData.length) { - valOf = pathData[i].charCodeAt(0); - if ((valOf >= 65 && valOf <= 90) || (valOf >= 97 && valOf <= 122)) { - // if it's a letter - // populate the tmpArray with coordinates - j = i; - i++; - if (i < pathData.length) { // don't go over boundary of array - tmpArray = []; - valOf = pathData[i].charCodeAt(0); - while (!((valOf >= 65 && valOf <= 90) || - (valOf >= 97 && valOf <= 100) || - (valOf >= 102 && valOf <= 122)) && flag === false) { // if its NOT a letter - if (valOf === 32) { //if its a space and the str isn't empty - // sometimes you get a space after the letter - if (str !== "") { - tmpArray.push(parseFloat(str)); - str = ""; - } - i++; - } else if (valOf === 45) { //if it's a - - // allow for 'e' notation in numbers, e.g. 2.10e-9 - if (pathData[i-1].charCodeAt(0) === 101) { - str += pathData[i].toString(); - i++; - } else { - // sometimes no space separator after (ex: 104.535-16.322) - if (str !== "") { - tmpArray.push(parseFloat(str)); - } - str = pathData[i].toString(); - i++; - } - } else { - str += pathData[i].toString(); - i++; - } - if (i === pathData.length) { // don't go over boundary of array - flag = true; - } else { - valOf = pathData[i].charCodeAt(0); - } - } - } - if (str !== "") { - tmpArray.push(parseFloat(str)); - str = ""; - } - command = pathData[j]; - valOf = command.charCodeAt(0); - if (valOf === 77) { // M - move to (absolute) - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - // need one+ pairs of co-ordinates - cx = tmpArray[0]; - cy = tmpArray[1]; - this.parsePathMoveto(cx, cy); - if (tmpArray.length > 2) { - for (j = 2, k = tmpArray.length; j < k; j+=2) { - // absolute line to - cx = tmpArray[j]; - cy = tmpArray[j+1]; - this.parsePathLineto(cx,cy); - } - } - } - } else if (valOf === 109) { // m - move to (relative) - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - // need one+ pairs of co-ordinates - cx += tmpArray[0]; - cy += tmpArray[1]; - this.parsePathMoveto(cx,cy); - if (tmpArray.length > 2) { - for (j = 2, k = tmpArray.length; j < k; j+=2) { - // relative line to - cx += tmpArray[j]; - cy += tmpArray[j + 1]; - this.parsePathLineto(cx,cy); - } - } - } - } else if (valOf === 76) { // L - lineto (absolute) - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - // need one+ pairs of co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=2) { - cx = tmpArray[j]; - cy = tmpArray[j + 1]; - this.parsePathLineto(cx,cy); - } - } - } else if (valOf === 108) { // l - lineto (relative) - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - // need one+ pairs of co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=2) { - cx += tmpArray[j]; - cy += tmpArray[j+1]; - this.parsePathLineto(cx,cy); - } - } - } else if (valOf === 72) { // H - horizontal lineto (absolute) - for (j = 0, k = tmpArray.length; j < k; j++) { - // multiple x co-ordinates can be provided - cx = tmpArray[j]; - this.parsePathLineto(cx, cy); - } - } else if (valOf === 104) { // h - horizontal lineto (relative) - for (j = 0, k = tmpArray.length; j < k; j++) { - // multiple x co-ordinates can be provided - cx += tmpArray[j]; - this.parsePathLineto(cx, cy); - } - } else if (valOf === 86) { // V - vertical lineto (absolute) - for (j = 0, k = tmpArray.length; j < k; j++) { - // multiple y co-ordinates can be provided - cy = tmpArray[j]; - this.parsePathLineto(cx, cy); - } - } else if (valOf === 118) { // v - vertical lineto (relative) - for (j = 0, k = tmpArray.length; j < k; j++) { - // multiple y co-ordinates can be provided - cy += tmpArray[j]; - this.parsePathLineto(cx, cy); - } - } else if (valOf === 67) { // C - curve to (absolute) - if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) { - // need one+ multiples of 6 co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=6) { - ctrlX1 = tmpArray[j]; - ctrlY1 = tmpArray[j + 1]; - ctrlX2 = tmpArray[j + 2]; - ctrlY2 = tmpArray[j + 3]; - endX = tmpArray[j + 4]; - endY = tmpArray[j + 5]; - this.parsePathCurveto(ctrlX1, - ctrlY1, - ctrlX2, - ctrlY2, - endX, - endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 99) { // c - curve to (relative) - if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) { - // need one+ multiples of 6 co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=6) { - ctrlX1 = cx + tmpArray[j]; - ctrlY1 = cy + tmpArray[j + 1]; - ctrlX2 = cx + tmpArray[j + 2]; - ctrlY2 = cy + tmpArray[j + 3]; - endX = cx + tmpArray[j + 4]; - endY = cy + tmpArray[j + 5]; - this.parsePathCurveto(ctrlX1, - ctrlY1, - ctrlX2, - ctrlY2, - endX, - endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 83) { // S - curve to shorthand (absolute) - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) { - // need one+ multiples of 4 co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=4) { - if (lastInstruction.toLowerCase() === "c" || - lastInstruction.toLowerCase() === "s") { - ppx = this.vertices[ this.vertices.length-2 ][0]; - ppy = this.vertices[ this.vertices.length-2 ][1]; - px = this.vertices[ this.vertices.length-1 ][0]; - py = this.vertices[ this.vertices.length-1 ][1]; - ctrlX1 = px + (px - ppx); - ctrlY1 = py + (py - ppy); - } else { - //If there is no previous curve, - //the current point will be used as the first control point. - ctrlX1 = this.vertices[this.vertices.length-1][0]; - ctrlY1 = this.vertices[this.vertices.length-1][1]; - } - ctrlX2 = tmpArray[j]; - ctrlY2 = tmpArray[j + 1]; - endX = tmpArray[j + 2]; - endY = tmpArray[j + 3]; - this.parsePathCurveto(ctrlX1, - ctrlY1, - ctrlX2, - ctrlY2, - endX, - endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 115) { // s - curve to shorthand (relative) - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) { - // need one+ multiples of 4 co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=4) { - if (lastInstruction.toLowerCase() === "c" || - lastInstruction.toLowerCase() === "s") { - ppx = this.vertices[this.vertices.length-2][0]; - ppy = this.vertices[this.vertices.length-2][1]; - px = this.vertices[this.vertices.length-1][0]; - py = this.vertices[this.vertices.length-1][1]; - ctrlX1 = px + (px - ppx); - ctrlY1 = py + (py - ppy); - } else { - //If there is no previous curve, - //the current point will be used as the first control point. - ctrlX1 = this.vertices[this.vertices.length-1][0]; - ctrlY1 = this.vertices[this.vertices.length-1][1]; - } - ctrlX2 = cx + tmpArray[j]; - ctrlY2 = cy + tmpArray[j + 1]; - endX = cx + tmpArray[j + 2]; - endY = cy + tmpArray[j + 3]; - this.parsePathCurveto(ctrlX1, - ctrlY1, - ctrlX2, - ctrlY2, - endX, - endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 81) { // Q - quadratic curve to (absolute) - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) { - // need one+ multiples of 4 co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=4) { - ctrlX = tmpArray[j]; - ctrlY = tmpArray[j + 1]; - endX = tmpArray[j + 2]; - endY = tmpArray[j + 3]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 113) { // q - quadratic curve to (relative) - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) { - // need one+ multiples of 4 co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=4) { - ctrlX = cx + tmpArray[j]; - ctrlY = cy + tmpArray[j + 1]; - endX = cx + tmpArray[j + 2]; - endY = cy + tmpArray[j + 3]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 84) { - // T - quadratic curve to shorthand (absolute) - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - // need one+ pairs of co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=2) { - if (lastInstruction.toLowerCase() === "q" || - lastInstruction.toLowerCase() === "t") { - ppx = this.vertices[this.vertices.length-2][0]; - ppy = this.vertices[this.vertices.length-2][1]; - px = this.vertices[this.vertices.length-1][0]; - py = this.vertices[this.vertices.length-1][1]; - ctrlX = px + (px - ppx); - ctrlY = py + (py - ppy); - } else { - // If there is no previous command or if the previous command - // was not a Q, q, T or t, assume the control point is - // coincident with the current point. - ctrlX = cx; - ctrlY = cy; - } - endX = tmpArray[j]; - endY = tmpArray[j + 1]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 116) { - // t - quadratic curve to shorthand (relative) - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - // need one+ pairs of co-ordinates - for (j = 0, k = tmpArray.length; j < k; j+=2) { - if (lastInstruction.toLowerCase() === "q" || - lastInstruction.toLowerCase() === "t") { - ppx = this.vertices[this.vertices.length-2][0]; - ppy = this.vertices[this.vertices.length-2][1]; - px = this.vertices[this.vertices.length-1][0]; - py = this.vertices[this.vertices.length-1][1]; - ctrlX = px + (px - ppx); - ctrlY = py + (py - ppy); - } else { - // If there is no previous command or if the previous command - // was not a Q, q, T or t, assume the control point is - // coincident with the current point. - ctrlX = cx; - ctrlY = cy; - } - endX = cx + tmpArray[j]; - endY = cy + tmpArray[j + 1]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY; - } - } - } else if (valOf === 90 || valOf === 122) { // Z or z (these do the same thing) - this.close = true; - } - lastInstruction = command.toString(); - } else { i++;} - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parsePath() helper function - * - * @see PShapeSVG#parsePath - */ - PShapeSVG.prototype.parsePathQuadto = function(x1, y1, cx, cy, x2, y2) { - if (this.vertices.length > 0) { - this.parsePathCode(PConstants.BEZIER_VERTEX); - // x1/y1 already covered by last moveto, lineto, or curveto - this.parsePathVertex(x1 + ((cx-x1)*2/3), y1 + ((cy-y1)*2/3)); - this.parsePathVertex(x2 + ((cx-x2)*2/3), y2 + ((cy-y2)*2/3)); - this.parsePathVertex(x2, y2); - } else { - throw ("Path must start with M/m"); - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parsePath() helper function - * - * @see PShapeSVG#parsePath - */ - PShapeSVG.prototype.parsePathCurveto = function(x1, y1, x2, y2, x3, y3) { - if (this.vertices.length > 0) { - this.parsePathCode(PConstants.BEZIER_VERTEX ); - this.parsePathVertex(x1, y1); - this.parsePathVertex(x2, y2); - this.parsePathVertex(x3, y3); - } else { - throw ("Path must start with M/m"); - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parsePath() helper function - * - * @see PShapeSVG#parsePath - */ - PShapeSVG.prototype.parsePathLineto = function(px, py) { - if (this.vertices.length > 0) { - this.parsePathCode(PConstants.VERTEX); - this.parsePathVertex(px, py); - // add property to distinguish between curContext.moveTo - // or curContext.lineTo - this.vertices[this.vertices.length-1].moveTo = false; - } else { - throw ("Path must start with M/m"); - } - }; - - PShapeSVG.prototype.parsePathMoveto = function(px, py) { - if (this.vertices.length > 0) { - this.parsePathCode(PConstants.BREAK); - } - this.parsePathCode(PConstants.VERTEX); - this.parsePathVertex(px, py); - // add property to distinguish between curContext.moveTo - // or curContext.lineTo - this.vertices[this.vertices.length-1].moveTo = true; - }; - /** - * @member PShapeSVG - * PShapeSVG.parsePath() helper function - * - * @see PShapeSVG#parsePath - */ - PShapeSVG.prototype.parsePathVertex = function(x, y) { - var verts = []; - verts[0] = x; - verts[1] = y; - this.vertices.push(verts); - }; - /** - * @member PShapeSVG - * PShapeSVG.parsePath() helper function - * - * @see PShapeSVG#parsePath - */ - PShapeSVG.prototype.parsePathCode = function(what) { - this.vertexCodes.push(what); - }; - /** - * @member PShapeSVG - * The parsePoly() function parses a polyline or polygon from an SVG file. - * - * @param {boolean}val true if shape is closed (polygon), false if not (polyline) - */ - PShapeSVG.prototype.parsePoly = function(val) { - this.family = PConstants.PATH; - this.close = val; - var pointsAttr = CommonFunctions.trim(this.element.getStringAttribute("points").replace(/[,\s]+/g,' ')); - if (pointsAttr !== null) { - //split into array - var pointsBuffer = pointsAttr.split(" "); - if (pointsBuffer.length % 2 === 0) { - for (var i = 0, j = pointsBuffer.length; i < j; i++) { - var verts = []; - verts[0] = pointsBuffer[i]; - verts[1] = pointsBuffer[++i]; - this.vertices.push(verts); - } - } else { - throw("Error parsing polygon points: odd number of coordinates provided"); - } - } - }; - /** - * @member PShapeSVG - * The parseRect() function parses a rect from an SVG file. - */ - PShapeSVG.prototype.parseRect = function() { - this.kind = PConstants.RECT; - this.family = PConstants.PRIMITIVE; - this.params = []; - this.params[0] = this.element.getFloatAttribute("x"); - this.params[1] = this.element.getFloatAttribute("y"); - this.params[2] = this.element.getFloatAttribute("width"); - this.params[3] = this.element.getFloatAttribute("height"); - if (this.params[2] < 0 || this.params[3] < 0) { - throw("svg error: negative width or height found while parsing <rect>"); - } - }; - /** - * @member PShapeSVG - * The parseEllipse() function handles parsing ellipse and circle tags. - * - * @param {boolean}val true if this is a circle and not an ellipse - */ - PShapeSVG.prototype.parseEllipse = function(val) { - this.kind = PConstants.ELLIPSE; - this.family = PConstants.PRIMITIVE; - this.params = []; - - this.params[0] = this.element.getFloatAttribute("cx") | 0 ; - this.params[1] = this.element.getFloatAttribute("cy") | 0; - - var rx, ry; - if (val) { - rx = ry = this.element.getFloatAttribute("r"); - if (rx < 0) { - throw("svg error: negative radius found while parsing <circle>"); - } - } else { - rx = this.element.getFloatAttribute("rx"); - ry = this.element.getFloatAttribute("ry"); - if (rx < 0 || ry < 0) { - throw("svg error: negative x-axis radius or y-axis radius found while parsing <ellipse>"); - } - } - this.params[0] -= rx; - this.params[1] -= ry; - - this.params[2] = rx*2; - this.params[3] = ry*2; - }; - /** - * @member PShapeSVG - * The parseLine() function handles parsing line tags. - * - * @param {boolean}val true if this is a circle and not an ellipse - */ - PShapeSVG.prototype.parseLine = function() { - this.kind = PConstants.LINE; - this.family = PConstants.PRIMITIVE; - this.params = []; - this.params[0] = this.element.getFloatAttribute("x1"); - this.params[1] = this.element.getFloatAttribute("y1"); - this.params[2] = this.element.getFloatAttribute("x2"); - this.params[3] = this.element.getFloatAttribute("y2"); - }; - /** - * @member PShapeSVG - * The parseColors() function handles parsing the opacity, strijem stroke-width, stroke-linejoin,stroke-linecap, fill, and style attributes - * - * @param {XMLElement}element the element of which attributes to parse - */ - PShapeSVG.prototype.parseColors = function(element) { - if (element.hasAttribute("opacity")) { - this.setOpacity(element.getAttribute("opacity")); - } - if (element.hasAttribute("stroke")) { - this.setStroke(element.getAttribute("stroke")); - } - if (element.hasAttribute("stroke-width")) { - // if NaN (i.e. if it's 'inherit') then default - // back to the inherit setting - this.setStrokeWeight(element.getAttribute("stroke-width")); - } - if (element.hasAttribute("stroke-linejoin") ) { - this.setStrokeJoin(element.getAttribute("stroke-linejoin")); - } - if (element.hasAttribute("stroke-linecap")) { - this.setStrokeCap(element.getStringAttribute("stroke-linecap")); - } - // fill defaults to black (though stroke defaults to "none") - // http://www.w3.org/TR/SVG/painting.html#FillProperties - if (element.hasAttribute("fill")) { - this.setFill(element.getStringAttribute("fill")); - } - if (element.hasAttribute("style")) { - var styleText = element.getStringAttribute("style"); - var styleTokens = styleText.toString().split( ";" ); - - for (var i = 0, j = styleTokens.length; i < j; i++) { - var tokens = CommonFunctions.trim(styleTokens[i].split( ":" )); - if (tokens[0] === "fill") { - this.setFill(tokens[1]); - } else if (tokens[0] === "fill-opacity") { - this.setFillOpacity(tokens[1]); - } else if (tokens[0] === "stroke") { - this.setStroke(tokens[1]); - } else if (tokens[0] === "stroke-width") { - this.setStrokeWeight(tokens[1]); - } else if (tokens[0] === "stroke-linecap") { - this.setStrokeCap(tokens[1]); - } else if (tokens[0] === "stroke-linejoin") { - this.setStrokeJoin(tokens[1]); - } else if (tokens[0] === "stroke-opacity") { - this.setStrokeOpacity(tokens[1]); - } else if (tokens[0] === "opacity") { - this.setOpacity(tokens[1]); - } // Other attributes are not yet implemented - } - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} opacityText the value of fillOpacity - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setFillOpacity = function(opacityText) { - this.fillOpacity = parseFloat(opacityText); - this.fillColor = this.fillOpacity * 255 << 24 | - this.fillColor & 0xFFFFFF; - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} fillText the value of fill - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setFill = function (fillText) { - var opacityMask = this.fillColor & 0xFF000000; - if (fillText === "none") { - this.fill = false; - } else if (fillText.indexOf("#") === 0) { - this.fill = true; - if (fillText.length === 4) { - // convert #00F to #0000FF - fillText = fillText.replace(/#(.)(.)(.)/,"#$1$1$2$2$3$3"); - } - this.fillColor = opacityMask | - (parseInt(fillText.substring(1), 16 )) & - 0xFFFFFF; - } else if (fillText.indexOf("rgb") === 0) { - this.fill = true; - this.fillColor = opacityMask | this.parseRGB(fillText); - } else if (fillText.indexOf("url(#") === 0) { - this.fillName = fillText.substring(5, fillText.length - 1 ); - } else if (colors[fillText]) { - this.fill = true; - this.fillColor = opacityMask | - (parseInt(colors[fillText].substring(1), 16)) & - 0xFFFFFF; - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} opacity the value of opacity - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setOpacity = function(opacity) { - this.strokeColor = parseFloat(opacity) * 255 << 24 | - this.strokeColor & 0xFFFFFF; - this.fillColor = parseFloat(opacity) * 255 << 24 | - this.fillColor & 0xFFFFFF; - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} strokeText the value to set stroke to - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setStroke = function(strokeText) { - var opacityMask = this.strokeColor & 0xFF000000; - if (strokeText === "none") { - this.stroke = false; - } else if (strokeText.charAt( 0 ) === "#") { - this.stroke = true; - if (strokeText.length === 4) { - // convert #00F to #0000FF - strokeText = strokeText.replace(/#(.)(.)(.)/,"#$1$1$2$2$3$3"); - } - this.strokeColor = opacityMask | - (parseInt( strokeText.substring( 1 ), 16 )) & - 0xFFFFFF; - } else if (strokeText.indexOf( "rgb" ) === 0 ) { - this.stroke = true; - this.strokeColor = opacityMask | this.parseRGB(strokeText); - } else if (strokeText.indexOf( "url(#" ) === 0) { - this.strokeName = strokeText.substring(5, strokeText.length - 1); - } else if (colors[strokeText]) { - this.stroke = true; - this.strokeColor = opacityMask | - (parseInt(colors[strokeText].substring(1), 16)) & - 0xFFFFFF; - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} weight the value to set strokeWeight to - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setStrokeWeight = function(weight) { - this.strokeWeight = this.parseUnitSize(weight); - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} linejoin the value to set strokeJoin to - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setStrokeJoin = function(linejoin) { - if (linejoin === "miter") { - this.strokeJoin = PConstants.MITER; - - } else if (linejoin === "round") { - this.strokeJoin = PConstants.ROUND; - - } else if (linejoin === "bevel") { - this.strokeJoin = PConstants.BEVEL; - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} linecap the value to set strokeCap to - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setStrokeCap = function (linecap) { - if (linecap === "butt") { - this.strokeCap = PConstants.SQUARE; - - } else if (linecap === "round") { - this.strokeCap = PConstants.ROUND; - - } else if (linecap === "square") { - this.strokeCap = PConstants.PROJECT; - } - }; - /** - * @member PShapeSVG - * PShapeSVG.parseColors() helper function - * - * @param {String} opacityText the value to set stroke opacity to - * - * @see PShapeSVG#parseColors - */ - PShapeSVG.prototype.setStrokeOpacity = function (opacityText) { - this.strokeOpacity = parseFloat(opacityText); - this.strokeColor = this.strokeOpacity * 255 << 24 | - this.strokeColor & - 0xFFFFFF; - }; - /** - * @member PShapeSVG - * The parseRGB() function parses an rbg() color string and returns a color int - * - * @param {String} color the color to parse in rbg() format - * - * @return {int} the equivalent color int - */ - PShapeSVG.prototype.parseRGB = function(color) { - var sub = color.substring(color.indexOf('(') + 1, color.indexOf(')')); - var values = sub.split(", "); - return (values[0] << 16) | (values[1] << 8) | (values[2]); - }; - /** - * @member PShapeSVG - * The parseUnitSize() function parse a size that may have a suffix for its units. - * Ignoring cases where this could also be a percentage. - * The <A HREF="http://www.w3.org/TR/SVG/coords.html#Units">units</A> spec: - * <UL> - * <LI>"1pt" equals "1.25px" (and therefore 1.25 user units) - * <LI>"1pc" equals "15px" (and therefore 15 user units) - * <LI>"1mm" would be "3.543307px" (3.543307 user units) - * <LI>"1cm" equals "35.43307px" (and therefore 35.43307 user units) - * <LI>"1in" equals "90px" (and therefore 90 user units) - * </UL> - */ - PShapeSVG.prototype.parseUnitSize = function (text) { - var len = text.length - 2; - if (len < 0) { return text; } - if (text.indexOf("pt") === len) { - return parseFloat(text.substring(0, len)) * 1.25; - } - if (text.indexOf("pc") === len) { - return parseFloat( text.substring( 0, len)) * 15; - } - if (text.indexOf("mm") === len) { - return parseFloat( text.substring(0, len)) * 3.543307; - } - if (text.indexOf("cm") === len) { - return parseFloat(text.substring(0, len)) * 35.43307; - } - if (text.indexOf("in") === len) { - return parseFloat(text.substring(0, len)) * 90; - } - if (text.indexOf("px") === len) { - return parseFloat(text.substring(0, len)); - } - return parseFloat(text); - }; - - return PShapeSVG; -}; - -},{}],18:[function(require,module,exports){ -module.exports = function(options, undef) { - var PConstants = options.PConstants; - - function PVector(x, y, z) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - } - - PVector.fromAngle = function(angle, v) { - if (v === undef || v === null) { - v = new PVector(); - } - v.x = Math.cos(angle); - v.y = Math.sin(angle); - return v; - }; - - PVector.random2D = function(v) { - return PVector.fromAngle(Math.random() * PConstants.TWO_PI, v); - }; - - PVector.random3D = function(v) { - var angle = Math.random() * PConstants.TWO_PI; - var vz = Math.random() * 2 - 1; - var mult = Math.sqrt(1 - vz * vz); - var vx = mult * Math.cos(angle); - var vy = mult * Math.sin(angle); - if (v === undef || v === null) { - v = new PVector(vx, vy, vz); - } else { - v.set(vx, vy, vz); - } - return v; - }; - - PVector.dist = function(v1, v2) { - return v1.dist(v2); - }; - - PVector.dot = function(v1, v2) { - return v1.dot(v2); - }; - - PVector.cross = function(v1, v2) { - return v1.cross(v2); - }; - - PVector.sub = function(v1, v2) { - return new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); - }; - - PVector.angleBetween = function(v1, v2) { - return Math.acos(v1.dot(v2) / Math.sqrt(v1.magSq() * v2.magSq())); - }; - - PVector.lerp = function(v1, v2, amt) { - // non-static lerp mutates object, but this version returns a new vector - var retval = new PVector(v1.x, v1.y, v1.z); - retval.lerp(v2, amt); - return retval; - }; - - // Common vector operations for PVector - PVector.prototype = { - set: function(v, y, z) { - if (arguments.length === 1) { - this.set(v.x || v[0] || 0, - v.y || v[1] || 0, - v.z || v[2] || 0); - } else { - this.x = v; - this.y = y; - this.z = z; - } - }, - get: function() { - return new PVector(this.x, this.y, this.z); - }, - mag: function() { - var x = this.x, - y = this.y, - z = this.z; - return Math.sqrt(x * x + y * y + z * z); - }, - magSq: function() { - var x = this.x, - y = this.y, - z = this.z; - return (x * x + y * y + z * z); - }, - setMag: function(v_or_len, len) { - if (len === undef) { - len = v_or_len; - this.normalize(); - this.mult(len); - } else { - var v = v_or_len; - v.normalize(); - v.mult(len); - return v; - } - }, - add: function(v, y, z) { - if (arguments.length === 1) { - this.x += v.x; - this.y += v.y; - this.z += v.z; - } else if (arguments.length === 2) { - // 2D Vector - this.x += v; - this.y += y; - } else { - this.x += v; - this.y += y; - this.z += z; - } - }, - sub: function(v, y, z) { - if (arguments.length === 1) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - } else if (arguments.length === 2) { - // 2D Vector - this.x -= v; - this.y -= y; - } else { - this.x -= v; - this.y -= y; - this.z -= z; - } - }, - mult: function(v) { - if (typeof v === 'number') { - this.x *= v; - this.y *= v; - this.z *= v; - } else { - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - } - }, - div: function(v) { - if (typeof v === 'number') { - this.x /= v; - this.y /= v; - this.z /= v; - } else { - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - } - }, - rotate: function(angle) { - var prev_x = this.x; - var c = Math.cos(angle); - var s = Math.sin(angle); - this.x = c * this.x - s * this.y; - this.y = s * prev_x + c * this.y; - }, - dist: function(v) { - var dx = this.x - v.x, - dy = this.y - v.y, - dz = this.z - v.z; - return Math.sqrt(dx * dx + dy * dy + dz * dz); - }, - dot: function(v, y, z) { - if (arguments.length === 1) { - return (this.x * v.x + this.y * v.y + this.z * v.z); - } - return (this.x * v + this.y * y + this.z * z); - }, - cross: function(v) { - var x = this.x, - y = this.y, - z = this.z; - return new PVector(y * v.z - v.y * z, - z * v.x - v.z * x, - x * v.y - v.x * y); - }, - lerp: function(v_or_x, amt_or_y, z, amt) { - var lerp_val = function(start, stop, amt) { - return start + (stop - start) * amt; - }; - var x, y; - if (arguments.length === 2) { - // given vector and amt - amt = amt_or_y; - x = v_or_x.x; - y = v_or_x.y; - z = v_or_x.z; - } else { - // given x, y, z and amt - x = v_or_x; - y = amt_or_y; - } - this.x = lerp_val(this.x, x, amt); - this.y = lerp_val(this.y, y, amt); - this.z = lerp_val(this.z, z, amt); - }, - normalize: function() { - var m = this.mag(); - if (m > 0) { - this.div(m); - } - }, - limit: function(high) { - if (this.mag() > high) { - this.normalize(); - this.mult(high); - } - }, - heading: function() { - return (-Math.atan2(-this.y, this.x)); - }, - heading2D: function() { - return this.heading(); - }, - toString: function() { - return "[" + this.x + ", " + this.y + ", " + this.z + "]"; - }, - array: function() { - return [this.x, this.y, this.z]; - } - }; - - function createPVectorMethod(method) { - return function(v1, v2) { - var v = v1.get(); - v[method](v2); - return v; - }; - } - - for (var method in PVector.prototype) { - if (PVector.prototype.hasOwnProperty(method) && !PVector.hasOwnProperty(method)) { - PVector[method] = createPVectorMethod(method); - } - } - - return PVector; -}; - -},{}],19:[function(require,module,exports){ -/** - * XMLAttribute is an attribute of a XML element. - * - * @param {String} fname the full name of the attribute - * @param {String} n the short name of the attribute - * @param {String} namespace the namespace URI of the attribute - * @param {String} v the value of the attribute - * @param {String }t the type of the attribute - * - * @see XMLElement - */ -module.exports = function() { - - var XMLAttribute = function (fname, n, nameSpace, v, t){ - this.fullName = fname || ""; - this.name = n || ""; - this.namespace = nameSpace || ""; - this.value = v; - this.type = t; - }; - - XMLAttribute.prototype = { - /** - * @member XMLAttribute - * The getName() function returns the short name of the attribute - * - * @return {String} the short name of the attribute - */ - getName: function() { - return this.name; - }, - /** - * @member XMLAttribute - * The getFullName() function returns the full name of the attribute - * - * @return {String} the full name of the attribute - */ - getFullName: function() { - return this.fullName; - }, - /** - * @member XMLAttribute - * The getNamespace() function returns the namespace of the attribute - * - * @return {String} the namespace of the attribute - */ - getNamespace: function() { - return this.namespace; - }, - /** - * @member XMLAttribute - * The getValue() function returns the value of the attribute - * - * @return {String} the value of the attribute - */ - getValue: function() { - return this.value; - }, - /** - * @member XMLAttribute - * The getValue() function returns the type of the attribute - * - * @return {String} the type of the attribute - */ - getType: function() { - return this.type; - }, - /** - * @member XMLAttribute - * The setValue() function sets the value of the attribute - * - * @param {String} newval the new value - */ - setValue: function(newval) { - this.value = newval; - } - }; - - return XMLAttribute; -}; - -},{}],20:[function(require,module,exports){ -/** - * XMLElement is a representation of an XML object. The object is able to parse XML code - * - * @param {PApplet} parent typically use "this" - * @param {String} filename name of the XML/SVG file to load - * @param {String} xml the xml/svg string - * @param {String} fullname the full name of the element - * @param {String} namespace the namespace of the URI - * @param {String} systemID the system ID of the XML data where the element starts - * @param {Integer }lineNr the line in the XML data where the element starts - */ -module.exports = function(options, undef) { - - var Browser = options.Browser, - ajax = Browser.ajax, - window = Browser.window, - XMLHttpRequest = window.XMLHttpRequest, - DOMParser = window.DOMParser, - XMLAttribute = options. XMLAttribute; - - var XMLElement = function(selector, uri, sysid, line) { - this.attributes = []; - this.children = []; - this.fullName = null; - this.name = null; - this.namespace = ""; - this.content = null; - this.parent = null; - this.lineNr = ""; - this.systemID = ""; - this.type = "ELEMENT"; - - if (selector) { - if (typeof selector === "string") { - if (uri === undef && selector.indexOf("<") > -1) { - // load XML from text string - this.parse(selector); - } else { - // XMLElement(fullname, namespace, sysid, line) format - this.fullName = selector; - this.namespace = uri; - this.systemId = sysid; - this.lineNr = line; - } - } else { - // XMLElement(this, file uri) format - this.parse(uri, true); - } - } - }; - /** - * XMLElement methods - * missing: enumerateAttributeNames(), enumerateChildren(), - * NOTE: parse does not work when a url is passed in - */ - XMLElement.prototype = { - /** - * @member XMLElement - * The parse() function retrieves the file via ajax() and uses DOMParser() - * parseFromString method to make an XML document - * @addon - * - * @param {String} filename name of the XML/SVG file to load - * - * @throws ExceptionType Error loading document - * - * @see XMLElement#parseChildrenRecursive - */ - parse: function(textstring, stringIsURI) { - var xmlDoc; - try { - if (stringIsURI) { - textstring = ajax(textstring); - } - xmlDoc = new DOMParser().parseFromString(textstring, "text/xml"); - var elements = xmlDoc.documentElement; - if (elements) { - this.parseChildrenRecursive(null, elements); - } else { - throw ("Error loading document"); - } - return this; - } catch(e) { - throw(e); - } - }, - /** - * @member XMLElement - * Internal helper function for parse(). - * Loops through the - * @addon - * - * @param {XMLElement} parent the parent node - * @param {XML document childNodes} elementpath the remaining nodes that need parsing - * - * @return {XMLElement} the new element and its children elements - */ - parseChildrenRecursive: function (parent, elementpath){ - var xmlelement, - xmlattribute, - tmpattrib, - l, m, - child; - if (!parent) { // this element is the root element - this.fullName = elementpath.localName; - this.name = elementpath.nodeName; - xmlelement = this; - } else { // this element has a parent - xmlelement = new XMLElement(elementpath.nodeName); - xmlelement.parent = parent; - } - - // if this is a text node, return a PCData element (parsed character data) - if (elementpath.nodeType === 3 && elementpath.textContent !== "") { - return this.createPCDataElement(elementpath.textContent); - } - - // if this is a CDATA node, return a CData element (unparsed character data) - if (elementpath.nodeType === 4) { - return this.createCDataElement(elementpath.textContent); - } - - // bind all attributes, if there are any - if (elementpath.attributes) { - for (l = 0, m = elementpath.attributes.length; l < m; l++) { - tmpattrib = elementpath.attributes[l]; - xmlattribute = new XMLAttribute(tmpattrib.getname, - tmpattrib.nodeName, - tmpattrib.namespaceURI, - tmpattrib.nodeValue, - tmpattrib.nodeType); - xmlelement.attributes.push(xmlattribute); - } - } - - // bind all children, if there are any - if (elementpath.childNodes) { - for (l = 0, m = elementpath.childNodes.length; l < m; l++) { - var node = elementpath.childNodes[l]; - child = xmlelement.parseChildrenRecursive(xmlelement, node); - if (child !== null) { - xmlelement.children.push(child); - } - } - } - - return xmlelement; - }, - /** - * @member XMLElement - * The createElement() function Creates an empty element - * - * @param {String} fullName the full name of the element - * @param {String} namespace the namespace URI - * @param {String} systemID the system ID of the XML data where the element starts - * @param {int} lineNr the line in the XML data where the element starts - */ - createElement: function (fullname, namespaceuri, sysid, line) { - if (sysid === undef) { - return new XMLElement(fullname, namespaceuri); - } - return new XMLElement(fullname, namespaceuri, sysid, line); - }, - /** - * @member XMLElement - * The createPCDataElement() function creates an element to be used for #PCDATA content. - * Because Processing discards whitespace TEXT nodes, this method will not build an element - * if the passed content is empty after trimming for whitespace. - * - * @return {XMLElement} new "pcdata" XMLElement, or null if content consists only of whitespace - */ - createPCDataElement: function (content, isCDATA) { - if (content.replace(/^\s+$/g,"") === "") { - return null; - } - var pcdata = new XMLElement(); - pcdata.type = "TEXT"; - pcdata.content = content; - return pcdata; - }, - /** - * @member XMLElement - * The createCDataElement() function creates an element to be used for CDATA content. - * - * @return {XMLElement} new "cdata" XMLElement, or null if content consists only of whitespace - */ - createCDataElement: function (content) { - var cdata = this.createPCDataElement(content); - if (cdata === null) { - return null; - } - - cdata.type = "CDATA"; - var htmlentities = {"<": "<", ">": ">", "'": "'", '"': """}, - entity; - for (entity in htmlentities) { - if (!Object.hasOwnProperty(htmlentities,entity)) { - content = content.replace(new RegExp(entity, "g"), htmlentities[entity]); - } - } - cdata.cdata = content; - return cdata; - }, - /** - * @member XMLElement - * The hasAttribute() function returns whether an attribute exists - * - * @param {String} name name of the attribute - * @param {String} namespace the namespace URI of the attribute - * - * @return {boolean} true if the attribute exists - */ - hasAttribute: function () { - if (arguments.length === 1) { - return this.getAttribute(arguments[0]) !== null; - } - if (arguments.length === 2) { - return this.getAttribute(arguments[0],arguments[1]) !== null; - } - }, - /** - * @member XMLElement - * The equals() function checks to see if the XMLElement being passed in equals another XMLElement - * - * @param {XMLElement} rawElement the element to compare to - * - * @return {boolean} true if the element equals another element - */ - equals: function(other) { - if (!(other instanceof XMLElement)) { - return false; - } - var i, j; - if (this.fullName !== other.fullName) { return false; } - if (this.attributes.length !== other.getAttributeCount()) { return false; } - // attributes may be ordered differently - if (this.attributes.length !== other.attributes.length) { return false; } - var attr_name, attr_ns, attr_value, attr_type, attr_other; - for (i = 0, j = this.attributes.length; i < j; i++) { - attr_name = this.attributes[i].getName(); - attr_ns = this.attributes[i].getNamespace(); - attr_other = other.findAttribute(attr_name, attr_ns); - if (attr_other === null) { return false; } - if (this.attributes[i].getValue() !== attr_other.getValue()) { return false; } - if (this.attributes[i].getType() !== attr_other.getType()) { return false; } - } - // children must be ordered identically - if (this.children.length !== other.getChildCount()) { return false; } - if (this.children.length>0) { - var child1, child2; - for (i = 0, j = this.children.length; i < j; i++) { - child1 = this.getChild(i); - child2 = other.getChild(i); - if (!child1.equals(child2)) { return false; } - } - return true; - } - return (this.content === other.content); - }, - /** - * @member XMLElement - * The getContent() function returns the content of an element. If there is no such content, null is returned - * - * @return {String} the (possibly null) content - */ - getContent: function(){ - if (this.type === "TEXT" || this.type === "CDATA") { - return this.content; - } - var children = this.children; - if (children.length === 1 && (children[0].type === "TEXT" || children[0].type === "CDATA")) { - return children[0].content; - } - return null; - }, - /** - * @member XMLElement - * The getAttribute() function returns the value of an attribute - * - * @param {String} name the non-null full name of the attribute - * @param {String} namespace the namespace URI, which may be null - * @param {String} defaultValue the default value of the attribute - * - * @return {String} the value, or defaultValue if the attribute does not exist - */ - getAttribute: function (){ - var attribute; - if (arguments.length === 2) { - attribute = this.findAttribute(arguments[0]); - if (attribute) { - return attribute.getValue(); - } - return arguments[1]; - } else if (arguments.length === 1) { - attribute = this.findAttribute(arguments[0]); - if (attribute) { - return attribute.getValue(); - } - return null; - } else if (arguments.length === 3) { - attribute = this.findAttribute(arguments[0],arguments[1]); - if (attribute) { - return attribute.getValue(); - } - return arguments[2]; - } - }, - /** - * @member XMLElement - * The getStringAttribute() function returns the string attribute of the element - * If the <b>defaultValue</b> parameter is used and the attribute doesn't exist, the <b>defaultValue</b> value is returned. - * When calling the function without the <b>defaultValue</b> parameter, if the attribute doesn't exist, the value 0 is returned. - * - * @param name the name of the attribute - * @param defaultValue value returned if the attribute is not found - * - * @return {String} the value, or defaultValue if the attribute does not exist - */ - getStringAttribute: function() { - if (arguments.length === 1) { - return this.getAttribute(arguments[0]); - } - if (arguments.length === 2) { - return this.getAttribute(arguments[0], arguments[1]); - } - return this.getAttribute(arguments[0], arguments[1],arguments[2]); - }, - /** - * Processing 1.5 XML API wrapper for the generic String - * attribute getter. This may only take one argument. - */ - getString: function(attributeName) { - return this.getStringAttribute(attributeName); - }, - /** - * @member XMLElement - * The getFloatAttribute() function returns the float attribute of the element. - * If the <b>defaultValue</b> parameter is used and the attribute doesn't exist, the <b>defaultValue</b> value is returned. - * When calling the function without the <b>defaultValue</b> parameter, if the attribute doesn't exist, the value 0 is returned. - * - * @param name the name of the attribute - * @param defaultValue value returned if the attribute is not found - * - * @return {float} the value, or defaultValue if the attribute does not exist - */ - getFloatAttribute: function() { - if (arguments.length === 1 ) { - return parseFloat(this.getAttribute(arguments[0], 0)); - } - if (arguments.length === 2 ) { - return this.getAttribute(arguments[0], arguments[1]); - } - return this.getAttribute(arguments[0], arguments[1],arguments[2]); - }, - /** - * Processing 1.5 XML API wrapper for the generic float - * attribute getter. This may only take one argument. - */ - getFloat: function(attributeName) { - return this.getFloatAttribute(attributeName); - }, - /** - * @member XMLElement - * The getIntAttribute() function returns the integer attribute of the element. - * If the <b>defaultValue</b> parameter is used and the attribute doesn't exist, the <b>defaultValue</b> value is returned. - * When calling the function without the <b>defaultValue</b> parameter, if the attribute doesn't exist, the value 0 is returned. - * - * @param name the name of the attribute - * @param defaultValue value returned if the attribute is not found - * - * @return {int} the value, or defaultValue if the attribute does not exist - */ - getIntAttribute: function () { - if (arguments.length === 1) { - return this.getAttribute( arguments[0], 0 ); - } - if (arguments.length === 2) { - return this.getAttribute(arguments[0], arguments[1]); - } - return this.getAttribute(arguments[0], arguments[1],arguments[2]); - }, - /** - * Processing 1.5 XML API wrapper for the generic int - * attribute getter. This may only take one argument. - */ - getInt: function(attributeName) { - return this.getIntAttribute(attributeName); - }, - /** - * @member XMLElement - * The hasChildren() function returns whether the element has children. - * - * @return {boolean} true if the element has children. - */ - hasChildren: function () { - return this.children.length > 0 ; - }, - /** - * @member XMLElement - * The addChild() function adds a child element - * - * @param {XMLElement} child the non-null child to add. - */ - addChild: function (child) { - if (child !== null) { - child.parent = this; - this.children.push(child); - } - }, - /** - * @member XMLElement - * The insertChild() function inserts a child element at the index provided - * - * @param {XMLElement} child the non-null child to add. - * @param {int} index where to put the child. - */ - insertChild: function (child, index) { - if (child) { - if ((child.getLocalName() === null) && (! this.hasChildren())) { - var lastChild = this.children[this.children.length -1]; - if (lastChild.getLocalName() === null) { - lastChild.setContent(lastChild.getContent() + child.getContent()); - return; - } - } - child.parent = this; - this.children.splice(index,0,child); - } - }, - /** - * @member XMLElement - * The getChild() returns the child XMLElement as specified by the <b>index</b> parameter. - * The value of the <b>index</b> parameter must be less than the total number of children to avoid going out of the array storing the child elements. - * When the <b>path</b> parameter is specified, then it will return all children that match that path. The path is a series of elements and sub-elements, separated by slashes. - * - * @param {int} index where to put the child. - * @param {String} path path to a particular element - * - * @return {XMLElement} the element - */ - getChild: function (selector) { - if (typeof selector === "number") { - return this.children[selector]; - } - if (selector.indexOf('/') !== -1) { - // path traversal is required - return this.getChildRecursive(selector.split("/"), 0); - } - var kid, kidName; - for (var i = 0, j = this.getChildCount(); i < j; i++) { - kid = this.getChild(i); - kidName = kid.getName(); - if (kidName !== null && kidName === selector) { - return kid; - } - } - return null; - }, - /** - * @member XMLElement - * The getChildren() returns all of the children as an XMLElement array. - * When the <b>path</b> parameter is specified, then it will return all children that match that path. - * The path is a series of elements and sub-elements, separated by slashes. - * - * @param {String} path element name or path/to/element - * - * @return {XMLElement} array of child elements that match - * - * @see XMLElement#getChildCount() - * @see XMLElement#getChild() - */ - getChildren: function(){ - if (arguments.length === 1) { - if (typeof arguments[0] === "number") { - return this.getChild( arguments[0]); - } - if (arguments[0].indexOf('/') !== -1) { // path was given - return this.getChildrenRecursive( arguments[0].split("/"), 0); - } - var matches = []; - var kid, kidName; - for (var i = 0, j = this.getChildCount(); i < j; i++) { - kid = this.getChild(i); - kidName = kid.getName(); - if (kidName !== null && kidName === arguments[0]) { - matches.push(kid); - } - } - return matches; - } - return this.children; - }, - /** - * @member XMLElement - * The getChildCount() returns the number of children for the element. - * - * @return {int} the count - * - * @see XMLElement#getChild() - * @see XMLElement#getChildren() - */ - getChildCount: function() { - return this.children.length; - }, - /** - * @member XMLElement - * Internal helper function for getChild(). - * - * @param {String[]} items result of splitting the query on slashes - * @param {int} offset where in the items[] array we're currently looking - * - * @return {XMLElement} matching element or null if no match - */ - getChildRecursive: function (items, offset) { - // terminating clause: we are the requested candidate - if (offset === items.length) { - return this; - } - // continuation clause - var kid, kidName, matchName = items[offset]; - for(var i = 0, j = this.getChildCount(); i < j; i++) { - kid = this.getChild(i); - kidName = kid.getName(); - if (kidName !== null && kidName === matchName) { - return kid.getChildRecursive(items, offset+1); - } - } - return null; - }, - /** - * @member XMLElement - * Internal helper function for getChildren(). - * - * @param {String[]} items result of splitting the query on slashes - * @param {int} offset where in the items[] array we're currently looking - * - * @return {XMLElement[]} matching elements or empty array if no match - */ - getChildrenRecursive: function (items, offset) { - if (offset === items.length-1) { - return this.getChildren(items[offset]); - } - var matches = this.getChildren(items[offset]); - var kidMatches = []; - for (var i = 0; i < matches.length; i++) { - kidMatches = kidMatches.concat(matches[i].getChildrenRecursive(items, offset+1)); - } - return kidMatches; - }, - /** - * @member XMLElement - * The isLeaf() function returns whether the element is a leaf element. - * - * @return {boolean} true if the element has no children. - */ - isLeaf: function() { - return !this.hasChildren(); - }, - /** - * @member XMLElement - * The listChildren() function put the names of all children into an array. Same as looping through - * each child and calling getName() on each XMLElement. - * - * @return {String[]} a list of element names. - */ - listChildren: function() { - var arr = []; - for (var i = 0, j = this.children.length; i < j; i++) { - arr.push( this.getChild(i).getName()); - } - return arr; - }, - /** - * @member XMLElement - * The removeAttribute() function removes an attribute - * - * @param {String} name the non-null name of the attribute. - * @param {String} namespace the namespace URI of the attribute, which may be null. - */ - removeAttribute: function (name , namespace) { - this.namespace = namespace || ""; - for (var i = 0, j = this.attributes.length; i < j; i++) { - if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) { - this.attributes.splice(i, 1); - break; - } - } - }, - /** - * @member XMLElement - * The removeChild() removes a child element. - * - * @param {XMLElement} child the the non-null child to be renoved - */ - removeChild: function(child) { - if (child) { - for (var i = 0, j = this.children.length; i < j; i++) { - if (this.children[i].equals(child)) { - this.children.splice(i, 1); - break; - } - } - } - }, - /** - * @member XMLElement - * The removeChildAtIndex() removes the child located at a certain index - * - * @param {int} index the index of the child, where the first child has index 0 - */ - removeChildAtIndex: function(index) { - if (this.children.length > index) { //make sure its not outofbounds - this.children.splice(index, 1); - } - }, - /** - * @member XMLElement - * The findAttribute() function searches an attribute - * - * @param {String} name fullName the non-null full name of the attribute - * @param {String} namespace the name space, which may be null - * - * @return {XMLAttribute} the attribute, or null if the attribute does not exist. - */ - findAttribute: function (name, namespace) { - this.namespace = namespace || ""; - for (var i = 0, j = this.attributes.length; i < j; i++) { - if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) { - return this.attributes[i]; - } - } - return null; - }, - /** - * @member XMLElement - * The setAttribute() function sets an attribute. - * - * @param {String} name the non-null full name of the attribute - * @param {String} namespace the non-null value of the attribute - */ - setAttribute: function() { - var attr; - if (arguments.length === 3) { - var index = arguments[0].indexOf(':'); - var name = arguments[0].substring(index + 1); - attr = this.findAttribute(name, arguments[1]); - if (attr) { - attr.setValue(arguments[2]); - } else { - attr = new XMLAttribute(arguments[0], name, arguments[1], arguments[2], "CDATA"); - this.attributes.push(attr); - } - } else { - attr = this.findAttribute(arguments[0]); - if (attr) { - attr.setValue(arguments[1]); - } else { - attr = new XMLAttribute(arguments[0], arguments[0], null, arguments[1], "CDATA"); - this.attributes.push(attr); - } - } - }, - /** - * Processing 1.5 XML API wrapper for the generic String - * attribute setter. This must take two arguments. - */ - setString: function(attribute, value) { - this.setAttribute(attribute, value); - }, - /** - * Processing 1.5 XML API wrapper for the generic int - * attribute setter. This must take two arguments. - */ - setInt: function(attribute, value) { - this.setAttribute(attribute, value); - }, - /** - * Processing 1.5 XML API wrapper for the generic float - * attribute setter. This must take two arguments. - */ - setFloat: function(attribute, value) { - this.setAttribute(attribute, value); - }, - /** - * @member XMLElement - * The setContent() function sets the #PCDATA content. It is an error to call this method with a - * non-null value if there are child objects. - * - * @param {String} content the (possibly null) content - */ - setContent: function(content) { - if (this.children.length > 0) { - Processing.debug("Tried to set content for XMLElement with children"); } - this.content = content; - }, - /** - * @member XMLElement - * The setName() function sets the full name. This method also sets the short name and clears the - * namespace URI. - * - * @param {String} name the non-null name - * @param {String} namespace the namespace URI, which may be null. - */ - setName: function() { - if (arguments.length === 1) { - this.name = arguments[0]; - this.fullName = arguments[0]; - this.namespace = null; - } else { - var index = arguments[0].indexOf(':'); - if ((arguments[1] === null) || (index < 0)) { - this.name = arguments[0]; - } else { - this.name = arguments[0].substring(index + 1); - } - this.fullName = arguments[0]; - this.namespace = arguments[1]; - } - }, - /** - * @member XMLElement - * The getName() function returns the full name (i.e. the name including an eventual namespace - * prefix) of the element. - * - * @return {String} the name, or null if the element only contains #PCDATA. - */ - getName: function() { - return this.fullName; - }, - /** - * @member XMLElement - * The getLocalName() function returns the local name (i.e. the name excluding an eventual namespace - * prefix) of the element. - * - * @return {String} the name, or null if the element only contains #PCDATA. - */ - getLocalName: function() { - return this.name; - }, - /** - * @member XMLElement - * The getAttributeCount() function returns the number of attributes for the node - * that this XMLElement represents. - * - * @return {int} the number of attributes in this XMLElement - */ - getAttributeCount: function() { - return this.attributes.length; - }, - /** - * @member XMLElement - * The toString() function returns the XML definition of an XMLElement. - * - * @return {String} the XML definition of this XMLElement - */ - toString: function() { - // shortcut for text and cdata nodes - if (this.type === "TEXT") { - return this.content || ""; - } - - if (this.type === "CDATA") { - return this.cdata || ""; - } - - // real XMLElements - var tagstring = this.fullName; - var xmlstring = "<" + tagstring; - var a,c; - - // serialize the attributes to XML string - for (a = 0; a<this.attributes.length; a++) { - var attr = this.attributes[a]; - xmlstring += " " + attr.getName() + "=" + '"' + attr.getValue() + '"'; - } - - // serialize all children to XML string - if (this.children.length === 0) { - if (this.content === "" || this.content === null || this.content === undefined) { - xmlstring += "/>"; - } else { - xmlstring += ">" + this.content + "</"+tagstring+">"; - } - } else { - xmlstring += ">"; - for (c = 0; c<this.children.length; c++) { - xmlstring += this.children[c].toString(); - } - xmlstring += "</" + tagstring + ">"; - } - return xmlstring; - } - }; - - /** - * static Processing 1.5 XML API wrapper for the - * parse method. This may only take one argument. - */ - XMLElement.parse = function(xmlstring) { - var element = new XMLElement(); - element.parse(xmlstring); - return element; - }; - - return XMLElement; -}; - -},{}],21:[function(require,module,exports){ -/** - * web colors, by name - */ -module.exports = { - aliceblue: "#f0f8ff", - antiquewhite: "#faebd7", - aqua: "#00ffff", - aquamarine: "#7fffd4", - azure: "#f0ffff", - beige: "#f5f5dc", - bisque: "#ffe4c4", - black: "#000000", - blanchedalmond: "#ffebcd", - blue: "#0000ff", - blueviolet: "#8a2be2", - brown: "#a52a2a", - burlywood: "#deb887", - cadetblue: "#5f9ea0", - chartreuse: "#7fff00", - chocolate: "#d2691e", - coral: "#ff7f50", - cornflowerblue: "#6495ed", - cornsilk: "#fff8dc", - crimson: "#dc143c", - cyan: "#00ffff", - darkblue: "#00008b", - darkcyan: "#008b8b", - darkgoldenrod: "#b8860b", - darkgray: "#a9a9a9", - darkgreen: "#006400", - darkkhaki: "#bdb76b", - darkmagenta: "#8b008b", - darkolivegreen: "#556b2f", - darkorange: "#ff8c00", - darkorchid: "#9932cc", - darkred: "#8b0000", - darksalmon: "#e9967a", - darkseagreen: "#8fbc8f", - darkslateblue: "#483d8b", - darkslategray: "#2f4f4f", - darkturquoise: "#00ced1", - darkviolet: "#9400d3", - deeppink: "#ff1493", - deepskyblue: "#00bfff", - dimgray: "#696969", - dodgerblue: "#1e90ff", - firebrick: "#b22222", - floralwhite: "#fffaf0", - forestgreen: "#228b22", - fuchsia: "#ff00ff", - gainsboro: "#dcdcdc", - ghostwhite: "#f8f8ff", - gold: "#ffd700", - goldenrod: "#daa520", - gray: "#808080", - green: "#008000", - greenyellow: "#adff2f", - honeydew: "#f0fff0", - hotpink: "#ff69b4", - indianred: "#cd5c5c", - indigo: "#4b0082", - ivory: "#fffff0", - khaki: "#f0e68c", - lavender: "#e6e6fa", - lavenderblush: "#fff0f5", - lawngreen: "#7cfc00", - lemonchiffon: "#fffacd", - lightblue: "#add8e6", - lightcoral: "#f08080", - lightcyan: "#e0ffff", - lightgoldenrodyellow: "#fafad2", - lightgrey: "#d3d3d3", - lightgreen: "#90ee90", - lightpink: "#ffb6c1", - lightsalmon: "#ffa07a", - lightseagreen: "#20b2aa", - lightskyblue: "#87cefa", - lightslategray: "#778899", - lightsteelblue: "#b0c4de", - lightyellow: "#ffffe0", - lime: "#00ff00", - limegreen: "#32cd32", - linen: "#faf0e6", - magenta: "#ff00ff", - maroon: "#800000", - mediumaquamarine: "#66cdaa", - mediumblue: "#0000cd", - mediumorchid: "#ba55d3", - mediumpurple: "#9370d8", - mediumseagreen: "#3cb371", - mediumslateblue: "#7b68ee", - mediumspringgreen: "#00fa9a", - mediumturquoise: "#48d1cc", - mediumvioletred: "#c71585", - midnightblue: "#191970", - mintcream: "#f5fffa", - mistyrose: "#ffe4e1", - moccasin: "#ffe4b5", - navajowhite: "#ffdead", - navy: "#000080", - oldlace: "#fdf5e6", - olive: "#808000", - olivedrab: "#6b8e23", - orange: "#ffa500", - orangered: "#ff4500", - orchid: "#da70d6", - palegoldenrod: "#eee8aa", - palegreen: "#98fb98", - paleturquoise: "#afeeee", - palevioletred: "#d87093", - papayawhip: "#ffefd5", - peachpuff: "#ffdab9", - peru: "#cd853f", - pink: "#ffc0cb", - plum: "#dda0dd", - powderblue: "#b0e0e6", - purple: "#800080", - red: "#ff0000", - rosybrown: "#bc8f8f", - royalblue: "#4169e1", - saddlebrown: "#8b4513", - salmon: "#fa8072", - sandybrown: "#f4a460", - seagreen: "#2e8b57", - seashell: "#fff5ee", - sienna: "#a0522d", - silver: "#c0c0c0", - skyblue: "#87ceeb", - slateblue: "#6a5acd", - slategray: "#708090", - snow: "#fffafa", - springgreen: "#00ff7f", - steelblue: "#4682b4", - tan: "#d2b48c", - teal: "#008080", - thistle: "#d8bfd8", - tomato: "#ff6347", - turquoise: "#40e0d0", - violet: "#ee82ee", - wheat: "#f5deb3", - white: "#ffffff", - whitesmoke: "#f5f5f5", - yellow: "#ffff00", - yellowgreen: "#9acd32" - }; - -},{}],22:[function(require,module,exports){ -module.exports = function(virtHashCode, virtEquals, undef) { - - return function withProxyFunctions(p, removeFirstArgument) { - /** - * The contains(string) function returns true if the string passed in the parameter - * is a substring of this string. It returns false if the string passed - * in the parameter is not a substring of this string. - * - * @param {String} The string to look for in the current string - * - * @return {boolean} returns true if this string contains - * the string passed as parameter. returns false, otherwise. - * - */ - p.__contains = function (subject, subStr) { - if (typeof subject !== "string") { - return subject.contains.apply(subject, removeFirstArgument(arguments)); - } - //Parameter is not null AND - //The type of the parameter is the same as this object (string) - //The javascript function that finds a substring returns 0 or higher - return ( - (subject !== null) && - (subStr !== null) && - (typeof subStr === "string") && - (subject.indexOf(subStr) > -1) - ); - }; - - /** - * The __replaceAll() function searches all matches between a substring (or regular expression) and a string, - * and replaces the matched substring with a new substring - * - * @param {String} subject a substring - * @param {String} regex a substring or a regular expression - * @param {String} replace the string to replace the found value - * - * @return {String} returns result - * - * @see #match - */ - p.__replaceAll = function(subject, regex, replacement) { - if (typeof subject !== "string") { - return subject.replaceAll.apply(subject, removeFirstArgument(arguments)); - } - - return subject.replace(new RegExp(regex, "g"), replacement); - }; - - /** - * The __replaceFirst() function searches first matche between a substring (or regular expression) and a string, - * and replaces the matched substring with a new substring - * - * @param {String} subject a substring - * @param {String} regex a substring or a regular expression - * @param {String} replace the string to replace the found value - * - * @return {String} returns result - * - * @see #match - */ - p.__replaceFirst = function(subject, regex, replacement) { - if (typeof subject !== "string") { - return subject.replaceFirst.apply(subject, removeFirstArgument(arguments)); - } - - return subject.replace(new RegExp(regex, ""), replacement); - }; - - /** - * The __replace() function searches all matches between a substring and a string, - * and replaces the matched substring with a new substring - * - * @param {String} subject a substring - * @param {String} what a substring to find - * @param {String} replacement the string to replace the found value - * - * @return {String} returns result - */ - p.__replace = function(subject, what, replacement) { - if (typeof subject !== "string") { - return subject.replace.apply(subject, removeFirstArgument(arguments)); - } - if (what instanceof RegExp) { - return subject.replace(what, replacement); - } - - if (typeof what !== "string") { - what = what.toString(); - } - if (what === "") { - return subject; - } - - var i = subject.indexOf(what); - if (i < 0) { - return subject; - } - - var j = 0, result = ""; - do { - result += subject.substring(j, i) + replacement; - j = i + what.length; - } while ( (i = subject.indexOf(what, j)) >= 0); - return result + subject.substring(j); - }; - - /** - * The __equals() function compares two strings (or objects) to see if they are the same. - * This method is necessary because it's not possible to compare strings using the equality operator (==). - * Returns true if the strings are the same and false if they are not. - * - * @param {String} subject a string used for comparison - * @param {String} other a string used for comparison with - * - * @return {boolean} true is the strings are the same false otherwise - */ - p.__equals = function(subject, other) { - if (subject.equals instanceof Function) { - return subject.equals.apply(subject, removeFirstArgument(arguments)); - } - - return virtEquals(subject, other); - }; - - /** - * The __equalsIgnoreCase() function compares two strings to see if they are the same. - * Returns true if the strings are the same, either when forced to all lower case or - * all upper case. - * - * @param {String} subject a string used for comparison - * @param {String} other a string used for comparison with - * - * @return {boolean} true is the strings are the same, ignoring case. false otherwise - */ - p.__equalsIgnoreCase = function(subject, other) { - if (typeof subject !== "string") { - return subject.equalsIgnoreCase.apply(subject, removeFirstArgument(arguments)); - } - - return subject.toLowerCase() === other.toLowerCase(); - }; - - /** - * The __toCharArray() function splits the string into a char array. - * - * @param {String} subject The string - * - * @return {Char[]} a char array - */ - p.__toCharArray = function(subject) { - if (typeof subject !== "string") { - return subject.toCharArray.apply(subject, removeFirstArgument(arguments)); - } - - var chars = []; - for (var i = 0, len = subject.length; i < len; ++i) { - chars[i] = new Char(subject.charAt(i)); - } - return chars; - }; - - /** - * The __split() function splits a string using the regex delimiter - * specified. If limit is specified, the resultant array will have number - * of elements equal to or less than the limit. - * - * @param {String} subject string to be split - * @param {String} regexp regex string used to split the subject - * @param {int} limit max number of tokens to be returned - * - * @return {String[]} an array of tokens from the split string - */ - p.__split = function(subject, regex, limit) { - if (typeof subject !== "string") { - return subject.split.apply(subject, removeFirstArgument(arguments)); - } - - var pattern = new RegExp(regex); - - // If limit is not specified, use JavaScript's built-in String.split. - if ((limit === undef) || (limit < 1)) { - return subject.split(pattern); - } - - // If limit is specified, JavaScript's built-in String.split has a - // different behaviour than Java's. A Java-compatible implementation is - // provided here. - var result = [], currSubject = subject, pos; - while (((pos = currSubject.search(pattern)) !== -1) && (result.length < (limit - 1))) { - var match = pattern.exec(currSubject).toString(); - result.push(currSubject.substring(0, pos)); - currSubject = currSubject.substring(pos + match.length); - } - if ((pos !== -1) || (currSubject !== "")) { - result.push(currSubject); - } - return result; - }; - - /** - * The codePointAt() function returns the unicode value of the character at a given index of a string. - * - * @param {int} idx the index of the character - * - * @return {String} code the String containing the unicode value of the character - */ - p.__codePointAt = function(subject, idx) { - var code = subject.charCodeAt(idx), - hi, - low; - if (0xD800 <= code && code <= 0xDBFF) { - hi = code; - low = subject.charCodeAt(idx + 1); - return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; - } - return code; - }; - - /** - * The matches() function checks whether or not a string matches a given regular expression. - * - * @param {String} str the String on which the match is tested - * @param {String} regexp the regexp for which a match is tested - * - * @return {boolean} true if the string fits the regexp, false otherwise - */ - p.__matches = function(str, regexp) { - return (new RegExp(regexp)).test(str); - }; - - /** - * The startsWith() function tests if a string starts with the specified prefix. If the prefix - * is the empty String or equal to the subject String, startsWith() will also return true. - * - * @param {String} prefix the String used to compare against the start of the subject String. - * @param {int} toffset (optional) an offset into the subject String where searching should begin. - * - * @return {boolean} true if the subject String starts with the prefix. - */ - p.__startsWith = function(subject, prefix, toffset) { - if (typeof subject !== "string") { - return subject.startsWith.apply(subject, removeFirstArgument(arguments)); - } - - toffset = toffset || 0; - if (toffset < 0 || toffset > subject.length) { - return false; - } - return (prefix === '' || prefix === subject) ? true : (subject.indexOf(prefix) === toffset); - }; - - /** - * The endsWith() function tests if a string ends with the specified suffix. If the suffix - * is the empty String, endsWith() will also return true. - * - * @param {String} suffix the String used to compare against the end of the subject String. - * - * @return {boolean} true if the subject String starts with the prefix. - */ - p.__endsWith = function(subject, suffix) { - if (typeof subject !== "string") { - return subject.endsWith.apply(subject, removeFirstArgument(arguments)); - } - - var suffixLen = suffix ? suffix.length : 0; - return (suffix === '' || suffix === subject) ? true : - (subject.indexOf(suffix) === subject.length - suffixLen); - }; - - /** - * The returns hash code of the. - * - * @param {Object} subject The string - * - * @return {int} a hash code - */ - p.__hashCode = function(subject) { - if (subject.hashCode instanceof Function) { - return subject.hashCode.apply(subject, removeFirstArgument(arguments)); - } - return virtHashCode(subject); - }; - - /** - * The __printStackTrace() prints stack trace to the console. - * - * @param {Exception} subject The error - */ - p.__printStackTrace = function(subject) { - p.println("Exception: " + subject.toString() ); - }; - }; - -}; - -},{}],23:[function(require,module,exports){ -/** - * For many "math" functions, we can delegate - * to the Math object. For others, we can't. - */ -module.exports = function withMath(p, undef) { - var internalRandomGenerator = function() { return Math.random(); }; - - /** - * Calculates the absolute value (magnitude) of a number. The absolute value of a number is always positive. - * - * @param {int|float} value int or float - * - * @returns {int|float} - */ - p.abs = Math.abs; - - /** - * Calculates the closest int value that is greater than or equal to the value of the parameter. - * For example, ceil(9.03) returns the value 10. - * - * @param {float} value float - * - * @returns {int} - * - * @see floor - * @see round - */ - p.ceil = Math.ceil; - - /** - * Returns Euler's number e (2.71828...) raised to the power of the value parameter. - * - * @param {int|float} value int or float: the exponent to raise e to - * - * @returns {float} - */ - p.exp = Math.exp; - - /** - * Calculates the closest int value that is less than or equal to the value of the parameter. - * - * @param {int|float} value the value to floor - * - * @returns {int|float} - * - * @see ceil - * @see round - */ - p.floor = Math.floor; - - /** - * Calculates the natural logarithm (the base-e logarithm) of a number. This function - * expects the values greater than 0.0. - * - * @param {int|float} value int or float: number must be greater then 0.0 - * - * @returns {float} - */ - p.log = Math.log; - - /** - * Facilitates exponential expressions. The pow() function is an efficient way of - * multiplying numbers by themselves (or their reciprocal) in large quantities. - * For example, pow(3, 5) is equivalent to the expression 3*3*3*3*3 and pow(3, -5) - * is equivalent to 1 / 3*3*3*3*3. - * - * @param {int|float} num base of the exponential expression - * @param {int|float} exponent power of which to raise the base - * - * @returns {float} - * - * @see sqrt - */ - p.pow = Math.pow; - - /** - * Calculates the integer closest to the value parameter. For example, round(9.2) returns the value 9. - * - * @param {float} value number to round - * - * @returns {int} - * - * @see floor - * @see ceil - */ - p.round = Math.round; - /** - * Calculates the square root of a number. The square root of a number is always positive, - * even though there may be a valid negative root. The square root s of number a is such - * that s*s = a. It is the opposite of squaring. - * - * @param {float} value int or float, non negative - * - * @returns {float} - * - * @see pow - * @see sq - */ - - p.sqrt = Math.sqrt; - - // Trigonometry - /** - * The inverse of cos(), returns the arc cosine of a value. This function expects the - * values in the range of -1 to 1 and values are returned in the range 0 to PI (3.1415927). - * - * @param {float} value the value whose arc cosine is to be returned - * - * @returns {float} - * - * @see cos - * @see asin - * @see atan - */ - p.acos = Math.acos; - - /** - * The inverse of sin(), returns the arc sine of a value. This function expects the values - * in the range of -1 to 1 and values are returned in the range -PI/2 to PI/2. - * - * @param {float} value the value whose arc sine is to be returned - * - * @returns {float} - * - * @see sin - * @see acos - * @see atan - */ - p.asin = Math.asin; - - /** - * The inverse of tan(), returns the arc tangent of a value. This function expects the values - * in the range of -Infinity to Infinity (exclusive) and values are returned in the range -PI/2 to PI/2 . - * - * @param {float} value -Infinity to Infinity (exclusive) - * - * @returns {float} - * - * @see tan - * @see asin - * @see acos - */ - p.atan = Math.atan; - - /** - * Calculates the angle (in radians) from a specified point to the coordinate origin as measured from - * the positive x-axis. Values are returned as a float in the range from PI to -PI. The atan2() function - * is most often used for orienting geometry to the position of the cursor. Note: The y-coordinate of the - * point is the first parameter and the x-coordinate is the second due the the structure of calculating the tangent. - * - * @param {float} y y-coordinate of the point - * @param {float} x x-coordinate of the point - * - * @returns {float} - * - * @see tan - */ - p.atan2 = Math.atan2; - - /** - * Calculates the cosine of an angle. This function expects the values of the angle parameter to be provided - * in radians (values from 0 to PI*2). Values are returned in the range -1 to 1. - * - * @param {float} value an angle in radians - * - * @returns {float} - * - * @see tan - * @see sin - */ - p.cos = Math.cos; - - /** - * Calculates the sine of an angle. This function expects the values of the angle parameter to be provided in - * radians (values from 0 to 6.28). Values are returned in the range -1 to 1. - * - * @param {float} value an angle in radians - * - * @returns {float} - * - * @see cos - * @see radians - */ - p.sin = Math.sin; - - /** - * Calculates the ratio of the sine and cosine of an angle. This function expects the values of the angle - * parameter to be provided in radians (values from 0 to PI*2). Values are returned in the range infinity to -infinity. - * - * @param {float} value an angle in radians - * - * @returns {float} - * - * @see cos - * @see sin - * @see radians - */ - p.tan = Math.tan; - - /** - * Constrains a value to not exceed a maximum and minimum value. - * - * @param {int|float} value the value to constrain - * @param {int|float} value minimum limit - * @param {int|float} value maximum limit - * - * @returns {int|float} - * - * @see max - * @see min - */ - p.constrain = function(aNumber, aMin, aMax) { - return aNumber > aMax ? aMax : aNumber < aMin ? aMin : aNumber; - }; - - /** - * Calculates the distance between two points. - * - * @param {int|float} x1 int or float: x-coordinate of the first point - * @param {int|float} y1 int or float: y-coordinate of the first point - * @param {int|float} z1 int or float: z-coordinate of the first point - * @param {int|float} x2 int or float: x-coordinate of the second point - * @param {int|float} y2 int or float: y-coordinate of the second point - * @param {int|float} z2 int or float: z-coordinate of the second point - * - * @returns {float} - */ - p.dist = function() { - var dx, dy, dz; - if (arguments.length === 4) { - dx = arguments[0] - arguments[2]; - dy = arguments[1] - arguments[3]; - return Math.sqrt(dx * dx + dy * dy); - } - if (arguments.length === 6) { - dx = arguments[0] - arguments[3]; - dy = arguments[1] - arguments[4]; - dz = arguments[2] - arguments[5]; - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - }; - - /** - * Calculates a number between two numbers at a specific increment. The amt parameter is the - * amount to interpolate between the two values where 0.0 equal to the first point, 0.1 is very - * near the first point, 0.5 is half-way in between, etc. The lerp function is convenient for - * creating motion along a straight path and for drawing dotted lines. - * - * @param {int|float} value1 float or int: first value - * @param {int|float} value2 float or int: second value - * @param {int|float} amt float: between 0.0 and 1.0 - * - * @returns {float} - * - * @see curvePoint - * @see bezierPoint - */ - p.lerp = function(value1, value2, amt) { - return ((value2 - value1) * amt) + value1; - }; - - /** - * Calculates the magnitude (or length) of a vector. A vector is a direction in space commonly - * used in computer graphics and linear algebra. Because it has no "start" position, the magnitude - * of a vector can be thought of as the distance from coordinate (0,0) to its (x,y) value. - * Therefore, mag() is a shortcut for writing "dist(0, 0, x, y)". - * - * @param {int|float} a float or int: first value - * @param {int|float} b float or int: second value - * @param {int|float} c float or int: third value - * - * @returns {float} - * - * @see dist - */ - p.mag = function(a, b, c) { - if (c) { - return Math.sqrt(a * a + b * b + c * c); - } - - return Math.sqrt(a * a + b * b); - }; - - /** - * Re-maps a number from one range to another. In the example above, the number '25' is converted from - * a value in the range 0..100 into a value that ranges from the left edge (0) to the right edge (width) of the screen. - * Numbers outside the range are not clamped to 0 and 1, because out-of-range values are often intentional and useful. - * - * @param {float} value The incoming value to be converted - * @param {float} istart Lower bound of the value's current range - * @param {float} istop Upper bound of the value's current range - * @param {float} ostart Lower bound of the value's target range - * @param {float} ostop Upper bound of the value's target range - * - * @returns {float} - * - * @see norm - * @see lerp - */ - p.map = function(value, istart, istop, ostart, ostop) { - return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); - }; - - /** - * Determines the largest value in a sequence of numbers. - * - * @param {int|float} value1 int or float - * @param {int|float} value2 int or float - * @param {int|float} value3 int or float - * @param {int|float} array int or float array - * - * @returns {int|float} - * - * @see min - */ - p.max = function() { - if (arguments.length === 2) { - return arguments[0] < arguments[1] ? arguments[1] : arguments[0]; - } - var numbers = arguments.length === 1 ? arguments[0] : arguments; // if single argument, array is used - if (! ("length" in numbers && numbers.length > 0)) { - throw "Non-empty array is expected"; - } - var max = numbers[0], - count = numbers.length; - for (var i = 1; i < count; ++i) { - if (max < numbers[i]) { - max = numbers[i]; - } - } - return max; - }; - - /** - * Determines the smallest value in a sequence of numbers. - * - * @param {int|float} value1 int or float - * @param {int|float} value2 int or float - * @param {int|float} value3 int or float - * @param {int|float} array int or float array - * - * @returns {int|float} - * - * @see max - */ - p.min = function() { - if (arguments.length === 2) { - return arguments[0] < arguments[1] ? arguments[0] : arguments[1]; - } - var numbers = arguments.length === 1 ? arguments[0] : arguments; // if single argument, array is used - if (! ("length" in numbers && numbers.length > 0)) { - throw "Non-empty array is expected"; - } - var min = numbers[0], - count = numbers.length; - for (var i = 1; i < count; ++i) { - if (min > numbers[i]) { - min = numbers[i]; - } - } - return min; - }; - - /** - * Normalizes a number from another range into a value between 0 and 1. - * Identical to map(value, low, high, 0, 1); - * Numbers outside the range are not clamped to 0 and 1, because out-of-range - * values are often intentional and useful. - * - * @param {float} aNumber The incoming value to be converted - * @param {float} low Lower bound of the value's current range - * @param {float} high Upper bound of the value's current range - * - * @returns {float} - * - * @see map - * @see lerp - */ - p.norm = function(aNumber, low, high) { - return (aNumber - low) / (high - low); - }; - - /** - * Squares a number (multiplies a number by itself). The result is always a positive number, - * as multiplying two negative numbers always yields a positive result. For example, -1 * -1 = 1. - * - * @param {float} value int or float - * - * @returns {float} - * - * @see sqrt - */ - p.sq = function(aNumber) { - return aNumber * aNumber; - }; - - /** - * Converts a radian measurement to its corresponding value in degrees. Radians and degrees are two ways of - * measuring the same thing. There are 360 degrees in a circle and 2*PI radians in a circle. For example, - * 90 degrees = PI/2 = 1.5707964. All trigonometric methods in Processing require their parameters to be specified in radians. - * - * @param {int|float} value an angle in radians - * - * @returns {float} - * - * @see radians - */ - p.degrees = function(aAngle) { - return (aAngle * 180) / Math.PI; - }; - - /** - * Generates random numbers. Each time the random() function is called, it returns an unexpected value within - * the specified range. If one parameter is passed to the function it will return a float between zero and the - * value of the high parameter. The function call random(5) returns values between 0 and 5 (starting at zero, - * up to but not including 5). If two parameters are passed, it will return a float with a value between the - * parameters. The function call random(-5, 10.2) returns values starting at -5 up to (but not including) 10.2. - * To convert a floating-point random number to an integer, use the int() function. - * - * @param {int|float} value1 if one parameter is used, the top end to random from, if two params the low end - * @param {int|float} value2 the top end of the random range - * - * @returns {float} - * - * @see randomSeed - * @see noise - */ - p.random = function() { - if(arguments.length === 0) { - return internalRandomGenerator(); - } - if(arguments.length === 1) { - return internalRandomGenerator() * arguments[0]; - } - var aMin = arguments[0], aMax = arguments[1]; - return internalRandomGenerator() * (aMax - aMin) + aMin; - }; - - // Pseudo-random generator - function Marsaglia(i1, i2) { - // from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c - var z=i1 || 362436069, w= i2 || 521288629; - var intGenerator = function() { - z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF; - w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF; - return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF; - }; - - this.doubleGenerator = function() { - var i = intGenerator() / 4294967296; - return i < 0 ? 1 + i : i; - }; - this.intGenerator = intGenerator; - } - - Marsaglia.createRandomized = function() { - var now = new Date(); - return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF); - }; - - /** - * Sets the seed value for random(). By default, random() produces different results each time the - * program is run. Set the value parameter to a constant to return the same pseudo-random numbers - * each time the software is run. - * - * @param {int|float} seed int - * - * @see random - * @see noise - * @see noiseSeed - */ - p.randomSeed = function(seed) { - internalRandomGenerator = (new Marsaglia(seed, (seed<<16)+(seed>>16))).doubleGenerator; - this.haveNextNextGaussian = false; - }; - - /** - * Returns a float from a random series of numbers having a mean of 0 and standard deviation of 1. Each time - * the randomGaussian() function is called, it returns a number fitting a Gaussian, or normal, distribution. - * There is theoretically no minimum or maximum value that randomGaussian() might return. Rather, there is just a - * very low probability that values far from the mean will be returned; and a higher probability that numbers - * near the mean will be returned. - * - * @returns {float} - * - * @see random - * @see noise - */ - p.randomGaussian = function() { - if (this.haveNextNextGaussian) { - this.haveNextNextGaussian = false; - return this.nextNextGaussian; - } - var v1, v2, s; - do { - v1 = 2 * internalRandomGenerator() - 1; // between -1.0 and 1.0 - v2 = 2 * internalRandomGenerator() - 1; // between -1.0 and 1.0 - s = v1 * v1 + v2 * v2; - } - while (s >= 1 || s === 0); - - var multiplier = Math.sqrt(-2 * Math.log(s) / s); - this.nextNextGaussian = v2 * multiplier; - this.haveNextNextGaussian = true; - - return v1 * multiplier; - }; - - // Noise functions and helpers - function PerlinNoise(seed) { - var rnd = seed !== undef ? new Marsaglia(seed, (seed<<16)+(seed>>16)) : Marsaglia.createRandomized(); - var i, j; - // http://www.noisemachine.com/talk1/17b.html - // http://mrl.nyu.edu/~perlin/noise/ - // generate permutation - var perm = new Uint8Array(512); - for(i=0;i<256;++i) { perm[i] = i; } - for(i=0;i<256;++i) { - // NOTE: we can only do this because we've made sure the Marsaglia generator - // gives us numbers where the last byte in a pseudo-random number is - // still pseudo-random. If no 2nd argument is passed in the constructor, - // that is no longer the case and this pair swap will always run identically. - var t = perm[j = rnd.intGenerator() & 0xFF]; - perm[j] = perm[i]; - perm[i] = t; - } - // copy to avoid taking mod in perm[0]; - for(i=0;i<256;++i) { perm[i + 256] = perm[i]; } - - function grad3d(i,x,y,z) { - var h = i & 15; // convert into 12 gradient directions - var u = h<8 ? x : y, - v = h<4 ? y : h===12||h===14 ? x : z; - return ((h&1) === 0 ? u : -u) + ((h&2) === 0 ? v : -v); - } - - function grad2d(i,x,y) { - var v = (i & 1) === 0 ? x : y; - return (i&2) === 0 ? -v : v; - } - - function grad1d(i,x) { - return (i&1) === 0 ? -x : x; - } - - function lerp(t,a,b) { return a + t * (b - a); } - - this.noise3d = function(x, y, z) { - var X = Math.floor(x)&255, Y = Math.floor(y)&255, Z = Math.floor(z)&255; - x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z); - var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y, fz = (3-2*z)*z*z; - var p0 = perm[X]+Y, p00 = perm[p0] + Z, p01 = perm[p0 + 1] + Z, - p1 = perm[X + 1] + Y, p10 = perm[p1] + Z, p11 = perm[p1 + 1] + Z; - return lerp(fz, - lerp(fy, lerp(fx, grad3d(perm[p00], x, y, z), grad3d(perm[p10], x-1, y, z)), - lerp(fx, grad3d(perm[p01], x, y-1, z), grad3d(perm[p11], x-1, y-1,z))), - lerp(fy, lerp(fx, grad3d(perm[p00 + 1], x, y, z-1), grad3d(perm[p10 + 1], x-1, y, z-1)), - lerp(fx, grad3d(perm[p01 + 1], x, y-1, z-1), grad3d(perm[p11 + 1], x-1, y-1,z-1)))); - }; - - this.noise2d = function(x, y) { - var X = Math.floor(x)&255, Y = Math.floor(y)&255; - x -= Math.floor(x); y -= Math.floor(y); - var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y; - var p0 = perm[X]+Y, p1 = perm[X + 1] + Y; - return lerp(fy, - lerp(fx, grad2d(perm[p0], x, y), grad2d(perm[p1], x-1, y)), - lerp(fx, grad2d(perm[p0 + 1], x, y-1), grad2d(perm[p1 + 1], x-1, y-1))); - }; - - this.noise1d = function(x) { - var X = Math.floor(x)&255; - x -= Math.floor(x); - var fx = (3-2*x)*x*x; - return lerp(fx, grad1d(perm[X], x), grad1d(perm[X+1], x-1)); - }; - } - - // processing defaults - var noiseProfile = { generator: undef, octaves: 4, fallout: 0.5, seed: undef}; - - /** - * Returns the Perlin noise value at specified coordinates. Perlin noise is a random sequence - * generator producing a more natural ordered, harmonic succession of numbers compared to the - * standard random() function. It was invented by Ken Perlin in the 1980s and been used since - * in graphical applications to produce procedural textures, natural motion, shapes, terrains etc. - * The main difference to the random() function is that Perlin noise is defined in an infinite - * n-dimensional space where each pair of coordinates corresponds to a fixed semi-random value - * (fixed only for the lifespan of the program). The resulting value will always be between 0.0 - * and 1.0. Processing can compute 1D, 2D and 3D noise, depending on the number of coordinates - * given. The noise value can be animated by moving through the noise space as demonstrated in - * the example above. The 2nd and 3rd dimension can also be interpreted as time. - * The actual noise is structured similar to an audio signal, in respect to the function's use - * of frequencies. Similar to the concept of harmonics in physics, perlin noise is computed over - * several octaves which are added together for the final result. - * Another way to adjust the character of the resulting sequence is the scale of the input - * coordinates. As the function works within an infinite space the value of the coordinates - * doesn't matter as such, only the distance between successive coordinates does (eg. when using - * noise() within a loop). As a general rule the smaller the difference between coordinates, the - * smoother the resulting noise sequence will be. Steps of 0.005-0.03 work best for most applications, - * but this will differ depending on use. - * - * @param {float} x x coordinate in noise space - * @param {float} y y coordinate in noise space - * @param {float} z z coordinate in noise space - * - * @returns {float} - * - * @see random - * @see noiseDetail - */ - p.noise = function(x, y, z) { - if(noiseProfile.generator === undef) { - // caching - noiseProfile.generator = new PerlinNoise(noiseProfile.seed); - } - var generator = noiseProfile.generator; - var effect = 1, k = 1, sum = 0; - for(var i=0; i<noiseProfile.octaves; ++i) { - effect *= noiseProfile.fallout; - switch (arguments.length) { - case 1: - sum += effect * (1 + generator.noise1d(k*x))/2; break; - case 2: - sum += effect * (1 + generator.noise2d(k*x, k*y))/2; break; - case 3: - sum += effect * (1 + generator.noise3d(k*x, k*y, k*z))/2; break; - } - k *= 2; - } - return sum; - }; - - /** - * Adjusts the character and level of detail produced by the Perlin noise function. - * Similar to harmonics in physics, noise is computed over several octaves. Lower octaves - * contribute more to the output signal and as such define the overal intensity of the noise, - * whereas higher octaves create finer grained details in the noise sequence. By default, - * noise is computed over 4 octaves with each octave contributing exactly half than its - * predecessor, starting at 50% strength for the 1st octave. This falloff amount can be - * changed by adding an additional function parameter. Eg. a falloff factor of 0.75 means - * each octave will now have 75% impact (25% less) of the previous lower octave. Any value - * between 0.0 and 1.0 is valid, however note that values greater than 0.5 might result in - * greater than 1.0 values returned by noise(). By changing these parameters, the signal - * created by the noise() function can be adapted to fit very specific needs and characteristics. - * - * @param {int} octaves number of octaves to be used by the noise() function - * @param {float} falloff falloff factor for each octave - * - * @see noise - */ - p.noiseDetail = function(octaves, fallout) { - noiseProfile.octaves = octaves; - if(fallout !== undef) { - noiseProfile.fallout = fallout; - } - }; - - /** - * Sets the seed value for noise(). By default, noise() produces different results each - * time the program is run. Set the value parameter to a constant to return the same - * pseudo-random numbers each time the software is run. - * - * @param {int} seed int - * - * @returns {float} - * - * @see random - * @see radomSeed - * @see noise - * @see noiseDetail - */ - p.noiseSeed = function(seed) { - noiseProfile.seed = seed; - noiseProfile.generator = undef; - }; -}; - -},{}],24:[function(require,module,exports){ -/** - * Common functions traditionally on "p" that should be class functions - * that get bound to "p" when an instance is actually built, instead. - */ -module.exports = (function commonFunctions(undef) { - - var CommonFunctions = { - /** - * Remove whitespace characters from the beginning and ending - * of a String or a String array. Works like String.trim() but includes the - * unicode nbsp character as well. If an array is passed in the function will return a new array not effecting the array passed in. - * - * @param {String} str the string to trim - * @param {String[]} str the string array to trim - * - * @return {String|String[]} retrurns a string or an array will removed whitespaces - */ - trim: function(str) { - if (str instanceof Array) { - var arr = []; - for (var i = 0; i < str.length; i++) { - arr.push(str[i].replace(/^\s*/, '').replace(/\s*$/, '').replace(/\r*$/, '')); - } - return arr; - } - return str.replace(/^\s*/, '').replace(/\s*$/, '').replace(/\r*$/, ''); - }, - - /** - * Converts a degree measurement to its corresponding value in radians. Radians and degrees are two ways of - * measuring the same thing. There are 360 degrees in a circle and 2*PI radians in a circle. For example, - * 90 degrees = PI/2 = 1.5707964. All trigonometric methods in Processing require their parameters to be specified in radians. - * - * @param {int|float} value an angle in radians - * - * @returns {float} - * - * @see degrees - */ - radians: function(aAngle) { - return (aAngle / 180) * Math.PI; - }, - - /** - * Number-to-String formatting function. Prepends "plus" or "minus" depending - * on whether the value is positive or negative, respectively, after padding - * the value with zeroes on the left and right, the number of zeroes used dictated - * by the values 'leftDigits' and 'rightDigits'. 'value' cannot be an array. - * - * @param {int|float} value the number to format - * @param {String} plus the prefix for positive numbers - * @param {String} minus the prefix for negative numbers - * @param {int} left number of digits to the left of the decimal point - * @param {int} right number of digits to the right of the decimal point - * @param {String} group string delimited for groups, such as the comma in "1,000" - * - * @returns {String or String[]} - * - * @see nfCore - */ - nfCoreScalar: function (value, plus, minus, leftDigits, rightDigits, group) { - var sign = (value < 0) ? minus : plus; - var autoDetectDecimals = rightDigits === 0; - var rightDigitsOfDefault = (rightDigits === undef || rightDigits < 0) ? 0 : rightDigits; - - var absValue = Math.abs(value); - if (autoDetectDecimals) { - rightDigitsOfDefault = 1; - absValue *= 10; - while (Math.abs(Math.round(absValue) - absValue) > 1e-6 && rightDigitsOfDefault < 7) { - ++rightDigitsOfDefault; - absValue *= 10; - } - } else if (rightDigitsOfDefault !== 0) { - absValue *= Math.pow(10, rightDigitsOfDefault); - } - - // Using Java's default rounding policy HALF_EVEN. This policy is based - // on the idea that 0.5 values round to the nearest even number, and - // everything else is rounded normally. - var number, doubled = absValue * 2; - if (Math.floor(absValue) === absValue) { - number = absValue; - } else if (Math.floor(doubled) === doubled) { - var floored = Math.floor(absValue); - number = floored + (floored % 2); - } else { - number = Math.round(absValue); - } - - var buffer = ""; - var totalDigits = leftDigits + rightDigitsOfDefault; - while (totalDigits > 0 || number > 0) { - totalDigits--; - buffer = "" + (number % 10) + buffer; - number = Math.floor(number / 10); - } - if (group !== undef) { - var i = buffer.length - 3 - rightDigitsOfDefault; - while(i > 0) { - buffer = buffer.substring(0,i) + group + buffer.substring(i); - i-=3; - } - } - if (rightDigitsOfDefault > 0) { - return sign + buffer.substring(0, buffer.length - rightDigitsOfDefault) + - "." + buffer.substring(buffer.length - rightDigitsOfDefault, buffer.length); - } - return sign + buffer; - }, - - /** - * Number-to-String formatting function. Prepends "plus" or "minus" depending - * on whether the value is positive or negative, respectively, after padding - * the value with zeroes on the left and right, the number of zeroes used dictated - * by the values 'leftDigits' and 'rightDigits'. 'value' can be an array; - * if the input is an array, each value in it is formatted separately, and - * an array with formatted values is returned. - * - * @param {int|int[]|float|float[]} value the number(s) to format - * @param {String} plus the prefix for positive numbers - * @param {String} minus the prefix for negative numbers - * @param {int} left number of digits to the left of the decimal point - * @param {int} right number of digits to the right of the decimal point - * @param {String} group string delimited for groups, such as the comma in "1,000" - * - * @returns {String or String[]} - * - * @see nfCoreScalar - */ - nfCore: function(value, plus, minus, leftDigits, rightDigits, group) { - if (value instanceof Array) { - var arr = []; - for (var i = 0, len = value.length; i < len; i++) { - arr.push(CommonFunctions.nfCoreScalar(value[i], plus, minus, leftDigits, rightDigits, group)); - } - return arr; - } - return CommonFunctions.nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group); - }, - - /** - * Utility function for formatting numbers into strings. There are two versions, one for - * formatting floats and one for formatting ints. The values for the digits, left, and - * right parameters should always be positive integers. - * As shown in the above example, nf() is used to add zeros to the left and/or right - * of a number. This is typically for aligning a list of numbers. To remove digits from - * a floating-point number, use the int(), ceil(), floor(), or round() functions. - * - * @param {int|int[]|float|float[]} value the number(s) to format - * @param {int} left number of digits to the left of the decimal point - * @param {int} right number of digits to the right of the decimal point - * - * @returns {String or String[]} - * - * @see nfs - * @see nfp - * @see nfc - */ - nf: function(value, leftDigits, rightDigits) { - return CommonFunctions.nfCore(value, "", "-", leftDigits, rightDigits); - }, - - /** - * Utility function for formatting numbers into strings. Similar to nf() but leaves a blank space in front - * of positive numbers so they align with negative numbers in spite of the minus symbol. There are two - * versions, one for formatting floats and one for formatting ints. The values for the digits, left, - * and right parameters should always be positive integers. - * - * @param {int|int[]|float|float[]} value the number(s) to format - * @param {int} left number of digits to the left of the decimal point - * @param {int} right number of digits to the right of the decimal point - * - * @returns {String or String[]} - * - * @see nf - * @see nfp - * @see nfc - */ - nfs: function(value, leftDigits, rightDigits) { - return CommonFunctions.nfCore(value, " ", "-", leftDigits, rightDigits); - }, - - /** - * Utility function for formatting numbers into strings. Similar to nf() but puts a "+" in front of - * positive numbers and a "-" in front of negative numbers. There are two versions, one for formatting - * floats and one for formatting ints. The values for the digits, left, and right parameters should - * always be positive integers. - * - * @param {int|int[]|float|float[]} value the number(s) to format - * @param {int} left number of digits to the left of the decimal point - * @param {int} right number of digits to the right of the decimal point - * - * @returns {String or String[]} - * - * @see nfs - * @see nf - * @see nfc - */ - nfp: function(value, leftDigits, rightDigits) { - return CommonFunctions.nfCore(value, "+", "-", leftDigits, rightDigits); - }, - - /** - * Utility function for formatting numbers into strings and placing appropriate commas to mark - * units of 1000. There are two versions, one for formatting ints and one for formatting an array - * of ints. The value for the digits parameter should always be a positive integer. - * - * @param {int|int[]|float|float[]} value the number(s) to format - * @param {int} left number of digits to the left of the decimal point - * @param {int} right number of digits to the right of the decimal point - * - * @returns {String or String[]} - * - * @see nf - * @see nfs - * @see nfp - */ - nfc: function(value, rightDigits) { - return CommonFunctions.nfCore(value, "", "-", 0, rightDigits, ","); - }, - - // used to bind all common functions to "p" - withCommonFunctions: function withCommonFunctions(p) { - ["trim", "radians", "nf", "nfs", "nfp", "nfc"].forEach(function(f){ - p[f] = CommonFunctions[f]; - }); - } - }; - - return CommonFunctions; -}()); - -},{}],25:[function(require,module,exports){ -/** - * Touch and Mouse event handling - */ -module.exports = function withTouch(p, curElement, attachEventHandler, document, PConstants, undef) { - - /** - * Determine the location of the (mouse) pointer. - */ - function calculateOffset(curElement, event) { - var element = curElement, - offsetX = 0, - offsetY = 0; - - p.pmouseX = p.mouseX; - p.pmouseY = p.mouseY; - - // Find element offset - if (element.offsetParent) { - do { - offsetX += element.offsetLeft; - offsetY += element.offsetTop; - } while (!!(element = element.offsetParent)); - } - - // Find Scroll offset - element = curElement; - do { - offsetX -= element.scrollLeft || 0; - offsetY -= element.scrollTop || 0; - } while (!!(element = element.parentNode)); - - // Get padding and border style widths for mouse offsets - var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop; - if (document.defaultView && document.defaultView.getComputedStyle) { - stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(curElement, null).paddingLeft, 10) || 0; - stylePaddingTop = parseInt(document.defaultView.getComputedStyle(curElement, null).paddingTop, 10) || 0; - styleBorderLeft = parseInt(document.defaultView.getComputedStyle(curElement, null).borderLeftWidth, 10) || 0; - styleBorderTop = parseInt(document.defaultView.getComputedStyle(curElement, null).borderTopWidth, 10) || 0; - } - - // Add padding and border style widths to offset - offsetX += stylePaddingLeft; - offsetY += stylePaddingTop; - - offsetX += styleBorderLeft; - offsetY += styleBorderTop; - - // Take into account any scrolling done - offsetX += window.pageXOffset; - offsetY += window.pageYOffset; - - return {'X':offsetX,'Y':offsetY}; - } - - // simple relative position - function updateMousePosition(curElement, event) { - var offset = calculateOffset(curElement, event); - // Dropping support for IE clientX and clientY, switching to pageX and pageY - // so we don't have to calculate scroll offset. - // Removed in ticket #184. See rev: 2f106d1c7017fed92d045ba918db47d28e5c16f4 - p.mouseX = event.pageX - offset.X; - p.mouseY = event.pageY - offset.Y; - } - - /** - * Return a TouchEvent with canvas-specific x/y co-ordinates - */ - function addTouchEventOffset(t) { - var offset = calculateOffset(t.changedTouches[0].target, t.changedTouches[0]), - i; - - for (i = 0; i < t.touches.length; i++) { - var touch = t.touches[i]; - touch.offsetX = touch.pageX - offset.X; - touch.offsetY = touch.pageY - offset.Y; - } - for (i = 0; i < t.targetTouches.length; i++) { - var targetTouch = t.targetTouches[i]; - targetTouch.offsetX = targetTouch.pageX - offset.X; - targetTouch.offsetY = targetTouch.pageY - offset.Y; - } - for (i = 0; i < t.changedTouches.length; i++) { - var changedTouch = t.changedTouches[i]; - changedTouch.offsetX = changedTouch.pageX - offset.X; - changedTouch.offsetY = changedTouch.pageY - offset.Y; - } - - return t; - } - - /** - * Touch event support. - */ - attachEventHandler(curElement, "touchstart", function (t) { - // Removes unwanted behaviour of the canvas when touching canvas - curElement.setAttribute("style","-webkit-user-select: none"); - curElement.setAttribute("onclick","void(0)"); - curElement.setAttribute("style","-webkit-tap-highlight-color:rgba(0,0,0,0)"); - // Loop though eventHandlers and remove mouse listeners - for (var i=0, ehl=eventHandlers.length; i<ehl; i++) { - var type = eventHandlers[i].type; - // Have this function remove itself from the eventHandlers list too - if (type === "mouseout" || type === "mousemove" || - type === "mousedown" || type === "mouseup" || - type === "DOMMouseScroll" || type === "mousewheel" || type === "touchstart") { - detachEventHandler(eventHandlers[i]); - } - } - - // If there are any native touch events defined in the sketch, connect all of them - // Otherwise, connect all of the emulated mouse events - if (p.touchStart !== undef || p.touchMove !== undef || - p.touchEnd !== undef || p.touchCancel !== undef) { - attachEventHandler(curElement, "touchstart", function(t) { - if (p.touchStart !== undef) { - t = addTouchEventOffset(t); - p.touchStart(t); - } - }); - - attachEventHandler(curElement, "touchmove", function(t) { - if (p.touchMove !== undef) { - t.preventDefault(); // Stop the viewport from scrolling - t = addTouchEventOffset(t); - p.touchMove(t); - } - }); - - attachEventHandler(curElement, "touchend", function(t) { - if (p.touchEnd !== undef) { - t = addTouchEventOffset(t); - p.touchEnd(t); - } - }); - - attachEventHandler(curElement, "touchcancel", function(t) { - if (p.touchCancel !== undef) { - t = addTouchEventOffset(t); - p.touchCancel(t); - } - }); - - } else { - // Emulated touch start/mouse down event - attachEventHandler(curElement, "touchstart", function(e) { - updateMousePosition(curElement, e.touches[0]); - - p.__mousePressed = true; - p.mouseDragging = false; - p.mouseButton = PConstants.LEFT; - - if (typeof p.mousePressed === "function") { - p.mousePressed(); - } - }); - - // Emulated touch move/mouse move event - attachEventHandler(curElement, "touchmove", function(e) { - e.preventDefault(); - updateMousePosition(curElement, e.touches[0]); - - if (typeof p.mouseMoved === "function" && !p.__mousePressed) { - p.mouseMoved(); - } - if (typeof p.mouseDragged === "function" && p.__mousePressed) { - p.mouseDragged(); - p.mouseDragging = true; - } - }); - - // Emulated touch up/mouse up event - attachEventHandler(curElement, "touchend", function(e) { - p.__mousePressed = false; - - if (typeof p.mouseClicked === "function" && !p.mouseDragging) { - p.mouseClicked(); - } - - if (typeof p.mouseReleased === "function") { - p.mouseReleased(); - } - }); - } - - // Refire the touch start event we consumed in this function - curElement.dispatchEvent(t); - }); - - /** - * Context menu toggles. Most often you will not want the - * browser's context menu to show on a right click, but - * sometimes, you do, so we add two unofficial functions - * that can be used to trigger context menu behaviour. - */ - (function() { - var enabled = true, - contextMenu = function(e) { - e.preventDefault(); - e.stopPropagation(); - }; - - p.disableContextMenu = function() { - if (!enabled) { - return; - } - attachEventHandler(curElement, 'contextmenu', contextMenu); - enabled = false; - }; - - p.enableContextMenu = function() { - if (enabled) { - return; - } - detachEventHandler({elem: curElement, type: 'contextmenu', fn: contextMenu}); - enabled = true; - }; - }()); - - /** - * Mouse moved or dragged - */ - attachEventHandler(curElement, "mousemove", function(e) { - updateMousePosition(curElement, e); - if (typeof p.mouseMoved === "function" && !p.__mousePressed) { - p.mouseMoved(); - } - if (typeof p.mouseDragged === "function" && p.__mousePressed) { - p.mouseDragged(); - p.mouseDragging = true; - } - }); - - /** - * Unofficial mouse-out handling - */ - attachEventHandler(curElement, "mouseout", function(e) { - if (typeof p.mouseOut === "function") { - p.mouseOut(); - } - }); - - /** - * Mouse over - */ - attachEventHandler(curElement, "mouseover", function(e) { - updateMousePosition(curElement, e); - if (typeof p.mouseOver === "function") { - p.mouseOver(); - } - }); - - /** - * Disable browser's default handling for click-drag of a canvas. - */ - curElement.onmousedown = function () { - // make sure focus happens, but nothing else - curElement.focus(); - return false; - }; - - /** - * Mouse pressed or drag - */ - attachEventHandler(curElement, "mousedown", function(e) { - p.__mousePressed = true; - p.mouseDragging = false; - switch (e.which) { - case 1: - p.mouseButton = PConstants.LEFT; - break; - case 2: - p.mouseButton = PConstants.CENTER; - break; - case 3: - p.mouseButton = PConstants.RIGHT; - break; - } - - if (typeof p.mousePressed === "function") { - p.mousePressed(); - } - }); - - /** - * Mouse clicked or released - */ - attachEventHandler(curElement, "mouseup", function(e) { - p.__mousePressed = false; - - if (typeof p.mouseClicked === "function" && !p.mouseDragging) { - p.mouseClicked(); - } - - if (typeof p.mouseReleased === "function") { - p.mouseReleased(); - } - }); - - /** - * Unofficial scroll wheel handling. - */ - var mouseWheelHandler = function(e) { - var delta = 0; - - if (e.wheelDelta) { - delta = e.wheelDelta / 120; - if (window.opera) { - delta = -delta; - } - } else if (e.detail) { - delta = -e.detail / 3; - } - - p.mouseScroll = delta; - - if (delta && typeof p.mouseScrolled === 'function') { - p.mouseScrolled(); - } - }; - - // Support Gecko and non-Gecko scroll events - attachEventHandler(document, 'DOMMouseScroll', mouseWheelHandler); - attachEventHandler(document, 'mousewheel', mouseWheelHandler); - -}; - -},{}],26:[function(require,module,exports){ -/** - * The parser for turning Processing syntax into Pjs JavaScript. - * This code is not trivial; unless you know what you're doing, - * you shouldn't be changing things in here =) - */ -module.exports = function setupParser(Processing, options) { - - var defaultScope = options.defaultScope, - PConstants = defaultScope.PConstants, - aFunctions = options.aFunctions, - Browser = options.Browser, - document = Browser.document, - undef; - - // Processing global methods and constants for the parser - function getGlobalMembers() { - // The names array contains the names of everything that is inside "p." - // When something new is added to "p." it must also be added to this list. - var names = [ /* this code is generated by jsglobals.js */ - "abs", "acos", "alpha", "ambient", "ambientLight", "append", "applyMatrix", - "arc", "arrayCopy", "asin", "atan", "atan2", "background", "beginCamera", - "beginDraw", "beginShape", "bezier", "bezierDetail", "bezierPoint", - "bezierTangent", "bezierVertex", "binary", "blend", "blendColor", - "blit_resize", "blue", "box", "breakShape", "brightness", - "camera", "ceil", "Character", "color", "colorMode", - "concat", "constrain", "copy", "cos", "createFont", - "createGraphics", "createImage", "cursor", "curve", "curveDetail", - "curvePoint", "curveTangent", "curveTightness", "curveVertex", "day", - "degrees", "directionalLight", "disableContextMenu", - "dist", "draw", "ellipse", "ellipseMode", "emissive", "enableContextMenu", - "endCamera", "endDraw", "endShape", "exit", "exp", "expand", "externals", - "fill", "filter", "floor", "focused", "frameCount", "frameRate", "frustum", - "get", "glyphLook", "glyphTable", "green", "height", "hex", "hint", "hour", - "hue", "image", "imageMode", "intersect", "join", "key", - "keyCode", "keyPressed", "keyReleased", "keyTyped", "lerp", "lerpColor", - "lightFalloff", "lights", "lightSpecular", "line", "link", "loadBytes", - "loadFont", "loadGlyphs", "loadImage", "loadPixels", "loadShape", "loadXML", - "loadStrings", "log", "loop", "mag", "map", "match", "matchAll", "max", - "millis", "min", "minute", "mix", "modelX", "modelY", "modelZ", "modes", - "month", "mouseButton", "mouseClicked", "mouseDragged", "mouseMoved", - "mouseOut", "mouseOver", "mousePressed", "mouseReleased", "mouseScroll", - "mouseScrolled", "mouseX", "mouseY", "name", "nf", "nfc", "nfp", "nfs", - "noCursor", "noFill", "noise", "noiseDetail", "noiseSeed", "noLights", - "noLoop", "norm", "normal", "noSmooth", "noStroke", "noTint", "ortho", - "param", "parseBoolean", "parseByte", "parseChar", "parseFloat", - "parseInt", "parseXML", "peg", "perspective", "PImage", "pixels", - "PMatrix2D", "PMatrix3D", "PMatrixStack", "pmouseX", "pmouseY", "point", - "pointLight", "popMatrix", "popStyle", "pow", "print", "printCamera", - "println", "printMatrix", "printProjection", "PShape", "PShapeSVG", - "pushMatrix", "pushStyle", "quad", "radians", "random", "randomGaussian", - "randomSeed", "rect", "rectMode", "red", "redraw", "requestImage", - "resetMatrix", "reverse", "rotate", "rotateX", "rotateY", "rotateZ", - "round", "saturation", "save", "saveFrame", "saveStrings", "scale", - "screenX", "screenY", "screenZ", "second", "set", "setup", "shape", - "shapeMode", "shared", "shearX", "shearY", "shininess", "shorten", "sin", "size", "smooth", - "sort", "specular", "sphere", "sphereDetail", "splice", "split", - "splitTokens", "spotLight", "sq", "sqrt", "status", "str", "stroke", - "strokeCap", "strokeJoin", "strokeWeight", "subset", "tan", "text", - "textAlign", "textAscent", "textDescent", "textFont", "textLeading", - "textMode", "textSize", "texture", "textureMode", "textWidth", "tint", "toImageData", - "touchCancel", "touchEnd", "touchMove", "touchStart", "translate", "transform", - "triangle", "trim", "unbinary", "unhex", "updatePixels", "use3DContext", - "vertex", "width", "XMLElement", "XML", "year", "__contains", "__equals", - "__equalsIgnoreCase", "__frameRate", "__hashCode", "__int_cast", - "__instanceof", "__keyPressed", "__mousePressed", "__printStackTrace", - "__replace", "__replaceAll", "__replaceFirst", "__toCharArray", "__split", - "__codePointAt", "__startsWith", "__endsWith", "__matches"]; - - // custom functions and properties are added here - if(aFunctions) { - Object.keys(aFunctions).forEach(function(name) { - names.push(name); - }); - } - - // custom libraries that were attached to Processing - var members = {}; - var i, l; - for (i = 0, l = names.length; i < l ; ++i) { - members[names[i]] = null; - } - for (var lib in Processing.lib) { - if (Processing.lib.hasOwnProperty(lib)) { - if (Processing.lib[lib].exports) { - var exportedNames = Processing.lib[lib].exports; - for (i = 0, l = exportedNames.length; i < l; ++i) { - members[exportedNames[i]] = null; - } - } - } - } - return members; - } - - /* - - Parser converts Java-like syntax into JavaScript. - Creates an Abstract Syntax Tree -- "Light AST" from the Java-like code. - - It is an object tree. The root object is created from the AstRoot class, which contains statements. - - A statement object can be of type: AstForStatement, AstCatchStatement, AstPrefixStatement, AstMethod, AstClass, - AstInterface, AstFunction, AstStatementBlock and AstLabel. - - AstPrefixStatement can be a statement of type: if, switch, while, with, do, else, finally, return, throw, try, break, and continue. - - These object's toString function returns the JavaScript code for the statement. - - Any processing calls need "processing." prepended to them. - - Similarly, calls from inside classes need "$this_1.", prepended to them, - with 1 being the depth level for inner classes. - This includes members passed down from inheritance. - - The resulting code is then eval'd and run. - - */ - - function parseProcessing(code) { - var globalMembers = getGlobalMembers(); - - // masks parentheses, brackets and braces with '"A5"' - // where A is the bracket type, and 5 is the index in an array containing all brackets split into atoms - // 'while(true){}' -> 'while"B1""A2"' - // parentheses() = B, brackets[] = C and braces{} = A - function splitToAtoms(code) { - var atoms = []; - var items = code.split(/([\{\[\(\)\]\}])/); - var result = items[0]; - - var stack = []; - for(var i=1; i < items.length; i += 2) { - var item = items[i]; - if(item === '[' || item === '{' || item === '(') { - stack.push(result); result = item; - } else if(item === ']' || item === '}' || item === ')') { - var kind = item === '}' ? 'A' : item === ')' ? 'B' : 'C'; - var index = atoms.length; atoms.push(result + item); - result = stack.pop() + '"' + kind + (index + 1) + '"'; - } - result += items[i + 1]; - } - atoms.unshift(result); - return atoms; - } - - // replaces strings and regexs keyed by index with an array of strings - function injectStrings(code, strings) { - return code.replace(/'(\d+)'/g, function(all, index) { - var val = strings[index]; - if(val.charAt(0) === "/") { - return val; - } - return (/^'((?:[^'\\\n])|(?:\\.[0-9A-Fa-f]*))'$/).test(val) ? "(new $p.Character(" + val + "))" : val; - }); - } - - // trims off leading and trailing spaces - // returns an object. object.left, object.middle, object.right, object.untrim - function trimSpaces(string) { - var m1 = /^\s*/.exec(string), result; - if(m1[0].length === string.length) { - result = {left: m1[0], middle: "", right: ""}; - } else { - var m2 = /\s*$/.exec(string); - result = {left: m1[0], middle: string.substring(m1[0].length, m2.index), right: m2[0]}; - } - result.untrim = function(t) { return this.left + t + this.right; }; - return result; - } - - // simple trim of leading and trailing spaces - function trim(string) { - return string.replace(/^\s+/,'').replace(/\s+$/,''); - } - - function appendToLookupTable(table, array) { - for(var i=0,l=array.length;i<l;++i) { - table[array[i]] = null; - } - return table; - } - - function isLookupTableEmpty(table) { - for(var i in table) { - if(table.hasOwnProperty(i)) { - return false; - } - } - return true; - } - - function getAtomIndex(templ) { return templ.substring(2, templ.length - 1); } - - // remove carriage returns "\r" - var codeWoExtraCr = code.replace(/\r\n?|\n\r/g, "\n"); - - // masks strings and regexs with "'5'", where 5 is the index in an array containing all strings and regexs - // also removes all comments - var strings = []; - var codeWoStrings = codeWoExtraCr.replace(/("(?:[^"\\\n]|\\.)*")|('(?:[^'\\\n]|\\.)*')|(([\[\(=|&!\^:?]\s*)(\/(?![*\/])(?:[^\/\\\n]|\\.)*\/[gim]*)\b)|(\/\/[^\n]*\n)|(\/\*(?:(?!\*\/)(?:.|\n))*\*\/)/g, - function(all, quoted, aposed, regexCtx, prefix, regex, singleComment, comment) { - var index; - if(quoted || aposed) { // replace strings - index = strings.length; strings.push(all); - return "'" + index + "'"; - } - if(regexCtx) { // replace RegExps - index = strings.length; strings.push(regex); - return prefix + "'" + index + "'"; - } - // kill comments - return comment !== "" ? " " : "\n"; - }); - - // protect character codes from namespace collision - codeWoStrings = codeWoStrings.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { - // $ = __x0024 - // _ = __x005F - // this protects existing character codes from conversion - // __x0024 = __x005F_x0024 - return "__x005F_x" + hexCode; - }); - - // convert dollar sign to character code - codeWoStrings = codeWoStrings.replace(/\$/g, "__x0024"); - - // Remove newlines after return statements - codeWoStrings = codeWoStrings.replace(/return\s*[\n\r]+/g, "return "); - - // removes generics - var genericsWereRemoved; - var codeWoGenerics = codeWoStrings; - var replaceFunc = function(all, before, types, after) { - if(!!before || !!after) { - return all; - } - genericsWereRemoved = true; - return ""; - }; - - do { - genericsWereRemoved = false; - codeWoGenerics = codeWoGenerics.replace(/([<]?)<\s*((?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?(?:\s*,\s*(?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?)*)\s*>([=]?)/g, replaceFunc); - } while (genericsWereRemoved); - - var atoms = splitToAtoms(codeWoGenerics); - var replaceContext; - var declaredClasses = {}, currentClassId, classIdSeed = 0; - - function addAtom(text, type) { - var lastIndex = atoms.length; - atoms.push(text); - return '"' + type + lastIndex + '"'; - } - - function generateClassId() { - return "class" + (++classIdSeed); - } - - function appendClass(class_, classId, scopeId) { - class_.classId = classId; - class_.scopeId = scopeId; - declaredClasses[classId] = class_; - } - - // functions defined below - var transformClassBody, transformInterfaceBody, transformStatementsBlock, transformStatements, transformMain, transformExpression; - - var classesRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)(class|interface)\s+([A-Za-z_$][\w$]*\b)(\s+extends\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?(\s+implements\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?\s*("A\d+")/g; - var methodsRegex = /\b((?:(?:public|private|final|protected|static|abstract|synchronized)\s+)*)((?!(?:else|new|return|throw|function|public|private|protected)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+"|;)/g; - var fieldTest = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:else|new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*(?:"C\d+"\s*)*([=,]|$)/; - var cstrsRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+")/g; - var attrAndTypeRegex = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*/; - var functionsRegex = /\bfunction(?:\s+([A-Za-z_$][\w$]*))?\s*("B\d+")\s*("A\d+")/g; - - // This converts classes, methods and functions into atoms, and adds them to the atoms array. - // classes = E, methods = D and functions = H - function extractClassesAndMethods(code) { - var s = code; - s = s.replace(classesRegex, function(all) { - return addAtom(all, 'E'); - }); - s = s.replace(methodsRegex, function(all) { - return addAtom(all, 'D'); - }); - s = s.replace(functionsRegex, function(all) { - return addAtom(all, 'H'); - }); - return s; - } - - // This converts constructors into atoms, and adds them to the atoms array. - // constructors = G - function extractConstructors(code, className) { - var result = code.replace(cstrsRegex, function(all, attr, name, params, throws_, body) { - if(name !== className) { - return all; - } - return addAtom(all, 'G'); - }); - return result; - } - - // AstParam contains the name of a parameter inside a function declaration - function AstParam(name) { - this.name = name; - } - AstParam.prototype.toString = function() { - return this.name; - }; - // AstParams contains an array of AstParam objects - function AstParams(params, methodArgsParam) { - this.params = params; - this.methodArgsParam = methodArgsParam; - } - AstParams.prototype.getNames = function() { - var names = []; - for(var i=0,l=this.params.length;i<l;++i) { - names.push(this.params[i].name); - } - return names; - }; - AstParams.prototype.prependMethodArgs = function(body) { - if (!this.methodArgsParam) { - return body; - } - return "{\nvar " + this.methodArgsParam.name + - " = Array.prototype.slice.call(arguments, " + - this.params.length + ");\n" + body.substring(1); - }; - AstParams.prototype.toString = function() { - if(this.params.length === 0) { - return "()"; - } - var result = "("; - for(var i=0,l=this.params.length;i<l;++i) { - result += this.params[i] + ", "; - } - return result.substring(0, result.length - 2) + ")"; - }; - - function transformParams(params) { - var paramsWoPars = trim(params.substring(1, params.length - 1)); - var result = [], methodArgsParam = null; - if(paramsWoPars !== "") { - var paramList = paramsWoPars.split(","); - for(var i=0; i < paramList.length; ++i) { - var param = /\b([A-Za-z_$][\w$]*\b)(\s*"[ABC][\d]*")*\s*$/.exec(paramList[i]); - if (i === paramList.length - 1 && paramList[i].indexOf('...') >= 0) { - methodArgsParam = new AstParam(param[1]); - break; - } - result.push(new AstParam(param[1])); - } - } - return new AstParams(result, methodArgsParam); - } - - function preExpressionTransform(expr) { - var s = expr; - // new type[] {...} --> {...} - s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"C\d+")+\s*("A\d+")/g, function(all, type, init) { - return init; - }); - // new Runnable() {...} --> "F???" - s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"B\d+")\s*("A\d+")/g, function(all, type, init) { - return addAtom(all, 'F'); - }); - // function(...) { } --> "H???" - s = s.replace(functionsRegex, function(all) { - return addAtom(all, 'H'); - }); - // new type[?] --> createJavaArray('type', [?]) - s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*("C\d+"(?:\s*"C\d+")*)/g, function(all, type, index) { - var args = index.replace(/"C(\d+)"/g, function(all, j) { return atoms[j]; }) - .replace(/\[\s*\]/g, "[null]").replace(/\s*\]\s*\[\s*/g, ", "); - var arrayInitializer = "{" + args.substring(1, args.length - 1) + "}"; - var createArrayArgs = "('" + type + "', " + addAtom(arrayInitializer, 'A') + ")"; - return '$p.createJavaArray' + addAtom(createArrayArgs, 'B'); - }); - // .length() --> .length - s = s.replace(/(\.\s*length)\s*"B\d+"/g, "$1"); - // #000000 --> 0x000000 - s = s.replace(/#([0-9A-Fa-f]{6})\b/g, function(all, digits) { - return "0xFF" + digits; - }); - // delete (type)???, except (int)??? - s = s.replace(/"B(\d+)"(\s*(?:[\w$']|"B))/g, function(all, index, next) { - var atom = atoms[index]; - if(!/^\(\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\s*(?:"C\d+"\s*)*\)$/.test(atom)) { - return all; - } - if(/^\(\s*int\s*\)$/.test(atom)) { - return "(int)" + next; - } - var indexParts = atom.split(/"C(\d+)"/g); - if(indexParts.length > 1) { - // even items contains atom numbers, can check only first - if(! /^\[\s*\]$/.test(atoms[indexParts[1]])) { - return all; // fallback - not a cast - } - } - return "" + next; - }); - // (int)??? -> __int_cast(???) - s = s.replace(/\(int\)([^,\]\)\}\?\:\*\+\-\/\^\|\%\&\~<\>\=]+)/g, function(all, arg) { - var trimmed = trimSpaces(arg); - return trimmed.untrim("__int_cast(" + trimmed.middle + ")"); - }); - // super() -> $superCstr(), super. -> $super.; - s = s.replace(/\bsuper(\s*"B\d+")/g, "$$superCstr$1").replace(/\bsuper(\s*\.)/g, "$$super$1"); - // 000.43->0.43 and 0010f->10, but not 0010 - s = s.replace(/\b0+((\d*)(?:\.[\d*])?(?:[eE][\-\+]?\d+)?[fF]?)\b/, function(all, numberWo0, intPart) { - if( numberWo0 === intPart) { - return all; - } - return intPart === "" ? "0" + numberWo0 : numberWo0; - }); - // 3.0f -> 3.0 - s = s.replace(/\b(\.?\d+\.?)[fF]\b/g, "$1"); - // Weird (?) parsing errors with % - s = s.replace(/([^\s])%([^=\s])/g, "$1 % $2"); - // Since frameRate() and frameRate are different things, - // we need to differentiate them somehow. So when we parse - // the Processing.js source, replace frameRate so it isn't - // confused with frameRate(), as well as keyPressed and mousePressed - s = s.replace(/\b(frameRate|keyPressed|mousePressed)\b(?!\s*"B)/g, "__$1"); - // "boolean", "byte", "int", etc. => "parseBoolean", "parseByte", "parseInt", etc. - s = s.replace(/\b(boolean|byte|char|float|int)\s*"B/g, function(all, name) { - return "parse" + name.substring(0, 1).toUpperCase() + name.substring(1) + "\"B"; - }); - // "pixels" replacements: - // pixels[i] = c => pixels.setPixel(i,c) | pixels[i] => pixels.getPixel(i) - // pixels.length => pixels.getLength() - // pixels = ar => pixels.set(ar) | pixels => pixels.toArray() - s = s.replace(/\bpixels\b\s*(("C(\d+)")|\.length)?(\s*=(?!=)([^,\]\)\}]+))?/g, - function(all, indexOrLength, index, atomIndex, equalsPart, rightSide) { - if(index) { - var atom = atoms[atomIndex]; - if(equalsPart) { - return "pixels.setPixel" + addAtom("(" +atom.substring(1, atom.length - 1) + - "," + rightSide + ")", 'B'); - } - return "pixels.getPixel" + addAtom("(" + atom.substring(1, atom.length - 1) + - ")", 'B'); - } - if(indexOrLength) { - // length - return "pixels.getLength" + addAtom("()", 'B'); - } - if(equalsPart) { - return "pixels.set" + addAtom("(" + rightSide + ")", 'B'); - } - return "pixels.toArray" + addAtom("()", 'B'); - }); - // Java method replacements for: replace, replaceAll, replaceFirst, equals, hashCode, etc. - // xxx.replace(yyy) -> __replace(xxx, yyy) - // "xx".replace(yyy) -> __replace("xx", yyy) - var repeatJavaReplacement; - function replacePrototypeMethods(all, subject, method, atomIndex) { - var atom = atoms[atomIndex]; - repeatJavaReplacement = true; - var trimmed = trimSpaces(atom.substring(1, atom.length - 1)); - return "__" + method + ( trimmed.middle === "" ? addAtom("(" + subject.replace(/\.\s*$/, "") + ")", 'B') : - addAtom("(" + subject.replace(/\.\s*$/, "") + "," + trimmed.middle + ")", 'B') ); - } - do { - repeatJavaReplacement = false; - s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*\.\s*(?:[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*\.\s*)*)(replace|replaceAll|replaceFirst|contains|equals|equalsIgnoreCase|hashCode|toCharArray|printStackTrace|split|startsWith|endsWith|codePointAt|matches)\s*"B(\d+)"/g, - replacePrototypeMethods); - } while (repeatJavaReplacement); - // xxx instanceof yyy -> __instanceof(xxx, yyy) - function replaceInstanceof(all, subject, type) { - repeatJavaReplacement = true; - return "__instanceof" + addAtom("(" + subject + ", " + type + ")", 'B'); - } - do { - repeatJavaReplacement = false; - s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*(?:\.\s*[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*)*)instanceof\s+([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)/g, - replaceInstanceof); - } while (repeatJavaReplacement); - // this() -> $constr() - s = s.replace(/\bthis(\s*"B\d+")/g, "$$constr$1"); - - return s; - } - - function AstInlineClass(baseInterfaceName, body) { - this.baseInterfaceName = baseInterfaceName; - this.body = body; - body.owner = this; - } - AstInlineClass.prototype.toString = function() { - return "new (" + this.body + ")"; - }; - - function transformInlineClass(class_) { - var m = new RegExp(/\bnew\s*([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)\s*"B\d+"\s*"A(\d+)"/).exec(class_); - var oldClassId = currentClassId, newClassId = generateClassId(); - currentClassId = newClassId; - var uniqueClassName = m[1] + "$" + newClassId; - var inlineClass = new AstInlineClass(uniqueClassName, - transformClassBody(atoms[m[2]], uniqueClassName, "", "implements " + m[1])); - appendClass(inlineClass, newClassId, oldClassId); - currentClassId = oldClassId; - return inlineClass; - } - - function AstFunction(name, params, body) { - this.name = name; - this.params = params; - this.body = body; - } - AstFunction.prototype.toString = function() { - var oldContext = replaceContext; - // saving "this." and parameters - var names = appendToLookupTable({"this":null}, this.params.getNames()); - replaceContext = function (subject) { - return names.hasOwnProperty(subject.name) ? subject.name : oldContext(subject); - }; - var result = "function"; - if(this.name) { - result += " " + this.name; - } - var body = this.params.prependMethodArgs(this.body.toString()); - result += this.params + " " + body; - replaceContext = oldContext; - return result; - }; - - function transformFunction(class_) { - var m = new RegExp(/\b([A-Za-z_$][\w$]*)\s*"B(\d+)"\s*"A(\d+)"/).exec(class_); - return new AstFunction( m[1] !== "function" ? m[1] : null, - transformParams(atoms[m[2]]), transformStatementsBlock(atoms[m[3]])); - } - - function AstInlineObject(members) { - this.members = members; - } - AstInlineObject.prototype.toString = function() { - var oldContext = replaceContext; - replaceContext = function (subject) { - return subject.name === "this" ? "this" : oldContext(subject); // saving "this." - }; - var result = ""; - for(var i=0,l=this.members.length;i<l;++i) { - if(this.members[i].label) { - result += this.members[i].label + ": "; - } - result += this.members[i].value.toString() + ", "; - } - replaceContext = oldContext; - return result.substring(0, result.length - 2); - }; - - function transformInlineObject(obj) { - var members = obj.split(','); - for(var i=0; i < members.length; ++i) { - var label = members[i].indexOf(':'); - if(label < 0) { - members[i] = { value: transformExpression(members[i]) }; - } else { - members[i] = { label: trim(members[i].substring(0, label)), - value: transformExpression( trim(members[i].substring(label + 1)) ) }; - } - } - return new AstInlineObject(members); - } - - function expandExpression(expr) { - if(expr.charAt(0) === '(' || expr.charAt(0) === '[') { - return expr.charAt(0) + expandExpression(expr.substring(1, expr.length - 1)) + expr.charAt(expr.length - 1); - } - if(expr.charAt(0) === '{') { - if(/^\{\s*(?:[A-Za-z_$][\w$]*|'\d+')\s*:/.test(expr)) { - return "{" + addAtom(expr.substring(1, expr.length - 1), 'I') + "}"; - } - return "[" + expandExpression(expr.substring(1, expr.length - 1)) + "]"; - } - var trimmed = trimSpaces(expr); - var result = preExpressionTransform(trimmed.middle); - result = result.replace(/"[ABC](\d+)"/g, function(all, index) { - return expandExpression(atoms[index]); - }); - return trimmed.untrim(result); - } - - function replaceContextInVars(expr) { - return expr.replace(/(\.\s*)?((?:\b[A-Za-z_]|\$)[\w$]*)(\s*\.\s*([A-Za-z_$][\w$]*)(\s*\()?)?/g, - function(all, memberAccessSign, identifier, suffix, subMember, callSign) { - if(memberAccessSign) { - return all; - } - var subject = { name: identifier, member: subMember, callSign: !!callSign }; - return replaceContext(subject) + (suffix === undef ? "" : suffix); - }); - } - - function AstExpression(expr, transforms) { - this.expr = expr; - this.transforms = transforms; - } - AstExpression.prototype.toString = function() { - var transforms = this.transforms; - var expr = replaceContextInVars(this.expr); - return expr.replace(/"!(\d+)"/g, function(all, index) { - return transforms[index].toString(); - }); - }; - - transformExpression = function(expr) { - var transforms = []; - var s = expandExpression(expr); - s = s.replace(/"H(\d+)"/g, function(all, index) { - transforms.push(transformFunction(atoms[index])); - return '"!' + (transforms.length - 1) + '"'; - }); - s = s.replace(/"F(\d+)"/g, function(all, index) { - transforms.push(transformInlineClass(atoms[index])); - return '"!' + (transforms.length - 1) + '"'; - }); - s = s.replace(/"I(\d+)"/g, function(all, index) { - transforms.push(transformInlineObject(atoms[index])); - return '"!' + (transforms.length - 1) + '"'; - }); - - return new AstExpression(s, transforms); - }; - - function AstVarDefinition(name, value, isDefault) { - this.name = name; - this.value = value; - this.isDefault = isDefault; - } - AstVarDefinition.prototype.toString = function() { - return this.name + ' = ' + this.value; - }; - - function transformVarDefinition(def, defaultTypeValue) { - var eqIndex = def.indexOf("="); - var name, value, isDefault; - if(eqIndex < 0) { - name = def; - value = defaultTypeValue; - isDefault = true; - } else { - name = def.substring(0, eqIndex); - value = transformExpression(def.substring(eqIndex + 1)); - isDefault = false; - } - return new AstVarDefinition( trim(name.replace(/(\s*"C\d+")+/g, "")), - value, isDefault); - } - - function getDefaultValueForType(type) { - if(type === "int" || type === "float") { - return "0"; - } - if(type === "boolean") { - return "false"; - } - if(type === "color") { - return "0x00000000"; - } - return "null"; - } - - function AstVar(definitions, varType) { - this.definitions = definitions; - this.varType = varType; - } - AstVar.prototype.getNames = function() { - var names = []; - for(var i=0,l=this.definitions.length;i<l;++i) { - names.push(this.definitions[i].name); - } - return names; - }; - AstVar.prototype.toString = function() { - return "var " + this.definitions.join(","); - }; - function AstStatement(expression) { - this.expression = expression; - } - AstStatement.prototype.toString = function() { - return this.expression.toString(); - }; - - function transformStatement(statement) { - if(fieldTest.test(statement)) { - var attrAndType = attrAndTypeRegex.exec(statement); - var definitions = statement.substring(attrAndType[0].length).split(","); - var defaultTypeValue = getDefaultValueForType(attrAndType[2]); - for(var i=0; i < definitions.length; ++i) { - definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue); - } - return new AstVar(definitions, attrAndType[2]); - } - return new AstStatement(transformExpression(statement)); - } - - function AstForExpression(initStatement, condition, step) { - this.initStatement = initStatement; - this.condition = condition; - this.step = step; - } - AstForExpression.prototype.toString = function() { - return "(" + this.initStatement + "; " + this.condition + "; " + this.step + ")"; - }; - - function AstForInExpression(initStatement, container) { - this.initStatement = initStatement; - this.container = container; - } - AstForInExpression.prototype.toString = function() { - var init = this.initStatement.toString(); - if(init.indexOf("=") >= 0) { // can be without var declaration - init = init.substring(0, init.indexOf("=")); - } - return "(" + init + " in " + this.container + ")"; - }; - - function AstForEachExpression(initStatement, container) { - this.initStatement = initStatement; - this.container = container; - } - AstForEachExpression.iteratorId = 0; - AstForEachExpression.prototype.toString = function() { - var init = this.initStatement.toString(); - var iterator = "$it" + (AstForEachExpression.iteratorId++); - var variableName = init.replace(/^\s*var\s*/, "").split("=")[0]; - var initIteratorAndVariable = "var " + iterator + " = new $p.ObjectIterator(" + this.container + "), " + - variableName + " = void(0)"; - var nextIterationCondition = iterator + ".hasNext() && ((" + - variableName + " = " + iterator + ".next()) || true)"; - return "(" + initIteratorAndVariable + "; " + nextIterationCondition + ";)"; - }; - - function transformForExpression(expr) { - var content; - if (/\bin\b/.test(expr)) { - content = expr.substring(1, expr.length - 1).split(/\bin\b/g); - return new AstForInExpression( transformStatement(trim(content[0])), - transformExpression(content[1])); - } - if (expr.indexOf(":") >= 0 && expr.indexOf(";") < 0) { - content = expr.substring(1, expr.length - 1).split(":"); - return new AstForEachExpression( transformStatement(trim(content[0])), - transformExpression(content[1])); - } - content = expr.substring(1, expr.length - 1).split(";"); - return new AstForExpression( transformStatement(trim(content[0])), - transformExpression(content[1]), transformExpression(content[2])); - } - - function sortByWeight(array) { - array.sort(function (a,b) { - return b.weight - a.weight; - }); - } - - function AstInnerInterface(name, body, isStatic) { - this.name = name; - this.body = body; - this.isStatic = isStatic; - body.owner = this; - } - AstInnerInterface.prototype.toString = function() { - return "" + this.body; - }; - function AstInnerClass(name, body, isStatic) { - this.name = name; - this.body = body; - this.isStatic = isStatic; - body.owner = this; - } - AstInnerClass.prototype.toString = function() { - return "" + this.body; - }; - - function transformInnerClass(class_) { - var m = classesRegex.exec(class_); // 1 - attr, 2 - class|int, 3 - name, 4 - extends, 5 - implements, 6 - body - classesRegex.lastIndex = 0; - var isStatic = m[1].indexOf("static") >= 0; - var body = atoms[getAtomIndex(m[6])], innerClass; - var oldClassId = currentClassId, newClassId = generateClassId(); - currentClassId = newClassId; - if(m[2] === "interface") { - innerClass = new AstInnerInterface(m[3], transformInterfaceBody(body, m[3], m[4]), isStatic); - } else { - innerClass = new AstInnerClass(m[3], transformClassBody(body, m[3], m[4], m[5]), isStatic); - } - appendClass(innerClass, newClassId, oldClassId); - currentClassId = oldClassId; - return innerClass; - } - - function AstClassMethod(name, params, body, isStatic) { - this.name = name; - this.params = params; - this.body = body; - this.isStatic = isStatic; - } - AstClassMethod.prototype.toString = function(){ - var paramNames = appendToLookupTable({}, this.params.getNames()); - var oldContext = replaceContext; - replaceContext = function (subject) { - return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject); - }; - var body = this.params.prependMethodArgs(this.body.toString()); - var result = "function " + this.methodId + this.params + " " + body +"\n"; - replaceContext = oldContext; - return result; - }; - - function transformClassMethod(method) { - var m = methodsRegex.exec(method); - methodsRegex.lastIndex = 0; - var isStatic = m[1].indexOf("static") >= 0; - var body = m[6] !== ';' ? atoms[getAtomIndex(m[6])] : "{}"; - return new AstClassMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), - transformStatementsBlock(body), isStatic ); - } - - function AstClassField(definitions, fieldType, isStatic) { - this.definitions = definitions; - this.fieldType = fieldType; - this.isStatic = isStatic; - } - AstClassField.prototype.getNames = function() { - var names = []; - for(var i=0,l=this.definitions.length;i<l;++i) { - names.push(this.definitions[i].name); - } - return names; - }; - AstClassField.prototype.toString = function() { - var thisPrefix = replaceContext({ name: "[this]" }); - if(this.isStatic) { - var className = this.owner.name; - var staticDeclarations = []; - for(var i=0,l=this.definitions.length;i<l;++i) { - var definition = this.definitions[i]; - var name = definition.name, staticName = className + "." + name; - var declaration = "if(" + staticName + " === void(0)) {\n" + - " " + staticName + " = " + definition.value + "; }\n" + - "$p.defineProperty(" + thisPrefix + ", " + - "'" + name + "', { get: function(){return " + staticName + ";}, " + - "set: function(val){" + staticName + " = val;} });\n"; - staticDeclarations.push(declaration); - } - return staticDeclarations.join(""); - } - return thisPrefix + "." + this.definitions.join("; " + thisPrefix + "."); - }; - - function transformClassField(statement) { - var attrAndType = attrAndTypeRegex.exec(statement); - var isStatic = attrAndType[1].indexOf("static") >= 0; - var definitions = statement.substring(attrAndType[0].length).split(/,\s*/g); - var defaultTypeValue = getDefaultValueForType(attrAndType[2]); - for(var i=0; i < definitions.length; ++i) { - definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue); - } - return new AstClassField(definitions, attrAndType[2], isStatic); - } - - function AstConstructor(params, body) { - this.params = params; - this.body = body; - } - AstConstructor.prototype.toString = function() { - var paramNames = appendToLookupTable({}, this.params.getNames()); - var oldContext = replaceContext; - replaceContext = function (subject) { - return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject); - }; - var prefix = "function $constr_" + this.params.params.length + this.params.toString(); - var body = this.params.prependMethodArgs(this.body.toString()); - if(!/\$(superCstr|constr)\b/.test(body)) { - body = "{\n$superCstr();\n" + body.substring(1); - } - replaceContext = oldContext; - return prefix + body + "\n"; - }; - - function transformConstructor(cstr) { - var m = new RegExp(/"B(\d+)"\s*"A(\d+)"/).exec(cstr); - var params = transformParams(atoms[m[1]]); - - return new AstConstructor(params, transformStatementsBlock(atoms[m[2]])); - } - - function AstInterfaceBody(name, interfacesNames, methodsNames, fields, innerClasses, misc) { - var i,l; - this.name = name; - this.interfacesNames = interfacesNames; - this.methodsNames = methodsNames; - this.fields = fields; - this.innerClasses = innerClasses; - this.misc = misc; - for(i=0,l=fields.length; i<l; ++i) { - fields[i].owner = this; - } - } - AstInterfaceBody.prototype.getMembers = function(classFields, classMethods, classInners) { - if(this.owner.base) { - this.owner.base.body.getMembers(classFields, classMethods, classInners); - } - var i, j, l, m; - for(i=0,l=this.fields.length;i<l;++i) { - var fieldNames = this.fields[i].getNames(); - for(j=0,m=fieldNames.length;j<m;++j) { - classFields[fieldNames[j]] = this.fields[i]; - } - } - for(i=0,l=this.methodsNames.length;i<l;++i) { - var methodName = this.methodsNames[i]; - classMethods[methodName] = true; - } - for(i=0,l=this.innerClasses.length;i<l;++i) { - var innerClass = this.innerClasses[i]; - classInners[innerClass.name] = innerClass; - } - }; - AstInterfaceBody.prototype.toString = function() { - function getScopeLevel(p) { - var i = 0; - while(p) { - ++i; - p=p.scope; - } - return i; - } - - var scopeLevel = getScopeLevel(this.owner); - - var className = this.name; - var staticDefinitions = ""; - var metadata = ""; - - var thisClassFields = {}, thisClassMethods = {}, thisClassInners = {}; - this.getMembers(thisClassFields, thisClassMethods, thisClassInners); - - var i, l, j, m; - - if (this.owner.interfaces) { - // interface name can be present, but interface is not - var resolvedInterfaces = [], resolvedInterface; - for (i = 0, l = this.interfacesNames.length; i < l; ++i) { - if (!this.owner.interfaces[i]) { - continue; - } - resolvedInterface = replaceContext({name: this.interfacesNames[i]}); - resolvedInterfaces.push(resolvedInterface); - staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n"; - } - metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n"; - } - metadata += className + ".$isInterface = true;\n"; - metadata += className + ".$methods = [\'" + this.methodsNames.join("\', \'") + "\'];\n"; - - sortByWeight(this.innerClasses); - for (i = 0, l = this.innerClasses.length; i < l; ++i) { - var innerClass = this.innerClasses[i]; - if (innerClass.isStatic) { - staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n"; - } - } - - for (i = 0, l = this.fields.length; i < l; ++i) { - var field = this.fields[i]; - if (field.isStatic) { - staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n"; - } - } - - return "(function() {\n" + - "function " + className + "() { throw \'Unable to create the interface\'; }\n" + - staticDefinitions + - metadata + - "return " + className + ";\n" + - "})()"; - }; - - transformInterfaceBody = function(body, name, baseInterfaces) { - var declarations = body.substring(1, body.length - 1); - declarations = extractClassesAndMethods(declarations); - declarations = extractConstructors(declarations, name); - var methodsNames = [], classes = []; - declarations = declarations.replace(/"([DE])(\d+)"/g, function(all, type, index) { - if(type === 'D') { methodsNames.push(index); } - else if(type === 'E') { classes.push(index); } - return ""; - }); - var fields = declarations.split(/;(?:\s*;)*/g); - var baseInterfaceNames; - var i, l; - - if(baseInterfaces !== undef) { - baseInterfaceNames = baseInterfaces.replace(/^\s*extends\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); - } - - for(i = 0, l = methodsNames.length; i < l; ++i) { - var method = transformClassMethod(atoms[methodsNames[i]]); - methodsNames[i] = method.name; - } - for(i = 0, l = fields.length - 1; i < l; ++i) { - var field = trimSpaces(fields[i]); - fields[i] = transformClassField(field.middle); - } - var tail = fields.pop(); - for(i = 0, l = classes.length; i < l; ++i) { - classes[i] = transformInnerClass(atoms[classes[i]]); - } - - return new AstInterfaceBody(name, baseInterfaceNames, methodsNames, fields, classes, { tail: tail }); - }; - - function AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, innerClasses, misc) { - var i,l; - this.name = name; - this.baseClassName = baseClassName; - this.interfacesNames = interfacesNames; - this.functions = functions; - this.methods = methods; - this.fields = fields; - this.cstrs = cstrs; - this.innerClasses = innerClasses; - this.misc = misc; - for(i=0,l=fields.length; i<l; ++i) { - fields[i].owner = this; - } - } - AstClassBody.prototype.getMembers = function(classFields, classMethods, classInners) { - if(this.owner.base) { - this.owner.base.body.getMembers(classFields, classMethods, classInners); - } - var i, j, l, m; - for(i=0,l=this.fields.length;i<l;++i) { - var fieldNames = this.fields[i].getNames(); - for(j=0,m=fieldNames.length;j<m;++j) { - classFields[fieldNames[j]] = this.fields[i]; - } - } - for(i=0,l=this.methods.length;i<l;++i) { - var method = this.methods[i]; - classMethods[method.name] = method; - } - for(i=0,l=this.innerClasses.length;i<l;++i) { - var innerClass = this.innerClasses[i]; - classInners[innerClass.name] = innerClass; - } - }; - AstClassBody.prototype.toString = function() { - function getScopeLevel(p) { - var i = 0; - while(p) { - ++i; - p=p.scope; - } - return i; - } - - var scopeLevel = getScopeLevel(this.owner); - - var selfId = "$this_" + scopeLevel; - var className = this.name; - var result = "var " + selfId + " = this;\n"; - var staticDefinitions = ""; - var metadata = ""; - - var thisClassFields = {}, thisClassMethods = {}, thisClassInners = {}; - this.getMembers(thisClassFields, thisClassMethods, thisClassInners); - - var oldContext = replaceContext; - replaceContext = function (subject) { - var name = subject.name; - if(name === "this") { - // returns "$this_N.$self" pointer instead of "this" in cases: - // "this()", "this.XXX()", "this", but not for "this.XXX" - return subject.callSign || !subject.member ? selfId + ".$self" : selfId; - } - if(thisClassFields.hasOwnProperty(name)) { - return thisClassFields[name].isStatic ? className + "." + name : selfId + "." + name; - } - if(thisClassInners.hasOwnProperty(name)) { - return selfId + "." + name; - } - if(thisClassMethods.hasOwnProperty(name)) { - return thisClassMethods[name].isStatic ? className + "." + name : selfId + ".$self." + name; - } - return oldContext(subject); - }; - - var resolvedBaseClassName; - if (this.baseClassName) { - resolvedBaseClassName = oldContext({name: this.baseClassName}); - result += "var $super = { $upcast: " + selfId + " };\n"; - result += "function $superCstr(){" + resolvedBaseClassName + - ".apply($super,arguments);if(!('$self' in $super)) $p.extendClassChain($super)}\n"; - metadata += className + ".$base = " + resolvedBaseClassName + ";\n"; - } else { - result += "function $superCstr(){$p.extendClassChain("+ selfId +")}\n"; - } - - if (this.owner.base) { - // base class name can be present, but class is not - staticDefinitions += "$p.extendStaticMembers(" + className + ", " + resolvedBaseClassName + ");\n"; - } - - var i, l, j, m; - - if (this.owner.interfaces) { - // interface name can be present, but interface is not - var resolvedInterfaces = [], resolvedInterface; - for (i = 0, l = this.interfacesNames.length; i < l; ++i) { - if (!this.owner.interfaces[i]) { - continue; - } - resolvedInterface = oldContext({name: this.interfacesNames[i]}); - resolvedInterfaces.push(resolvedInterface); - staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n"; - } - metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n"; - } - - if (this.functions.length > 0) { - result += this.functions.join('\n') + '\n'; - } - - sortByWeight(this.innerClasses); - for (i = 0, l = this.innerClasses.length; i < l; ++i) { - var innerClass = this.innerClasses[i]; - if (innerClass.isStatic) { - staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n"; - result += selfId + "." + innerClass.name + " = " + className + "." + innerClass.name + ";\n"; - } else { - result += selfId + "." + innerClass.name + " = " + innerClass + ";\n"; - } - } - - for (i = 0, l = this.fields.length; i < l; ++i) { - var field = this.fields[i]; - if (field.isStatic) { - staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n"; - for (j = 0, m = field.definitions.length; j < m; ++j) { - var fieldName = field.definitions[j].name, staticName = className + "." + fieldName; - result += "$p.defineProperty(" + selfId + ", '" + fieldName + "', {" + - "get: function(){return " + staticName + "}, " + - "set: function(val){" + staticName + " = val}});\n"; - } - } else { - result += selfId + "." + field.definitions.join(";\n" + selfId + ".") + ";\n"; - } - } - var methodOverloads = {}; - for (i = 0, l = this.methods.length; i < l; ++i) { - var method = this.methods[i]; - var overload = methodOverloads[method.name]; - var methodId = method.name + "$" + method.params.params.length; - var hasMethodArgs = !!method.params.methodArgsParam; - if (overload) { - ++overload; - methodId += "_" + overload; - } else { - overload = 1; - } - method.methodId = methodId; - methodOverloads[method.name] = overload; - if (method.isStatic) { - staticDefinitions += method; - staticDefinitions += "$p.addMethod(" + className + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n"; - result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n"; - } else { - result += method; - result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n"; - } - } - result += trim(this.misc.tail); - - if (this.cstrs.length > 0) { - result += this.cstrs.join('\n') + '\n'; - } - - result += "function $constr() {\n"; - var cstrsIfs = []; - for (i = 0, l = this.cstrs.length; i < l; ++i) { - var paramsLength = this.cstrs[i].params.params.length; - var methodArgsPresent = !!this.cstrs[i].params.methodArgsParam; - cstrsIfs.push("if(arguments.length " + (methodArgsPresent ? ">=" : "===") + - " " + paramsLength + ") { " + - "$constr_" + paramsLength + ".apply(" + selfId + ", arguments); }"); - } - if(cstrsIfs.length > 0) { - result += cstrsIfs.join(" else ") + " else "; - } - // ??? add check if length is 0, otherwise fail - result += "$superCstr();\n}\n"; - result += "$constr.apply(null, arguments);\n"; - - replaceContext = oldContext; - return "(function() {\n" + - "function " + className + "() {\n" + result + "}\n" + - staticDefinitions + - metadata + - "return " + className + ";\n" + - "})()"; - }; - - transformClassBody = function(body, name, baseName, interfaces) { - var declarations = body.substring(1, body.length - 1); - declarations = extractClassesAndMethods(declarations); - declarations = extractConstructors(declarations, name); - var methods = [], classes = [], cstrs = [], functions = []; - declarations = declarations.replace(/"([DEGH])(\d+)"/g, function(all, type, index) { - if(type === 'D') { methods.push(index); } - else if(type === 'E') { classes.push(index); } - else if(type === 'H') { functions.push(index); } - else { cstrs.push(index); } - return ""; - }); - var fields = declarations.replace(/^(?:\s*;)+/, "").split(/;(?:\s*;)*/g); - var baseClassName, interfacesNames; - var i; - - if(baseName !== undef) { - baseClassName = baseName.replace(/^\s*extends\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*$/g, "$1"); - } - - if(interfaces !== undef) { - interfacesNames = interfaces.replace(/^\s*implements\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); - } - - for(i = 0; i < functions.length; ++i) { - functions[i] = transformFunction(atoms[functions[i]]); - } - for(i = 0; i < methods.length; ++i) { - methods[i] = transformClassMethod(atoms[methods[i]]); - } - for(i = 0; i < fields.length - 1; ++i) { - var field = trimSpaces(fields[i]); - fields[i] = transformClassField(field.middle); - } - var tail = fields.pop(); - for(i = 0; i < cstrs.length; ++i) { - cstrs[i] = transformConstructor(atoms[cstrs[i]]); - } - for(i = 0; i < classes.length; ++i) { - classes[i] = transformInnerClass(atoms[classes[i]]); - } - - return new AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, - classes, { tail: tail }); - }; - - function AstInterface(name, body) { - this.name = name; - this.body = body; - body.owner = this; - } - AstInterface.prototype.toString = function() { - return "var " + this.name + " = " + this.body + ";\n" + - "$p." + this.name + " = " + this.name + ";\n"; - }; - function AstClass(name, body) { - this.name = name; - this.body = body; - body.owner = this; - } - AstClass.prototype.toString = function() { - return "var " + this.name + " = " + this.body + ";\n" + - "$p." + this.name + " = " + this.name + ";\n"; - }; - - function transformGlobalClass(class_) { - var m = classesRegex.exec(class_); // 1 - attr, 2 - class|int, 3 - name, 4 - extends, 5 - implements, 6 - body - classesRegex.lastIndex = 0; - var body = atoms[getAtomIndex(m[6])]; - var oldClassId = currentClassId, newClassId = generateClassId(); - currentClassId = newClassId; - var globalClass; - if(m[2] === "interface") { - globalClass = new AstInterface(m[3], transformInterfaceBody(body, m[3], m[4]) ); - } else { - globalClass = new AstClass(m[3], transformClassBody(body, m[3], m[4], m[5]) ); - } - appendClass(globalClass, newClassId, oldClassId); - currentClassId = oldClassId; - return globalClass; - } - - function AstMethod(name, params, body) { - this.name = name; - this.params = params; - this.body = body; - } - AstMethod.prototype.toString = function(){ - var paramNames = appendToLookupTable({}, this.params.getNames()); - var oldContext = replaceContext; - replaceContext = function (subject) { - return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject); - }; - var body = this.params.prependMethodArgs(this.body.toString()); - var result = "function " + this.name + this.params + " " + body + "\n" + - "$p." + this.name + " = " + this.name + ";\n" + - this.name + " = " + this.name + ".bind($p);"; -// "$p." + this.name + " = " + this.name + ";"; - replaceContext = oldContext; - return result; - }; - - function transformGlobalMethod(method) { - var m = methodsRegex.exec(method); - var result = - methodsRegex.lastIndex = 0; - return new AstMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), - transformStatementsBlock(atoms[getAtomIndex(m[6])])); - } - - function preStatementsTransform(statements) { - var s = statements; - // turns multiple catch blocks into one, because we have no way to properly get into them anyway. - s = s.replace(/\b(catch\s*"B\d+"\s*"A\d+")(\s*catch\s*"B\d+"\s*"A\d+")+/g, "$1"); - return s; - } - - function AstForStatement(argument, misc) { - this.argument = argument; - this.misc = misc; - } - AstForStatement.prototype.toString = function() { - return this.misc.prefix + this.argument.toString(); - }; - function AstCatchStatement(argument, misc) { - this.argument = argument; - this.misc = misc; - } - AstCatchStatement.prototype.toString = function() { - return this.misc.prefix + this.argument.toString(); - }; - function AstPrefixStatement(name, argument, misc) { - this.name = name; - this.argument = argument; - this.misc = misc; - } - AstPrefixStatement.prototype.toString = function() { - var result = this.misc.prefix; - if(this.argument !== undef) { - result += this.argument.toString(); - } - return result; - }; - function AstSwitchCase(expr) { - this.expr = expr; - } - AstSwitchCase.prototype.toString = function() { - return "case " + this.expr + ":"; - }; - function AstLabel(label) { - this.label = label; - } - AstLabel.prototype.toString = function() { - return this.label; - }; - - transformStatements = function(statements, transformMethod, transformClass) { - var nextStatement = new RegExp(/\b(catch|for|if|switch|while|with)\s*"B(\d+)"|\b(do|else|finally|return|throw|try|break|continue)\b|("[ADEH](\d+)")|\b(case)\s+([^:]+):|\b([A-Za-z_$][\w$]*\s*:)|(;)/g); - var res = []; - statements = preStatementsTransform(statements); - var lastIndex = 0, m, space; - // m contains the matches from the nextStatement regexp, null if there are no matches. - // nextStatement.exec starts searching at nextStatement.lastIndex. - while((m = nextStatement.exec(statements)) !== null) { - if(m[1] !== undef) { // catch, for ... - var i = statements.lastIndexOf('"B', nextStatement.lastIndex); - var statementsPrefix = statements.substring(lastIndex, i); - if(m[1] === "for") { - res.push(new AstForStatement(transformForExpression(atoms[m[2]]), - { prefix: statementsPrefix }) ); - } else if(m[1] === "catch") { - res.push(new AstCatchStatement(transformParams(atoms[m[2]]), - { prefix: statementsPrefix }) ); - } else { - res.push(new AstPrefixStatement(m[1], transformExpression(atoms[m[2]]), - { prefix: statementsPrefix }) ); - } - } else if(m[3] !== undef) { // do, else, ... - res.push(new AstPrefixStatement(m[3], undef, - { prefix: statements.substring(lastIndex, nextStatement.lastIndex) }) ); - } else if(m[4] !== undef) { // block, class and methods - space = statements.substring(lastIndex, nextStatement.lastIndex - m[4].length); - if(trim(space).length !== 0) { continue; } // avoiding new type[] {} construct - res.push(space); - var kind = m[4].charAt(1), atomIndex = m[5]; - if(kind === 'D') { - res.push(transformMethod(atoms[atomIndex])); - } else if(kind === 'E') { - res.push(transformClass(atoms[atomIndex])); - } else if(kind === 'H') { - res.push(transformFunction(atoms[atomIndex])); - } else { - res.push(transformStatementsBlock(atoms[atomIndex])); - } - } else if(m[6] !== undef) { // switch case - res.push(new AstSwitchCase(transformExpression(trim(m[7])))); - } else if(m[8] !== undef) { // label - space = statements.substring(lastIndex, nextStatement.lastIndex - m[8].length); - if(trim(space).length !== 0) { continue; } // avoiding ?: construct - res.push(new AstLabel(statements.substring(lastIndex, nextStatement.lastIndex)) ); - } else { // semicolon - var statement = trimSpaces(statements.substring(lastIndex, nextStatement.lastIndex - 1)); - res.push(statement.left); - res.push(transformStatement(statement.middle)); - res.push(statement.right + ";"); - } - lastIndex = nextStatement.lastIndex; - } - var statementsTail = trimSpaces(statements.substring(lastIndex)); - res.push(statementsTail.left); - if(statementsTail.middle !== "") { - res.push(transformStatement(statementsTail.middle)); - res.push(";" + statementsTail.right); - } - return res; - }; - - function getLocalNames(statements) { - var localNames = []; - for(var i=0,l=statements.length;i<l;++i) { - var statement = statements[i]; - if(statement instanceof AstVar) { - localNames = localNames.concat(statement.getNames()); - } else if(statement instanceof AstForStatement && - statement.argument.initStatement instanceof AstVar) { - localNames = localNames.concat(statement.argument.initStatement.getNames()); - } else if(statement instanceof AstInnerInterface || statement instanceof AstInnerClass || - statement instanceof AstInterface || statement instanceof AstClass || - statement instanceof AstMethod || statement instanceof AstFunction) { - localNames.push(statement.name); - } - } - return appendToLookupTable({}, localNames); - } - - function AstStatementsBlock(statements) { - this.statements = statements; - } - AstStatementsBlock.prototype.toString = function() { - var localNames = getLocalNames(this.statements); - var oldContext = replaceContext; - - // replacing context only when necessary - if(!isLookupTableEmpty(localNames)) { - replaceContext = function (subject) { - return localNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject); - }; - } - - var result = "{\n" + this.statements.join('') + "\n}"; - replaceContext = oldContext; - return result; - }; - - transformStatementsBlock = function(block) { - var content = trimSpaces(block.substring(1, block.length - 1)); - return new AstStatementsBlock(transformStatements(content.middle)); - }; - - function AstRoot(statements) { - this.statements = statements; - } - AstRoot.prototype.toString = function() { - var classes = [], otherStatements = [], statement; - for (var i = 0, len = this.statements.length; i < len; ++i) { - statement = this.statements[i]; - if (statement instanceof AstClass || statement instanceof AstInterface) { - classes.push(statement); - } else { - otherStatements.push(statement); - } - } - sortByWeight(classes); - - var localNames = getLocalNames(this.statements); - replaceContext = function (subject) { - var name = subject.name; - if(localNames.hasOwnProperty(name)) { - return name; - } - if(globalMembers.hasOwnProperty(name) || - PConstants.hasOwnProperty(name) || - defaultScope.hasOwnProperty(name)) { - return "$p." + name; - } - return name; - }; - var result = "// this code was autogenerated from PJS\n" + - "(function($p) {\n" + - classes.join('') + "\n" + - otherStatements.join('') + "\n})"; - replaceContext = null; - return result; - }; - - transformMain = function() { - var statements = extractClassesAndMethods(atoms[0]); - statements = statements.replace(/\bimport\s+[^;]+;/g, ""); - return new AstRoot( transformStatements(statements, - transformGlobalMethod, transformGlobalClass) ); - }; - - function generateMetadata(ast) { - var globalScope = {}; - var id, class_; - for(id in declaredClasses) { - if(declaredClasses.hasOwnProperty(id)) { - class_ = declaredClasses[id]; - var scopeId = class_.scopeId, name = class_.name; - if(scopeId) { - var scope = declaredClasses[scopeId]; - class_.scope = scope; - if(scope.inScope === undef) { - scope.inScope = {}; - } - scope.inScope[name] = class_; - } else { - globalScope[name] = class_; - } - } - } - - function findInScopes(class_, name) { - var parts = name.split('.'); - var currentScope = class_.scope, found; - while(currentScope) { - if(currentScope.hasOwnProperty(parts[0])) { - found = currentScope[parts[0]]; break; - } - currentScope = currentScope.scope; - } - if(found === undef) { - found = globalScope[parts[0]]; - } - for(var i=1,l=parts.length;i<l && found;++i) { - found = found.inScope[parts[i]]; - } - return found; - } - - for(id in declaredClasses) { - if(declaredClasses.hasOwnProperty(id)) { - class_ = declaredClasses[id]; - var baseClassName = class_.body.baseClassName; - if(baseClassName) { - var parent = findInScopes(class_, baseClassName); - if (parent) { - class_.base = parent; - if (!parent.derived) { - parent.derived = []; - } - parent.derived.push(class_); - } - } - var interfacesNames = class_.body.interfacesNames, - interfaces = [], i, l; - if (interfacesNames && interfacesNames.length > 0) { - for (i = 0, l = interfacesNames.length; i < l; ++i) { - var interface_ = findInScopes(class_, interfacesNames[i]); - interfaces.push(interface_); - if (!interface_) { - continue; - } - if (!interface_.derived) { - interface_.derived = []; - } - interface_.derived.push(class_); - } - if (interfaces.length > 0) { - class_.interfaces = interfaces; - } - } - } - } - } - - function setWeight(ast) { - var queue = [], tocheck = {}; - var id, scopeId, class_; - // queue most inner and non-inherited - for (id in declaredClasses) { - if (declaredClasses.hasOwnProperty(id)) { - class_ = declaredClasses[id]; - if (!class_.inScope && !class_.derived) { - queue.push(id); - class_.weight = 0; - } else { - var dependsOn = []; - if (class_.inScope) { - for (scopeId in class_.inScope) { - if (class_.inScope.hasOwnProperty(scopeId)) { - dependsOn.push(class_.inScope[scopeId]); - } - } - } - if (class_.derived) { - dependsOn = dependsOn.concat(class_.derived); - } - tocheck[id] = dependsOn; - } - } - } - function removeDependentAndCheck(targetId, from) { - var dependsOn = tocheck[targetId]; - if (!dependsOn) { - return false; // no need to process - } - var i = dependsOn.indexOf(from); - if (i < 0) { - return false; - } - dependsOn.splice(i, 1); - if (dependsOn.length > 0) { - return false; - } - delete tocheck[targetId]; - return true; - } - while (queue.length > 0) { - id = queue.shift(); - class_ = declaredClasses[id]; - if (class_.scopeId && removeDependentAndCheck(class_.scopeId, class_)) { - queue.push(class_.scopeId); - declaredClasses[class_.scopeId].weight = class_.weight + 1; - } - if (class_.base && removeDependentAndCheck(class_.base.classId, class_)) { - queue.push(class_.base.classId); - class_.base.weight = class_.weight + 1; - } - if (class_.interfaces) { - var i, l; - for (i = 0, l = class_.interfaces.length; i < l; ++i) { - if (!class_.interfaces[i] || - !removeDependentAndCheck(class_.interfaces[i].classId, class_)) { - continue; - } - queue.push(class_.interfaces[i].classId); - class_.interfaces[i].weight = class_.weight + 1; - } - } - } - } - - var transformed = transformMain(); - generateMetadata(transformed); - setWeight(transformed); - - var redendered = transformed.toString(); - - // remove empty extra lines with space - redendered = redendered.replace(/\s*\n(?:[\t ]*\n)+/g, "\n\n"); - - // convert character codes to characters - redendered = redendered.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { - return String.fromCharCode(parseInt(hexCode,16)); - }); - - return injectStrings(redendered, strings); - }// Parser ends - - function preprocessCode(aCode, sketch) { - // Parse out @pjs directive, if any. - var dm = new RegExp(/\/\*\s*@pjs\s+((?:[^\*]|\*+[^\*\/])*)\*\//g).exec(aCode); - if (dm && dm.length === 2) { - // masks contents of a JSON to be replaced later - // to protect the contents from further parsing - var jsonItems = [], - directives = dm.splice(1, 2)[0].replace(/\{([\s\S]*?)\}/g, (function() { - return function(all, item) { - jsonItems.push(item); - return "{" + (jsonItems.length-1) + "}"; - }; - }())).replace('\n', '').replace('\r', '').split(";"); - - // We'll L/RTrim, and also remove any surrounding double quotes (e.g., just take string contents) - var clean = function(s) { - return s.replace(/^\s*["']?/, '').replace(/["']?\s*$/, ''); - }; - - for (var i = 0, dl = directives.length; i < dl; i++) { - var pair = directives[i].split('='); - if (pair && pair.length === 2) { - var key = clean(pair[0]), - value = clean(pair[1]), - list = []; - // A few directives require work beyond storying key/value pairings - if (key === "preload") { - list = value.split(','); - // All pre-loaded images will get put in imageCache, keyed on filename - for (var j = 0, jl = list.length; j < jl; j++) { - var imageName = clean(list[j]); - sketch.imageCache.add(imageName); - } - // fonts can be declared as a string containing a url, - // or a JSON object, containing a font name, and a url - } else if (key === "font") { - list = value.split(","); - for (var x = 0, xl = list.length; x < xl; x++) { - var fontName = clean(list[x]), - index = /^\{(\d*?)\}$/.exec(fontName); - // if index is not null, send JSON, otherwise, send string - PFont.preloading.add(index ? JSON.parse("{" + jsonItems[index[1]] + "}") : fontName); - } - } else if (key === "pauseOnBlur") { - sketch.options.pauseOnBlur = value === "true"; - } else if (key === "globalKeyEvents") { - sketch.options.globalKeyEvents = value === "true"; - } else if (key.substring(0, 6) === "param-") { - sketch.params[key.substring(6)] = value; - } else { - sketch.options[key] = value; - } - } - } - } - return aCode; - } - - // Parse/compiles Processing (Java-like) syntax to JavaScript syntax - Processing.compile = function(pdeCode) { - var sketch = new Processing.Sketch(); - var code = preprocessCode(pdeCode, sketch); - var compiledPde = parseProcessing(code); - sketch.sourceCode = compiledPde; - return sketch; - }; - - var PjsConsole = require("../Helpers/PjsConsole"); - Processing.logger = new PjsConsole(document); - - // done - return Processing; -}; - -},{"../Helpers/PjsConsole":5}],27:[function(require,module,exports){ -/** - * Processing.js object - */ - module.exports = function(options, undef) { - var defaultScope = options.defaultScope, - extend = options.extend, - Browser = options.Browser, - ajax = Browser.ajax, - navigator = Browser.navigator, - window = Browser.window, - XMLHttpRequest = window.XMLHttpRequest, - document = Browser.document, - noop = options.noop, - - PConstants = defaultScope.PConstants; - PFont = defaultScope.PFont, - PShapeSVG = defaultScope.PShapeSVG, - PVector = defaultScope.PVector, - Char = Character = defaultScope.Char, - ObjectIterator = defaultScope.ObjectIterator, - XMLElement = defaultScope.XMLElement, - XML = defaultScope.XML; - - // fascinating "read only" jshint error if we don't start a new var block here. - var HTMLCanvasElement = window.HTMLCanvasElement, - HTMLImageElement = window.HTMLImageElement; - - // window.localStorage cannot be accessed if a user is blocking cookies. - // In that case, we make it a temporary source cache object. - var localStorage; - try { localStorage = window.localStorage; } catch (e) { localStorage = {}; } - - var isDOMPresent = ("document" in this) && !("fake" in this.document); - - // document.head polyfill for the benefit of Firefox 3.6 - if (!document.head) { - document.head = document.getElementsByTagName('head')[0]; - } - - var Float32Array = setupTypedArray("Float32Array", "WebGLFloatArray"), - Int32Array = setupTypedArray("Int32Array", "WebGLIntArray"), - Uint16Array = setupTypedArray("Uint16Array", "WebGLUnsignedShortArray"), - Uint8Array = setupTypedArray("Uint8Array", "WebGLUnsignedByteArray"); - - // Typed Arrays: fallback to WebGL arrays or Native JS arrays if unavailable - function setupTypedArray(name, fallback) { - // Check if TypedArray exists, and use if so. - if (name in window) { - return window[name]; - } - - // Check if WebGLArray exists - if (typeof window[fallback] === "function") { - return window[fallback]; - } - - // Use Native JS array - return function(obj) { - if (obj instanceof Array) { - return obj; - } - if (typeof obj === "number") { - var arr = []; - arr.length = obj; - return arr; - } - }; - } - - /* IE9+ quirks mode check - ticket #1606 */ - if (document.documentMode >= 9 && !document.doctype) { - throw("The doctype directive is missing. The recommended doctype in Internet Explorer is the HTML5 doctype: <!DOCTYPE html>"); - } - - // Manage multiple Processing instances - var processingInstances = []; - var processingInstanceIds = {}; - - /** - * instance tracking - adding new instances - */ - var addInstance = function(processing) { - if (processing.externals.canvas.id === undef || !processing.externals.canvas.id.length) { - processing.externals.canvas.id = "__processing" + processingInstances.length; - } - processingInstanceIds[processing.externals.canvas.id] = processingInstances.length; - processingInstances.push(processing); - }; - - /** - * instance tracking - removal - */ - var removeInstance = function(id) { - processingInstances.splice(processingInstanceIds[id], 1); - delete processingInstanceIds[id]; - }; - - - /** - * The Processing object - */ - var Processing = this.Processing = function(aCanvas, aCode, aFunctions) { - - if (!(this instanceof Processing)) { - throw("called Processing constructor as if it were a function: missing 'new'."); - } - - var curElement = {}, - pgraphicsMode = (aCanvas === undef && aCode === undef); - - if (pgraphicsMode) { - curElement = document.createElement("canvas"); - } else { - // We'll take a canvas element or a string for a canvas element's id - curElement = typeof aCanvas === "string" ? document.getElementById(aCanvas) : aCanvas; - } - - if (!('getContext' in curElement)) { - throw("called Processing constructor without passing canvas element reference or id."); - } - - function unimplemented(s) { - Processing.debug('Unimplemented - ' + s); - } - - //////////////////////////////////////////////////////////////////////////// - // JavaScript event binding and releasing - //////////////////////////////////////////////////////////////////////////// - - var eventHandlers = []; - - function attachEventHandler(elem, type, fn) { - if (elem.addEventListener) { - elem.addEventListener(type, fn, false); - } else { - elem.attachEvent("on" + type, fn); - } - eventHandlers.push({elem: elem, type: type, fn: fn}); - } - - function detachEventHandler(eventHandler) { - var elem = eventHandler.elem, - type = eventHandler.type, - fn = eventHandler.fn; - if (elem.removeEventListener) { - elem.removeEventListener(type, fn, false); - } else if (elem.detachEvent) { - elem.detachEvent("on" + type, fn); - } - } - - function removeFirstArgument(args) { - return Array.prototype.slice.call(args, 1); - } - - // When something new is added to "p." it must also be added to the "names" array. - // The names array contains the names of everything that is inside "p." - var p = this; - - p.Char = p.Character = Char; - - // add in the Processing API functions - extend.withCommonFunctions(p); - extend.withMath(p); - extend.withProxyFunctions(p, removeFirstArgument); - extend.withTouch(p, curElement, attachEventHandler, document, PConstants); - - // custom functions and properties are added here - if(aFunctions) { - Object.keys(aFunctions).forEach(function(name) { - p[name] = aFunctions[name]; - }); - } - - // PJS specific (non-p5) methods and properties to externalize - p.externals = { - canvas: curElement, - context: undef, - sketch: undef, - window: window - }; - - p.name = 'Processing.js Instance'; // Set Processing defaults / environment variables - p.use3DContext = false; // default '2d' canvas context - - /** - * Confirms if a Processing program is "focused", meaning that it is - * active and will accept input from mouse or keyboard. This variable - * is "true" if it is focused and "false" if not. This variable is - * often used when you want to warn people they need to click on the - * browser before it will work. - */ - p.focused = false; - p.breakShape = false; - - // Glyph path storage for textFonts - p.glyphTable = {}; - - // Global vars for tracking mouse position - p.pmouseX = 0; - p.pmouseY = 0; - p.mouseX = 0; - p.mouseY = 0; - p.mouseButton = 0; - p.mouseScroll = 0; - - // Undefined event handlers to be replaced by user when needed - p.mouseClicked = undef; - p.mouseDragged = undef; - p.mouseMoved = undef; - p.mousePressed = undef; - p.mouseReleased = undef; - p.mouseScrolled = undef; - p.mouseOver = undef; - p.mouseOut = undef; - p.touchStart = undef; - p.touchEnd = undef; - p.touchMove = undef; - p.touchCancel = undef; - p.key = undef; - p.keyCode = undef; - p.keyPressed = noop; // needed to remove function checks - p.keyReleased = noop; - p.keyTyped = noop; - p.draw = undef; - p.setup = undef; - - // Remapped vars - p.__mousePressed = false; - p.__keyPressed = false; - p.__frameRate = 60; - - // The current animation frame - p.frameCount = 0; - - // The height/width of the canvas - p.width = 100; - p.height = 100; - - // "Private" variables used to maintain state - var curContext, - curSketch, - drawing, // hold a Drawing2D or Drawing3D object - doFill = true, - fillStyle = [1.0, 1.0, 1.0, 1.0], - currentFillColor = 0xFFFFFFFF, - isFillDirty = true, - doStroke = true, - strokeStyle = [0.0, 0.0, 0.0, 1.0], - currentStrokeColor = 0xFF000000, - isStrokeDirty = true, - lineWidth = 1, - loopStarted = false, - renderSmooth = false, - doLoop = true, - looping = 0, - curRectMode = PConstants.CORNER, - curEllipseMode = PConstants.CENTER, - normalX = 0, - normalY = 0, - normalZ = 0, - normalMode = PConstants.NORMAL_MODE_AUTO, - curFrameRate = 60, - curMsPerFrame = 1000/curFrameRate, - curCursor = PConstants.ARROW, - oldCursor = curElement.style.cursor, - curShape = PConstants.POLYGON, - curShapeCount = 0, - curvePoints = [], - curTightness = 0, - curveDet = 20, - curveInited = false, - backgroundObj = -3355444, // rgb(204, 204, 204) is the default gray background colour - bezDetail = 20, - colorModeA = 255, - colorModeX = 255, - colorModeY = 255, - colorModeZ = 255, - pathOpen = false, - mouseDragging = false, - pmouseXLastFrame = 0, - pmouseYLastFrame = 0, - curColorMode = PConstants.RGB, - curTint = null, - curTint3d = null, - getLoaded = false, - start = Date.now(), - timeSinceLastFPS = start, - framesSinceLastFPS = 0, - textcanvas, - curveBasisMatrix, - curveToBezierMatrix, - curveDrawMatrix, - bezierDrawMatrix, - bezierBasisInverse, - bezierBasisMatrix, - curContextCache = { attributes: {}, locations: {} }, - // Shaders - programObject3D, - programObject2D, - programObjectUnlitShape, - boxBuffer, - boxNormBuffer, - boxOutlineBuffer, - rectBuffer, - rectNormBuffer, - sphereBuffer, - lineBuffer, - fillBuffer, - fillColorBuffer, - strokeColorBuffer, - pointBuffer, - shapeTexVBO, - canTex, // texture for createGraphics - textTex, // texture for 3d tex - curTexture = {width:0,height:0}, - curTextureMode = PConstants.IMAGE, - usingTexture = false, - textBuffer, - textureBuffer, - indexBuffer, - // Text alignment - horizontalTextAlignment = PConstants.LEFT, - verticalTextAlignment = PConstants.BASELINE, - textMode = PConstants.MODEL, - // Font state - curFontName = "Arial", - curTextSize = 12, - curTextAscent = 9, - curTextDescent = 2, - curTextLeading = 14, - curTextFont = PFont.get(curFontName, curTextSize), - // Pixels cache - originalContext, - proxyContext = null, - isContextReplaced = false, - setPixelsCached, - maxPixelsCached = 1000, - pressedKeysMap = [], - lastPressedKeyCode = null, - codedKeys = [ PConstants.SHIFT, PConstants.CONTROL, PConstants.ALT, PConstants.CAPSLK, PConstants.PGUP, PConstants.PGDN, - PConstants.END, PConstants.HOME, PConstants.LEFT, PConstants.UP, PConstants.RIGHT, PConstants.DOWN, PConstants.NUMLK, - PConstants.INSERT, PConstants.F1, PConstants.F2, PConstants.F3, PConstants.F4, PConstants.F5, PConstants.F6, PConstants.F7, - PConstants.F8, PConstants.F9, PConstants.F10, PConstants.F11, PConstants.F12, PConstants.META ]; - - // User can only have MAX_LIGHTS lights - var lightCount = 0; - - //sphere stuff - var sphereDetailV = 0, - sphereDetailU = 0, - sphereX = [], - sphereY = [], - sphereZ = [], - sinLUT = new Float32Array(PConstants.SINCOS_LENGTH), - cosLUT = new Float32Array(PConstants.SINCOS_LENGTH), - sphereVerts, - sphereNorms; - - // Camera defaults and settings - var cam, - cameraInv, - modelView, - modelViewInv, - userMatrixStack, - userReverseMatrixStack, - inverseCopy, - projection, - manipulatingCamera = false, - frustumMode = false, - cameraFOV = 60 * (Math.PI / 180), - cameraX = p.width / 2, - cameraY = p.height / 2, - cameraZ = cameraY / Math.tan(cameraFOV / 2), - cameraNear = cameraZ / 10, - cameraFar = cameraZ * 10, - cameraAspect = p.width / p.height; - - var vertArray = [], - curveVertArray = [], - curveVertCount = 0, - isCurve = false, - isBezier = false, - firstVert = true; - - //PShape stuff - var curShapeMode = PConstants.CORNER; - - // Stores states for pushStyle() and popStyle(). - var styleArray = []; - - // The vertices for the box cannot be specified using a triangle strip since each - // side of the cube must have its own set of normals. - // Vertices are specified in a counter-clockwise order. - // Triangles are in this order: back, front, right, bottom, left, top. - var boxVerts = new Float32Array([ - 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, - 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, - 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, - -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5]); - - var boxOutlineVerts = new Float32Array([ - 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, - -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, - 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, - -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, - 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, - -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5]); - - var boxNorms = new Float32Array([ - 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, - 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, - -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, - 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0]); - - // These verts are used for the fill and stroke using TRIANGLE_FAN and LINE_LOOP. - var rectVerts = new Float32Array([0,0,0, 0,1,0, 1,1,0, 1,0,0]); - - var rectNorms = new Float32Array([0,0,1, 0,0,1, 0,0,1, 0,0,1]); - - // Shader for points and lines in begin/endShape. - var vertexShaderSrcUnlitShape = - "varying vec4 vFrontColor;" + - - "attribute vec3 aVertex;" + - "attribute vec4 aColor;" + - - "uniform mat4 uView;" + - "uniform mat4 uProjection;" + - "uniform float uPointSize;" + - - "void main(void) {" + - " vFrontColor = aColor;" + - " gl_PointSize = uPointSize;" + - " gl_Position = uProjection * uView * vec4(aVertex, 1.0);" + - "}"; - - var fragmentShaderSrcUnlitShape = - "#ifdef GL_ES\n" + - "precision highp float;\n" + - "#endif\n" + - - "varying vec4 vFrontColor;" + - "uniform bool uSmooth;" + - - "void main(void){" + - " if(uSmooth == true){" + - " float dist = distance(gl_PointCoord, vec2(0.5));" + - " if(dist > 0.5){" + - " discard;" + - " }" + - " }" + - " gl_FragColor = vFrontColor;" + - "}"; - - // Shader for rect, text, box outlines, sphere outlines, point() and line(). - var vertexShaderSrc2D = - "varying vec4 vFrontColor;" + - - "attribute vec3 aVertex;" + - "attribute vec2 aTextureCoord;" + - "uniform vec4 uColor;" + - - "uniform mat4 uModel;" + - "uniform mat4 uView;" + - "uniform mat4 uProjection;" + - "uniform float uPointSize;" + - "varying vec2 vTextureCoord;"+ - - "void main(void) {" + - " gl_PointSize = uPointSize;" + - " vFrontColor = uColor;" + - " gl_Position = uProjection * uView * uModel * vec4(aVertex, 1.0);" + - " vTextureCoord = aTextureCoord;" + - "}"; - - var fragmentShaderSrc2D = - "#ifdef GL_ES\n" + - "precision highp float;\n" + - "#endif\n" + - - "varying vec4 vFrontColor;" + - "varying vec2 vTextureCoord;"+ - - "uniform sampler2D uSampler;"+ - "uniform int uIsDrawingText;"+ - "uniform bool uSmooth;" + - - "void main(void){" + - // WebGL does not support POINT_SMOOTH, so we do it ourselves - " if(uSmooth == true){" + - " float dist = distance(gl_PointCoord, vec2(0.5));" + - " if(dist > 0.5){" + - " discard;" + - " }" + - " }" + - - " if(uIsDrawingText == 1){" + - " float alpha = texture2D(uSampler, vTextureCoord).a;"+ - " gl_FragColor = vec4(vFrontColor.rgb * alpha, alpha);"+ - " }" + - " else{" + - " gl_FragColor = vFrontColor;" + - " }" + - "}"; - - var webglMaxTempsWorkaround = /Windows/.test(navigator.userAgent); - - // Vertex shader for boxes and spheres. - var vertexShaderSrc3D = - "varying vec4 vFrontColor;" + - - "attribute vec3 aVertex;" + - "attribute vec3 aNormal;" + - "attribute vec4 aColor;" + - "attribute vec2 aTexture;" + - "varying vec2 vTexture;" + - - "uniform vec4 uColor;" + - - "uniform bool uUsingMat;" + - "uniform vec3 uSpecular;" + - "uniform vec3 uMaterialEmissive;" + - "uniform vec3 uMaterialAmbient;" + - "uniform vec3 uMaterialSpecular;" + - "uniform float uShininess;" + - - "uniform mat4 uModel;" + - "uniform mat4 uView;" + - "uniform mat4 uProjection;" + - "uniform mat4 uNormalTransform;" + - - "uniform int uLightCount;" + - "uniform vec3 uFalloff;" + - - // Careful changing the order of these fields. Some cards - // have issues with memory alignment. - "struct Light {" + - " int type;" + - " vec3 color;" + - " vec3 position;" + - " vec3 direction;" + - " float angle;" + - " vec3 halfVector;" + - " float concentration;" + - "};" + - - // nVidia cards have issues with arrays of structures - // so instead we create 8 instances of Light. - "uniform Light uLights0;" + - "uniform Light uLights1;" + - "uniform Light uLights2;" + - "uniform Light uLights3;" + - "uniform Light uLights4;" + - "uniform Light uLights5;" + - "uniform Light uLights6;" + - "uniform Light uLights7;" + - - // GLSL does not support switch. - "Light getLight(int index){" + - " if(index == 0) return uLights0;" + - " if(index == 1) return uLights1;" + - " if(index == 2) return uLights2;" + - " if(index == 3) return uLights3;" + - " if(index == 4) return uLights4;" + - " if(index == 5) return uLights5;" + - " if(index == 6) return uLights6;" + - // Do not use a conditional for the last return statement - // because some video cards will fail and complain that - // "not all paths return". - " return uLights7;" + - "}" + - - "void AmbientLight( inout vec3 totalAmbient, in vec3 ecPos, in Light light ) {" + - // Get the vector from the light to the vertex and - // get the distance from the current vector to the light position. - " float d = length( light.position - ecPos );" + - " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + - " totalAmbient += light.color * attenuation;" + - "}" + - - /* - col - accumulated color - spec - accumulated specular highlight - vertNormal - Normal of the vertex - ecPos - eye coordinate position - light - light structure - */ - "void DirectionalLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + - " float powerFactor = 0.0;" + - " float nDotVP = max(0.0, dot( vertNormal, normalize(-light.position) ));" + - " float nDotVH = max(0.0, dot( vertNormal, normalize(-light.position-normalize(ecPos) )));" + - - " if( nDotVP != 0.0 ){" + - " powerFactor = pow( nDotVH, uShininess );" + - " }" + - - " col += light.color * nDotVP;" + - " spec += uSpecular * powerFactor;" + - "}" + - - /* - col - accumulated color - spec - accumulated specular highlight - vertNormal - Normal of the vertex - ecPos - eye coordinate position - light - light structure - */ - "void PointLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + - " float powerFactor;" + - - // Get the vector from the light to the vertex. - " vec3 VP = light.position - ecPos;" + - - // Get the distance from the current vector to the light position. - " float d = length( VP ); " + - - // Normalize the light ray so it can be used in the dot product operation. - " VP = normalize( VP );" + - - " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + - - " float nDotVP = max( 0.0, dot( vertNormal, VP ));" + - " vec3 halfVector = normalize( VP - normalize(ecPos) );" + - " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" + - - " if( nDotVP == 0.0 ) {" + - " powerFactor = 0.0;" + - " }" + - " else {" + - " powerFactor = pow( nDotHV, uShininess );" + - " }" + - - " spec += uSpecular * powerFactor * attenuation;" + - " col += light.color * nDotVP * attenuation;" + - "}" + - - /* - col - accumulated color - spec - accumulated specular highlight - vertNormal - Normal of the vertex - ecPos - eye coordinate position - light - light structure - */ - "void SpotLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + - " float spotAttenuation;" + - " float powerFactor = 0.0;" + - - // Calculate the vector from the current vertex to the light. - " vec3 VP = light.position - ecPos;" + - " vec3 ldir = normalize( -light.direction );" + - - // Get the distance from the spotlight and the vertex - " float d = length( VP );" + - " VP = normalize( VP );" + - - " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ) );" + - - // Dot product of the vector from vertex to light and light direction. - " float spotDot = dot( VP, ldir );" + - - // If the vertex falls inside the cone - (webglMaxTempsWorkaround ? // Windows reports max temps error if light.angle is used - " spotAttenuation = 1.0; " : - " if( spotDot > cos( light.angle ) ) {" + - " spotAttenuation = pow( spotDot, light.concentration );" + - " }" + - " else{" + - " spotAttenuation = 0.0;" + - " }" + - " attenuation *= spotAttenuation;" + - "") + - - " float nDotVP = max( 0.0, dot( vertNormal, VP ) );" + - " vec3 halfVector = normalize( VP - normalize(ecPos) );" + - " float nDotHV = max( 0.0, dot( vertNormal, halfVector ) );" + - - " if( nDotVP != 0.0 ) {" + - " powerFactor = pow( nDotHV, uShininess );" + - " }" + - - " spec += uSpecular * powerFactor * attenuation;" + - " col += light.color * nDotVP * attenuation;" + - "}" + - - "void main(void) {" + - " vec3 finalAmbient = vec3( 0.0 );" + - " vec3 finalDiffuse = vec3( 0.0 );" + - " vec3 finalSpecular = vec3( 0.0 );" + - - " vec4 col = uColor;" + - - " if ( uColor[0] == -1.0 ){" + - " col = aColor;" + - " }" + - - // We use the sphere vertices as the normals when we create the sphere buffer. - // But this only works if the sphere vertices are unit length, so we - // have to normalize the normals here. Since this is only required for spheres - // we could consider placing this in a conditional later on. - " vec3 norm = normalize(vec3( uNormalTransform * vec4( aNormal, 0.0 ) ));" + - - " vec4 ecPos4 = uView * uModel * vec4(aVertex, 1.0);" + - " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + - - // If there were no lights this draw call, just use the - // assigned fill color of the shape and the specular value. - " if( uLightCount == 0 ) {" + - " vFrontColor = col + vec4(uMaterialSpecular, 1.0);" + - " }" + - " else {" + - // WebGL forces us to iterate over a constant value - // so we can't iterate using lightCount. - " for( int i = 0; i < 8; i++ ) {" + - " Light l = getLight(i);" + - - // We can stop iterating if we know we have gone past - // the number of lights which are actually on. This gives us a - // significant performance increase with high vertex counts. - " if( i >= uLightCount ){" + - " break;" + - " }" + - - " if( l.type == 0 ) {" + - " AmbientLight( finalAmbient, ecPos, l );" + - " }" + - " else if( l.type == 1 ) {" + - " DirectionalLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + - " }" + - " else if( l.type == 2 ) {" + - " PointLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + - " }" + - " else {" + - " SpotLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + - " }" + - " }" + - - " if( uUsingMat == false ) {" + - " vFrontColor = vec4(" + - " vec3( col ) * finalAmbient +" + - " vec3( col ) * finalDiffuse +" + - " vec3( col ) * finalSpecular," + - " col[3] );" + - " }" + - " else{" + - " vFrontColor = vec4( " + - " uMaterialEmissive + " + - " (vec3(col) * uMaterialAmbient * finalAmbient ) + " + - " (vec3(col) * finalDiffuse) + " + - " (uMaterialSpecular * finalSpecular), " + - " col[3] );" + - " }" + - " }" + - - " vTexture.xy = aTexture.xy;" + - " gl_Position = uProjection * uView * uModel * vec4( aVertex, 1.0 );" + - "}"; - - var fragmentShaderSrc3D = - "#ifdef GL_ES\n" + - "precision highp float;\n" + - "#endif\n" + - - "varying vec4 vFrontColor;" + - - "uniform sampler2D uSampler;" + - "uniform bool uUsingTexture;" + - "varying vec2 vTexture;" + - - // In Processing, when a texture is used, the fill color is ignored - // vec4(1.0,1.0,1.0,0.5) - "void main(void){" + - " if( uUsingTexture ){" + - " gl_FragColor = vec4(texture2D(uSampler, vTexture.xy)) * vFrontColor;" + - " }"+ - " else{" + - " gl_FragColor = vFrontColor;" + - " }" + - "}"; - - //////////////////////////////////////////////////////////////////////////// - // 3D Functions - //////////////////////////////////////////////////////////////////////////// - - /* - * Sets a uniform variable in a program object to a particular - * value. Before calling this function, ensure the correct - * program object has been installed as part of the current - * rendering state by calling useProgram. - * - * On some systems, if the variable exists in the shader but isn't used, - * the compiler will optimize it out and this function will fail. - * - * @param {String} cacheId - * @param {WebGLProgram} programObj program object returned from - * createProgramObject - * @param {String} varName the name of the variable in the shader - * @param {float | Array} varValue either a scalar value or an Array - * - * @returns none - * - * @see uniformi - * @see uniformMatrix - */ - function uniformf(cacheId, programObj, varName, varValue) { - var varLocation = curContextCache.locations[cacheId]; - if(varLocation === undef) { - varLocation = curContext.getUniformLocation(programObj, varName); - curContextCache.locations[cacheId] = varLocation; - } - // the variable won't be found if it was optimized out. - if (varLocation !== null) { - if (varValue.length === 4) { - curContext.uniform4fv(varLocation, varValue); - } else if (varValue.length === 3) { - curContext.uniform3fv(varLocation, varValue); - } else if (varValue.length === 2) { - curContext.uniform2fv(varLocation, varValue); - } else { - curContext.uniform1f(varLocation, varValue); - } - } - } - - /** - * Sets a uniform int or int array in a program object to a particular - * value. Before calling this function, ensure the correct - * program object has been installed as part of the current - * rendering state. - * - * On some systems, if the variable exists in the shader but isn't used, - * the compiler will optimize it out and this function will fail. - * - * @param {String} cacheId - * @param {WebGLProgram} programObj program object returned from - * createProgramObject - * @param {String} varName the name of the variable in the shader - * @param {int | Array} varValue either a scalar value or an Array - * - * @returns none - * - * @see uniformf - * @see uniformMatrix - */ - function uniformi(cacheId, programObj, varName, varValue) { - var varLocation = curContextCache.locations[cacheId]; - if(varLocation === undef) { - varLocation = curContext.getUniformLocation(programObj, varName); - curContextCache.locations[cacheId] = varLocation; - } - // the variable won't be found if it was optimized out. - if (varLocation !== null) { - if (varValue.length === 4) { - curContext.uniform4iv(varLocation, varValue); - } else if (varValue.length === 3) { - curContext.uniform3iv(varLocation, varValue); - } else if (varValue.length === 2) { - curContext.uniform2iv(varLocation, varValue); - } else { - curContext.uniform1i(varLocation, varValue); - } - } - } - - /** - * Sets the value of a uniform matrix variable in a program - * object. Before calling this function, ensure the correct - * program object has been installed as part of the current - * rendering state. - * - * On some systems, if the variable exists in the shader but - * isn't used, the compiler will optimize it out and this - * function will fail. - * - * @param {String} cacheId - * @param {WebGLProgram} programObj program object returned from - * createProgramObject - * @param {String} varName the name of the variable in the shader - * @param {boolean} transpose must be false - * @param {Array} matrix an array of 4, 9 or 16 values - * - * @returns none - * - * @see uniformi - * @see uniformf - */ - function uniformMatrix(cacheId, programObj, varName, transpose, matrix) { - var varLocation = curContextCache.locations[cacheId]; - if(varLocation === undef) { - varLocation = curContext.getUniformLocation(programObj, varName); - curContextCache.locations[cacheId] = varLocation; - } - // The variable won't be found if it was optimized out. - if (varLocation !== -1) { - if (matrix.length === 16) { - curContext.uniformMatrix4fv(varLocation, transpose, matrix); - } else if (matrix.length === 9) { - curContext.uniformMatrix3fv(varLocation, transpose, matrix); - } else { - curContext.uniformMatrix2fv(varLocation, transpose, matrix); - } - } - } - - /** - * Binds the VBO, sets the vertex attribute data for the program - * object and enables the attribute. - * - * On some systems, if the attribute exists in the shader but - * isn't used, the compiler will optimize it out and this - * function will fail. - * - * @param {String} cacheId - * @param {WebGLProgram} programObj program object returned from - * createProgramObject - * @param {String} varName the name of the variable in the shader - * @param {int} size the number of components per vertex attribute - * @param {WebGLBuffer} VBO Vertex Buffer Object - * - * @returns none - * - * @see disableVertexAttribPointer - */ - function vertexAttribPointer(cacheId, programObj, varName, size, VBO) { - var varLocation = curContextCache.attributes[cacheId]; - if(varLocation === undef) { - varLocation = curContext.getAttribLocation(programObj, varName); - curContextCache.attributes[cacheId] = varLocation; - } - if (varLocation !== -1) { - curContext.bindBuffer(curContext.ARRAY_BUFFER, VBO); - curContext.vertexAttribPointer(varLocation, size, curContext.FLOAT, false, 0, 0); - curContext.enableVertexAttribArray(varLocation); - } - } - - /** - * Disables a program object attribute from being sent to WebGL. - * - * @param {String} cacheId - * @param {WebGLProgram} programObj program object returned from - * createProgramObject - * @param {String} varName name of the attribute - * - * @returns none - * - * @see vertexAttribPointer - */ - function disableVertexAttribPointer(cacheId, programObj, varName){ - var varLocation = curContextCache.attributes[cacheId]; - if(varLocation === undef) { - varLocation = curContext.getAttribLocation(programObj, varName); - curContextCache.attributes[cacheId] = varLocation; - } - if (varLocation !== -1) { - curContext.disableVertexAttribArray(varLocation); - } - } - - /** - * Creates a WebGL program object. - * - * @param {String} vetexShaderSource - * @param {String} fragmentShaderSource - * - * @returns {WebGLProgram} A program object - */ - var createProgramObject = function(curContext, vetexShaderSource, fragmentShaderSource) { - var vertexShaderObject = curContext.createShader(curContext.VERTEX_SHADER); - curContext.shaderSource(vertexShaderObject, vetexShaderSource); - curContext.compileShader(vertexShaderObject); - if (!curContext.getShaderParameter(vertexShaderObject, curContext.COMPILE_STATUS)) { - throw curContext.getShaderInfoLog(vertexShaderObject); - } - - var fragmentShaderObject = curContext.createShader(curContext.FRAGMENT_SHADER); - curContext.shaderSource(fragmentShaderObject, fragmentShaderSource); - curContext.compileShader(fragmentShaderObject); - if (!curContext.getShaderParameter(fragmentShaderObject, curContext.COMPILE_STATUS)) { - throw curContext.getShaderInfoLog(fragmentShaderObject); - } - - var programObject = curContext.createProgram(); - curContext.attachShader(programObject, vertexShaderObject); - curContext.attachShader(programObject, fragmentShaderObject); - curContext.linkProgram(programObject); - if (!curContext.getProgramParameter(programObject, curContext.LINK_STATUS)) { - throw "Error linking shaders."; - } - - return programObject; - }; - - //////////////////////////////////////////////////////////////////////////// - // 2D/3D drawing handling - //////////////////////////////////////////////////////////////////////////// - var imageModeCorner = function(x, y, w, h, whAreSizes) { - return { - x: x, - y: y, - w: w, - h: h - }; - }; - var imageModeConvert = imageModeCorner; - - var imageModeCorners = function(x, y, w, h, whAreSizes) { - return { - x: x, - y: y, - w: whAreSizes ? w : w - x, - h: whAreSizes ? h : h - y - }; - }; - - var imageModeCenter = function(x, y, w, h, whAreSizes) { - return { - x: x - w / 2, - y: y - h / 2, - w: w, - h: h - }; - }; - - // Objects for shared, 2D and 3D contexts - var DrawingShared = function(){}; - var Drawing2D = function(){}; - var Drawing3D = function(){}; - var DrawingPre = function(){}; - - // Setup the prototype chain - Drawing2D.prototype = new DrawingShared(); - Drawing2D.prototype.constructor = Drawing2D; - Drawing3D.prototype = new DrawingShared(); - Drawing3D.prototype.constructor = Drawing3D; - DrawingPre.prototype = new DrawingShared(); - DrawingPre.prototype.constructor = DrawingPre; - - // A no-op function for when the user calls 3D functions from a 2D sketch - // We can change this to a throw or console.error() later if we want - DrawingShared.prototype.a3DOnlyFunction = noop; - - /** - * The shape() function displays shapes to the screen. - * Processing currently works with SVG shapes only. - * The <b>shape</b> parameter specifies the shape to display and the <b>x</b> - * and <b>y</b> parameters define the location of the shape from its - * upper-left corner. - * The shape is displayed at its original size unless the <b>width</b> - * and <b>height</b> parameters specify a different size. - * The <b>shapeMode()</b> function changes the way the parameters work. - * A call to <b>shapeMode(CORNERS)</b>, for example, will change the width - * and height parameters to define the x and y values of the opposite corner - * of the shape. - * <br><br> - * Note complex shapes may draw awkwardly with P2D, P3D, and OPENGL. Those - * renderers do not yet support shapes that have holes or complicated breaks. - * - * @param {PShape} shape the shape to display - * @param {int|float} x x-coordinate of the shape - * @param {int|float} y y-coordinate of the shape - * @param {int|float} width width to display the shape - * @param {int|float} height height to display the shape - * - * @see PShape - * @see loadShape() - * @see shapeMode() - */ - p.shape = function(shape, x, y, width, height) { - if (arguments.length >= 1 && arguments[0] !== null) { - if (shape.isVisible()) { - p.pushMatrix(); - if (curShapeMode === PConstants.CENTER) { - if (arguments.length === 5) { - p.translate(x - width/2, y - height/2); - p.scale(width / shape.getWidth(), height / shape.getHeight()); - } else if (arguments.length === 3) { - p.translate(x - shape.getWidth()/2, - shape.getHeight()/2); - } else { - p.translate(-shape.getWidth()/2, -shape.getHeight()/2); - } - } else if (curShapeMode === PConstants.CORNER) { - if (arguments.length === 5) { - p.translate(x, y); - p.scale(width / shape.getWidth(), height / shape.getHeight()); - } else if (arguments.length === 3) { - p.translate(x, y); - } - } else if (curShapeMode === PConstants.CORNERS) { - if (arguments.length === 5) { - width -= x; - height -= y; - p.translate(x, y); - p.scale(width / shape.getWidth(), height / shape.getHeight()); - } else if (arguments.length === 3) { - p.translate(x, y); - } - } - shape.draw(p); - if ((arguments.length === 1 && curShapeMode === PConstants.CENTER ) || arguments.length > 1) { - p.popMatrix(); - } - } - } - }; - - /** - * The shapeMode() function modifies the location from which shapes draw. - * The default mode is <b>shapeMode(CORNER)</b>, which specifies the - * location to be the upper left corner of the shape and uses the third - * and fourth parameters of <b>shape()</b> to specify the width and height. - * The syntax <b>shapeMode(CORNERS)</b> uses the first and second parameters - * of <b>shape()</b> to set the location of one corner and uses the third - * and fourth parameters to set the opposite corner. - * The syntax <b>shapeMode(CENTER)</b> draws the shape from its center point - * and uses the third and forth parameters of <b>shape()</b> to specify the - * width and height. - * The parameter must be written in "ALL CAPS" because Processing syntax - * is case sensitive. - * - * @param {int} mode One of CORNER, CORNERS, CENTER - * - * @see shape() - * @see rectMode() - */ - p.shapeMode = function (mode) { - curShapeMode = mode; - }; - - /** - * The loadShape() function loads vector shapes into a variable of type PShape. Currently, only SVG files may be loaded. - * In most cases, <b>loadShape()</b> should be used inside <b>setup()</b> because loading shapes inside <b>draw()</b> will reduce the speed of a sketch. - * - * @param {String} filename an SVG file - * - * @return {PShape} a object of type PShape or null - * @see PShape - * @see PApplet#shape() - * @see PApplet#shapeMode() - */ - p.loadShape = function (filename) { - if (arguments.length === 1) { - if (filename.indexOf(".svg") > -1) { - return new PShapeSVG(null, filename); - } - } - return null; - }; - - /** - * Processing 2.0 function for loading XML files. - * - * @param {String} uri The uri for the xml file to load. - * - * @return {XML} An XML object representing the xml data. - */ - p.loadXML = function(uri) { - return new XML(p, uri); - }; - - /** - * Processing 2.0 function for creating XML elements from string - * - * @param {String} xml the XML source code - * - * @return {XML} An XML object representation of the input XML markup. - */ - p.parseXML = function(xmlstring) { - var element = new XML(); - element.parse(xmlstring); - return element; - }; - - //////////////////////////////////////////////////////////////////////////// - // 2D Matrix - //////////////////////////////////////////////////////////////////////////// - - /** - * Helper function for printMatrix(). Finds the largest scalar - * in the matrix, then number of digits left of the decimal. - * Call from PMatrix2D and PMatrix3D's print() function. - */ - var printMatrixHelper = function(elements) { - var big = 0; - for (var i = 0; i < elements.length; i++) { - if (i !== 0) { - big = Math.max(big, Math.abs(elements[i])); - } else { - big = Math.abs(elements[i]); - } - } - - var digits = (big + "").indexOf("."); - if (digits === 0) { - digits = 1; - } else if (digits === -1) { - digits = (big + "").length; - } - - return digits; - }; - /** - * PMatrix2D is a 3x2 affine matrix implementation. The constructor accepts another PMatrix2D or a list of six float elements. - * If no parameters are provided the matrix is set to the identity matrix. - * - * @param {PMatrix2D} matrix the initial matrix to set to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fifth element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - var PMatrix2D = p.PMatrix2D = function() { - if (arguments.length === 0) { - this.reset(); - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - this.set(arguments[0].array()); - } else if (arguments.length === 6) { - this.set(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); - } - }; - /** - * PMatrix2D methods - */ - PMatrix2D.prototype = { - /** - * @member PMatrix2D - * The set() function sets the matrix elements. The function accepts either another PMatrix2D, an array of elements, or a list of six floats. - * - * @param {PMatrix2D} matrix the matrix to set this matrix to - * @param {float[]} elements an array of elements to set this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fith element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - set: function() { - if (arguments.length === 6) { - var a = arguments; - this.set([a[0], a[1], a[2], - a[3], a[4], a[5]]); - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - this.elements = arguments[0].array(); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - this.elements = arguments[0].slice(); - } - }, - /** - * @member PMatrix2D - * The get() function returns a copy of this PMatrix2D. - * - * @return {PMatrix2D} a copy of this PMatrix2D - */ - get: function() { - var outgoing = new PMatrix2D(); - outgoing.set(this.elements); - return outgoing; - }, - /** - * @member PMatrix2D - * The reset() function sets this PMatrix2D to the identity matrix. - */ - reset: function() { - this.set([1, 0, 0, 0, 1, 0]); - }, - /** - * @member PMatrix2D - * The array() function returns a copy of the element values. - * @addon - * - * @return {float[]} returns a copy of the element values - */ - array: function array() { - return this.elements.slice(); - }, - /** - * @member PMatrix2D - * The translate() function translates this matrix by moving the current coordinates to the location specified by tx and ty. - * - * @param {float} tx the x-axis coordinate to move to - * @param {float} ty the y-axis coordinate to move to - */ - translate: function(tx, ty) { - this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this.elements[2]; - this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this.elements[5]; - }, - /** - * @member PMatrix2D - * The invTranslate() function translates this matrix by moving the current coordinates to the negative location specified by tx and ty. - * - * @param {float} tx the x-axis coordinate to move to - * @param {float} ty the y-axis coordinate to move to - */ - invTranslate: function(tx, ty) { - this.translate(-tx, -ty); - }, - /** - * @member PMatrix2D - * The transpose() function is not used in processingjs. - */ - transpose: function() { - // Does nothing in Processing. - }, - /** - * @member PMatrix2D - * The mult() function multiplied this matrix. - * If two array elements are passed in the function will multiply a two element vector against this matrix. - * If target is null or not length four, a new float array will be returned. - * The values for vec and target can be the same (though that's less efficient). - * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix. - * - * @param {PVector} source, target the PVectors used to multiply this matrix - * @param {float[]} source, target the arrays used to multiply this matrix - * - * @return {PVector|float[]} returns a PVector or an array representing the new matrix - */ - mult: function(source, target) { - var x, y; - if (source instanceof PVector) { - x = source.x; - y = source.y; - if (!target) { - target = new PVector(); - } - } else if (source instanceof Array) { - x = source[0]; - y = source[1]; - if (!target) { - target = []; - } - } - if (target instanceof Array) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2]; - target[1] = this.elements[3] * x + this.elements[4] * y + this.elements[5]; - } else if (target instanceof PVector) { - target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2]; - target.y = this.elements[3] * x + this.elements[4] * y + this.elements[5]; - target.z = 0; - } - return target; - }, - /** - * @member PMatrix2D - * The multX() function calculates the x component of a vector from a transformation. - * - * @param {float} x the x component of the vector being transformed - * @param {float} y the y component of the vector being transformed - * - * @return {float} returnes the result of the calculation - */ - multX: function(x, y) { - return (x * this.elements[0] + y * this.elements[1] + this.elements[2]); - }, - /** - * @member PMatrix2D - * The multY() function calculates the y component of a vector from a transformation. - * - * @param {float} x the x component of the vector being transformed - * @param {float} y the y component of the vector being transformed - * - * @return {float} returnes the result of the calculation - */ - multY: function(x, y) { - return (x * this.elements[3] + y * this.elements[4] + this.elements[5]); - }, - /** - * @member PMatrix2D - * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewX: function(angle) { - this.apply(1, 0, 1, angle, 0, 0); - }, - /** - * @member PMatrix2D - * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewY: function(angle) { - this.apply(1, 0, 1, 0, angle, 0); - }, - /** - * @member PMatrix2D - * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - shearX: function(angle) { - this.apply(1, 0, 1, Math.tan(angle) , 0, 0); - }, - /** - * @member PMatrix2D - * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - shearY: function(angle) { - this.apply(1, 0, 1, 0, Math.tan(angle), 0); - }, - /** - * @member PMatrix2D - * The determinant() function calvculates the determinant of this matrix. - * - * @return {float} the determinant of the matrix - */ - determinant: function() { - return (this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3]); - }, - /** - * @member PMatrix2D - * The invert() function inverts this matrix - * - * @return {boolean} true if successful - */ - invert: function() { - var d = this.determinant(); - if (Math.abs( d ) > PConstants.MIN_INT) { - var old00 = this.elements[0]; - var old01 = this.elements[1]; - var old02 = this.elements[2]; - var old10 = this.elements[3]; - var old11 = this.elements[4]; - var old12 = this.elements[5]; - this.elements[0] = old11 / d; - this.elements[3] = -old10 / d; - this.elements[1] = -old01 / d; - this.elements[4] = old00 / d; - this.elements[2] = (old01 * old12 - old11 * old02) / d; - this.elements[5] = (old10 * old02 - old00 * old12) / d; - return true; - } - return false; - }, - /** - * @member PMatrix2D - * The scale() function increases or decreases the size of a shape by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions. - * This is equivalent to a two parameter call. - * - * @param {float} sx the amount to scale on the x-axis - * @param {float} sy the amount to scale on the y-axis - */ - scale: function(sx, sy) { - if (sx && !sy) { - sy = sx; - } - if (sx && sy) { - this.elements[0] *= sx; - this.elements[1] *= sy; - this.elements[3] *= sx; - this.elements[4] *= sy; - } - }, - /** - * @member PMatrix2D - * The invScale() function decreases or increases the size of a shape by contracting and expanding vertices. When only one parameter is specified scale will occur in all dimensions. - * This is equivalent to a two parameter call. - * - * @param {float} sx the amount to scale on the x-axis - * @param {float} sy the amount to scale on the y-axis - */ - invScale: function(sx, sy) { - if (sx && !sy) { - sy = sx; - } - this.scale(1 / sx, 1 / sy); - }, - /** - * @member PMatrix2D - * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix2D or a list of floats can be passed in. - * - * @param {PMatrix2D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fith element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - apply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - source = arguments[0].array(); - } else if (arguments.length === 6) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - - var result = [0, 0, this.elements[2], - 0, 0, this.elements[5]]; - var e = 0; - for (var row = 0; row < 2; row++) { - for (var col = 0; col < 3; col++, e++) { - result[e] += this.elements[row * 3 + 0] * source[col + 0] + - this.elements[row * 3 + 1] * source[col + 3]; - } - } - this.elements = result.slice(); - }, - /** - * @member PMatrix2D - * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix2D or elements of a matrix can be passed in. - * - * @param {PMatrix2D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the third element of the matrix - * @param {float} m10 the fourth element of the matrix - * @param {float} m11 the fith element of the matrix - * @param {float} m12 the sixth element of the matrix - */ - preApply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) { - source = arguments[0].array(); - } else if (arguments.length === 6) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - var result = [0, 0, source[2], - 0, 0, source[5]]; - result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1]; - result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4]; - result[0] = this.elements[0] * source[0] + this.elements[3] * source[1]; - result[3] = this.elements[0] * source[3] + this.elements[3] * source[4]; - result[1] = this.elements[1] * source[0] + this.elements[4] * source[1]; - result[4] = this.elements[1] * source[3] + this.elements[4] * source[4]; - this.elements = result.slice(); - }, - /** - * @member PMatrix2D - * The rotate() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotate: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - var temp1 = this.elements[0]; - var temp2 = this.elements[1]; - this.elements[0] = c * temp1 + s * temp2; - this.elements[1] = -s * temp1 + c * temp2; - temp1 = this.elements[3]; - temp2 = this.elements[4]; - this.elements[3] = c * temp1 + s * temp2; - this.elements[4] = -s * temp1 + c * temp2; - }, - /** - * @member PMatrix2D - * The rotateZ() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateZ: function(angle) { - this.rotate(angle); - }, - /** - * @member PMatrix2D - * The invRotateZ() function rotates the matrix in opposite direction. - * - * @param {float} angle the angle of rotation in radiants - */ - invRotateZ: function(angle) { - this.rotateZ(angle - Math.PI); - }, - /** - * @member PMatrix2D - * The print() function prints out the elements of this matrix - */ - print: function() { - var digits = printMatrixHelper(this.elements); - var output = "" + p.nfs(this.elements[0], digits, 4) + " " + - p.nfs(this.elements[1], digits, 4) + " " + - p.nfs(this.elements[2], digits, 4) + "\n" + - p.nfs(this.elements[3], digits, 4) + " " + - p.nfs(this.elements[4], digits, 4) + " " + - p.nfs(this.elements[5], digits, 4) + "\n\n"; - p.println(output); - } - }; - - /** - * PMatrix3D is a 4x4 matrix implementation. The constructor accepts another PMatrix3D or a list of six or sixteen float elements. - * If no parameters are provided the matrix is set to the identity matrix. - */ - var PMatrix3D = p.PMatrix3D = function() { - // When a matrix is created, it is set to an identity matrix - this.reset(); - }; - /** - * PMatrix3D methods - */ - PMatrix3D.prototype = { - /** - * @member PMatrix2D - * The set() function sets the matrix elements. The function accepts either another PMatrix3D, an array of elements, or a list of six or sixteen floats. - * - * @param {PMatrix3D} matrix the initial matrix to set to - * @param {float[]} elements an array of elements to set this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - */ - set: function() { - if (arguments.length === 16) { - this.elements = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) { - this.elements = arguments[0].array(); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - this.elements = arguments[0].slice(); - } - }, - /** - * @member PMatrix3D - * The get() function returns a copy of this PMatrix3D. - * - * @return {PMatrix3D} a copy of this PMatrix3D - */ - get: function() { - var outgoing = new PMatrix3D(); - outgoing.set(this.elements); - return outgoing; - }, - /** - * @member PMatrix3D - * The reset() function sets this PMatrix3D to the identity matrix. - */ - reset: function() { - this.elements = [1,0,0,0, - 0,1,0,0, - 0,0,1,0, - 0,0,0,1]; - }, - /** - * @member PMatrix3D - * The array() function returns a copy of the element values. - * @addon - * - * @return {float[]} returns a copy of the element values - */ - array: function array() { - return this.elements.slice(); - }, - /** - * @member PMatrix3D - * The translate() function translates this matrix by moving the current coordinates to the location specified by tx, ty, and tz. - * - * @param {float} tx the x-axis coordinate to move to - * @param {float} ty the y-axis coordinate to move to - * @param {float} tz the z-axis coordinate to move to - */ - translate: function(tx, ty, tz) { - if (tz === undef) { - tz = 0; - } - - this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2]; - this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6]; - this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10]; - this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + tz * this.elements[14]; - }, - /** - * @member PMatrix3D - * The transpose() function transpose this matrix. - */ - transpose: function() { - var temp = this.elements[4]; - this.elements[4] = this.elements[1]; - this.elements[1] = temp; - - temp = this.elements[8]; - this.elements[8] = this.elements[2]; - this.elements[2] = temp; - - temp = this.elements[6]; - this.elements[6] = this.elements[9]; - this.elements[9] = temp; - - temp = this.elements[3]; - this.elements[3] = this.elements[12]; - this.elements[12] = temp; - - temp = this.elements[7]; - this.elements[7] = this.elements[13]; - this.elements[13] = temp; - - temp = this.elements[11]; - this.elements[11] = this.elements[14]; - this.elements[14] = temp; - }, - /** - * @member PMatrix3D - * The mult() function multiplied this matrix. - * If two array elements are passed in the function will multiply a two element vector against this matrix. - * If target is null or not length four, a new float array will be returned. - * The values for vec and target can be the same (though that's less efficient). - * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix. - * - * @param {PVector} source, target the PVectors used to multiply this matrix - * @param {float[]} source, target the arrays used to multiply this matrix - * - * @return {PVector|float[]} returns a PVector or an array representing the new matrix - */ - mult: function(source, target) { - var x, y, z, w; - if (source instanceof PVector) { - x = source.x; - y = source.y; - z = source.z; - w = 1; - if (!target) { - target = new PVector(); - } - } else if (source instanceof Array) { - x = source[0]; - y = source[1]; - z = source[2]; - w = source[3] || 1; - - if ( !target || (target.length !== 3 && target.length !== 4) ) { - target = [0, 0, 0]; - } - } - - if (target instanceof Array) { - if (target.length === 3) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - } else if (target.length === 4) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w; - target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w; - target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w; - target[3] = this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w; - } - } - if (target instanceof PVector) { - target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - target.y = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - target.z = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - } - return target; - }, - /** - * @member PMatrix3D - * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix3D or elements of a matrix can be passed in. - * - * @param {PMatrix3D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - */ - preApply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) { - source = arguments[0].array(); - } else if (arguments.length === 16) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - - var result = [0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0]; - var e = 0; - for (var row = 0; row < 4; row++) { - for (var col = 0; col < 4; col++, e++) { - result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] * - source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] + - this.elements[col + 12] * source[row * 4 + 3]; - } - } - this.elements = result.slice(); - }, - /** - * @member PMatrix3D - * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix3D or a list of floats can be passed in. - * - * @param {PMatrix3D} matrix the matrix to apply this matrix to - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - */ - apply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) { - source = arguments[0].array(); - } else if (arguments.length === 16) { - source = Array.prototype.slice.call(arguments); - } else if (arguments.length === 1 && arguments[0] instanceof Array) { - source = arguments[0]; - } - - var result = [0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0]; - var e = 0; - for (var row = 0; row < 4; row++) { - for (var col = 0; col < 4; col++, e++) { - result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] * - source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] + - this.elements[row * 4 + 3] * source[col + 12]; - } - } - this.elements = result.slice(); - }, - /** - * @member PMatrix3D - * The rotate() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotate: function(angle, v0, v1, v2) { - if (arguments.length < 4) { - this.rotateZ(angle); - } else { - var v = new PVector(v0, v1, v2); - var m = v.mag(); - if (m === 0) { - return; - } else if (m != 1) { - v.normalize(); - v0 = v.x; - v1 = v.y; - v2 = v.z; - } - var c = p.cos(angle); - var s = p.sin(angle); - var t = 1.0 - c; - - this.apply((t * v0 * v0) + c, - (t * v0 * v1) - (s * v2), - (t * v0 * v2) + (s * v1), - 0, - (t * v0 * v1) + (s * v2), - (t * v1 * v1) + c, - (t * v1 * v2) - (s * v0), - 0, - (t * v0 * v2) - (s * v1), - (t * v1 * v2) + (s * v0), - (t * v2 * v2) + c, - 0, - 0, 0, 0, 1); - } - }, - /** - * @member PMatrix3D - * The invApply() function applies the inverted matrix to this matrix. - * - * @param {float} m00 the first element of the matrix - * @param {float} m01 the second element of the matrix - * @param {float} m02 the third element of the matrix - * @param {float} m03 the fourth element of the matrix - * @param {float} m10 the fifth element of the matrix - * @param {float} m11 the sixth element of the matrix - * @param {float} m12 the seventh element of the matrix - * @param {float} m13 the eight element of the matrix - * @param {float} m20 the nineth element of the matrix - * @param {float} m21 the tenth element of the matrix - * @param {float} m22 the eleventh element of the matrix - * @param {float} m23 the twelveth element of the matrix - * @param {float} m30 the thirteenth element of the matrix - * @param {float} m31 the fourtheenth element of the matrix - * @param {float} m32 the fivetheenth element of the matrix - * @param {float} m33 the sixteenth element of the matrix - * - * @return {boolean} returns true if the operation was successful. - */ - invApply: function() { - if (inverseCopy === undef) { - inverseCopy = new PMatrix3D(); - } - var a = arguments; - inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], - a[9], a[10], a[11], a[12], a[13], a[14], a[15]); - - if (!inverseCopy.invert()) { - return false; - } - this.preApply(inverseCopy); - return true; - }, - /** - * @member PMatrix3D - * The rotateZ() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateX: function(angle) { - var c = p.cos(angle); - var s = p.sin(angle); - this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]); - }, - /** - * @member PMatrix3D - * The rotateY() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateY: function(angle) { - var c = p.cos(angle); - var s = p.sin(angle); - this.apply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]); - }, - /** - * @member PMatrix3D - * The rotateZ() function rotates the matrix. - * - * @param {float} angle the angle of rotation in radiants - */ - rotateZ: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); - }, - /** - * @member PMatrix3D - * The scale() function increases or decreases the size of a matrix by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions. - * This is equivalent to a three parameter call. - * - * @param {float} sx the amount to scale on the x-axis - * @param {float} sy the amount to scale on the y-axis - * @param {float} sz the amount to scale on the z-axis - */ - scale: function(sx, sy, sz) { - if (sx && !sy && !sz) { - sy = sz = sx; - } else if (sx && sy && !sz) { - sz = 1; - } - - if (sx && sy && sz) { - this.elements[0] *= sx; - this.elements[1] *= sy; - this.elements[2] *= sz; - this.elements[4] *= sx; - this.elements[5] *= sy; - this.elements[6] *= sz; - this.elements[8] *= sx; - this.elements[9] *= sy; - this.elements[10] *= sz; - this.elements[12] *= sx; - this.elements[13] *= sy; - this.elements[14] *= sz; - } - }, - /** - * @member PMatrix3D - * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewX: function(angle) { - var t = Math.tan(angle); - this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - /** - * @member PMatrix3D - * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of skew specified in radians - */ - skewY: function(angle) { - var t = Math.tan(angle); - this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - /** - * @member PMatrix3D - * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of shear specified in radians - */ - shearX: function(angle) { - var t = Math.tan(angle); - this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - /** - * @member PMatrix3D - * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function. - * - * @param {float} angle angle of shear specified in radians - */ - shearY: function(angle) { - var t = Math.tan(angle); - this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - }, - multX: function(x, y, z, w) { - if (!z) { - return this.elements[0] * x + this.elements[1] * y + this.elements[3]; - } - if (!w) { - return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - } - return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w; - }, - multY: function(x, y, z, w) { - if (!z) { - return this.elements[4] * x + this.elements[5] * y + this.elements[7]; - } - if (!w) { - return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - } - return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w; - }, - multZ: function(x, y, z, w) { - if (!w) { - return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - } - return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w; - }, - multW: function(x, y, z, w) { - if (!w) { - return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15]; - } - return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w; - }, - /** - * @member PMatrix3D - * The invert() function inverts this matrix - * - * @return {boolean} true if successful - */ - invert: function() { - var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this.elements[4]; - var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this.elements[4]; - var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this.elements[4]; - var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this.elements[5]; - var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this.elements[5]; - var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this.elements[6]; - var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this.elements[12]; - var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * this.elements[12]; - var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * this.elements[12]; - var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * this.elements[13]; - var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * this.elements[13]; - var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * this.elements[14]; - - // Determinant - var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0; - - // Account for a very small value - // return false if not successful. - if (Math.abs(fDet) <= 1e-9) { - return false; - } - - var kInv = []; - kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elements[7] * fB3; - kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elements[7] * fB1; - kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elements[7] * fB0; - kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.elements[6] * fB0; - kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elements[3] * fB3; - kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elements[3] * fB1; - kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elements[3] * fB0; - kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.elements[2] * fB0; - kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elements[15] * fA3; - kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elements[15] * fA1; - kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.elements[15] * fA0; - kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.elements[14] * fA0; - kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.elements[11] * fA3; - kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.elements[11] * fA1; - kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.elements[11] * fA0; - kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.elements[10] * fA0; - - // Inverse using Determinant - var fInvDet = 1.0 / fDet; - kInv[0] *= fInvDet; - kInv[1] *= fInvDet; - kInv[2] *= fInvDet; - kInv[3] *= fInvDet; - kInv[4] *= fInvDet; - kInv[5] *= fInvDet; - kInv[6] *= fInvDet; - kInv[7] *= fInvDet; - kInv[8] *= fInvDet; - kInv[9] *= fInvDet; - kInv[10] *= fInvDet; - kInv[11] *= fInvDet; - kInv[12] *= fInvDet; - kInv[13] *= fInvDet; - kInv[14] *= fInvDet; - kInv[15] *= fInvDet; - - this.elements = kInv.slice(); - return true; - }, - toString: function() { - var str = ""; - for (var i = 0; i < 15; i++) { - str += this.elements[i] + ", "; - } - str += this.elements[15]; - return str; - }, - /** - * @member PMatrix3D - * The print() function prints out the elements of this matrix - */ - print: function() { - var digits = printMatrixHelper(this.elements); - - var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) + - " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs(this.elements[3], digits, 4) + - "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + - " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) + - "\n" + p.nfs(this.elements[8], digits, 4) + " " + p.nfs(this.elements[9], digits, 4) + - " " + p.nfs(this.elements[10], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) + - "\n" + p.nfs(this.elements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) + - " " + p.nfs(this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n\n"; - p.println(output); - }, - invTranslate: function(tx, ty, tz) { - this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1); - }, - invRotateX: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]); - }, - invRotateY: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]); - }, - invRotateZ: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); - }, - invScale: function(x, y, z) { - this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]); - } - }; - - /** - * @private - * The matrix stack stores the transformations and translations that occur within the space. - */ - var PMatrixStack = p.PMatrixStack = function() { - this.matrixStack = []; - }; - - /** - * @member PMatrixStack - * load pushes the matrix given in the function into the stack - * - * @param {Object | Array} matrix the matrix to be pushed into the stack - */ - PMatrixStack.prototype.load = function() { - var tmpMatrix = drawing.$newPMatrix(); - - if (arguments.length === 1) { - tmpMatrix.set(arguments[0]); - } else { - tmpMatrix.set(arguments); - } - this.matrixStack.push(tmpMatrix); - }; - - Drawing2D.prototype.$newPMatrix = function() { - return new PMatrix2D(); - }; - - Drawing3D.prototype.$newPMatrix = function() { - return new PMatrix3D(); - }; - - /** - * @member PMatrixStack - * push adds a duplicate of the top of the stack onto the stack - uses the peek function - */ - PMatrixStack.prototype.push = function() { - this.matrixStack.push(this.peek()); - }; - - /** - * @member PMatrixStack - * pop removes returns the matrix at the top of the stack - * - * @returns {Object} the matrix at the top of the stack - */ - PMatrixStack.prototype.pop = function() { - return this.matrixStack.pop(); - }; - - /** - * @member PMatrixStack - * peek returns but doesn't remove the matrix at the top of the stack - * - * @returns {Object} the matrix at the top of the stack - */ - PMatrixStack.prototype.peek = function() { - var tmpMatrix = drawing.$newPMatrix(); - - tmpMatrix.set(this.matrixStack[this.matrixStack.length - 1]); - return tmpMatrix; - }; - - /** - * @member PMatrixStack - * this function multiplies the matrix at the top of the stack with the matrix given as a parameter - * - * @param {Object | Array} matrix the matrix to be multiplied into the stack - */ - PMatrixStack.prototype.mult = function(matrix) { - this.matrixStack[this.matrixStack.length - 1].apply(matrix); - }; - - //////////////////////////////////////////////////////////////////////////// - // Array handling - //////////////////////////////////////////////////////////////////////////// - - /** - * The split() function breaks a string into pieces using a character or string - * as the divider. The delim parameter specifies the character or characters that - * mark the boundaries between each piece. A String[] array is returned that contains - * each of the pieces. - * If the result is a set of numbers, you can convert the String[] array to to a float[] - * or int[] array using the datatype conversion functions int() and float() (see example above). - * The splitTokens() function works in a similar fashion, except that it splits using a range - * of characters instead of a specific character or sequence. - * - * @param {String} str the String to be split - * @param {String} delim the character or String used to separate the data - * - * @returns {string[]} The new string array - * - * @see splitTokens - * @see join - * @see trim - */ - p.split = function(str, delim) { - return str.split(delim); - }; - - /** - * The splitTokens() function splits a String at one or many character "tokens." The tokens - * parameter specifies the character or characters to be used as a boundary. - * If no tokens character is specified, any whitespace character is used to split. - * Whitespace characters include tab (\t), line feed (\n), carriage return (\r), form - * feed (\f), and space. To convert a String to an array of integers or floats, use the - * datatype conversion functions int() and float() to convert the array of Strings. - * - * @param {String} str the String to be split - * @param {Char[]} tokens list of individual characters that will be used as separators - * - * @returns {string[]} The new string array - * - * @see split - * @see join - * @see trim - */ - p.splitTokens = function(str, tokens) { - if (tokens === undef) { - return str.split(/\s+/g); - } - - var chars = tokens.split(/()/g), - buffer = "", - len = str.length, - i, c, - tokenized = []; - - for (i = 0; i < len; i++) { - c = str[i]; - if (chars.indexOf(c) > -1) { - if (buffer !== "") { - tokenized.push(buffer); - } - buffer = ""; - } else { - buffer += c; - } - } - - if (buffer !== "") { - tokenized.push(buffer); - } - - return tokenized; - }; - - /** - * Expands an array by one element and adds data to the new position. The datatype of - * the element parameter must be the same as the datatype of the array. - * When using an array of objects, the data returned from the function must be cast to - * the object array's data type. For example: SomeClass[] items = (SomeClass[]) - * append(originalArray, element). - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array boolean[], - * byte[], char[], int[], float[], or String[], or an array of objects - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} element new data for the array - * - * @returns Array (the same datatype as the input) - * - * @see shorten - * @see expand - */ - p.append = function(array, element) { - array[array.length] = element; - return array; - }; - - /** - * Concatenates two arrays. For example, concatenating the array { 1, 2, 3 } and the - * array { 4, 5, 6 } yields { 1, 2, 3, 4, 5, 6 }. Both parameters must be arrays of the - * same datatype. - * When using an array of objects, the data returned from the function must be cast to the - * object array's data type. For example: SomeClass[] items = (SomeClass[]) concat(array1, array2). - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array1 boolean[], - * byte[], char[], int[], float[], String[], or an array of objects - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array2 boolean[], - * byte[], char[], int[], float[], String[], or an array of objects - * - * @returns Array (the same datatype as the input) - * - * @see splice - */ - p.concat = function(array1, array2) { - return array1.concat(array2); - }; - - /** - * Sorts an array of numbers from smallest to largest and puts an array of - * words in alphabetical order. The original array is not modified, a - * re-ordered array is returned. The count parameter states the number of - * elements to sort. For example if there are 12 elements in an array and - * if count is the value 5, only the first five elements on the array will - * be sorted. Alphabetical ordering is case insensitive. - * - * @param {String[] | int[] | float[]} array Array of elements to sort - * @param {int} numElem Number of elements to sort - * - * @returns {String[] | int[] | float[]} Array (same datatype as the input) - * - * @see reverse - */ - p.sort = function(array, numElem) { - var ret = []; - - // depending on the type used (int, float) or string - // we'll need to use a different compare function - if (array.length > 0) { - // copy since we need to return another array - var elemsToCopy = numElem > 0 ? numElem : array.length; - for (var i = 0; i < elemsToCopy; i++) { - ret.push(array[i]); - } - if (typeof array[0] === "string") { - ret.sort(); - } - // int or float - else { - ret.sort(function(a, b) { - return a - b; - }); - } - - // copy on the rest of the elements that were not sorted in case the user - // only wanted a subset of an array to be sorted. - if (numElem > 0) { - for (var j = ret.length; j < array.length; j++) { - ret.push(array[j]); - } - } - } - return ret; - }; - - /** - * Inserts a value or array of values into an existing array. The first two parameters must - * be of the same datatype. The array parameter defines the array which will be modified - * and the second parameter defines the data which will be inserted. When using an array - * of objects, the data returned from the function must be cast to the object array's data - * type. For example: SomeClass[] items = (SomeClass[]) splice(array1, array2, index). - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array boolean[], - * byte[], char[], int[], float[], String[], or an array of objects - * @param {boolean|byte|char|int|float|String|boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} - * value boolean, byte, char, int, float, String, boolean[], byte[], char[], int[], - * float[], String[], or other Object: value or an array of objects to be spliced in - * @param {int} index position in the array from which to insert data - * - * @returns Array (the same datatype as the input) - * - * @see contract - * @see subset - */ - p.splice = function(array, value, index) { - - // Trying to splice an empty array into "array" in P5 won't do - // anything, just return the original. - if(value.length === 0) - { - return array; - } - - // If the second argument was an array, we'll need to iterate over all - // the "value" elements and add one by one because - // array.splice(index, 0, value); - // would create a multi-dimensional array which isn't what we want. - if(value instanceof Array) { - for(var i = 0, j = index; i < value.length; j++,i++) { - array.splice(j, 0, value[i]); - } - } else { - array.splice(index, 0, value); - } - - return array; - }; - - /** - * Extracts an array of elements from an existing array. The array parameter defines the - * array from which the elements will be copied and the offset and length parameters determine - * which elements to extract. If no length is given, elements will be extracted from the offset - * to the end of the array. When specifying the offset remember the first array element is 0. - * This function does not change the source array. - * When using an array of objects, the data returned from the function must be cast to the - * object array's data type. - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array boolean[], - * byte[], char[], int[], float[], String[], or an array of objects - * @param {int} offset position to begin - * @param {int} length number of values to extract - * - * @returns Array (the same datatype as the input) - * - * @see splice - */ - p.subset = function(array, offset, length) { - var end = (length !== undef) ? offset + length : array.length; - return array.slice(offset, end); - }; - - /** - * Combines an array of Strings into one String, each separated by the character(s) used for - * the separator parameter. To join arrays of ints or floats, it's necessary to first convert - * them to strings using nf() or nfs(). - * - * @param {Array} array array of Strings - * @param {char|String} separator char or String to be placed between each item - * - * @returns {String} The combined string - * - * @see split - * @see trim - * @see nf - * @see nfs - */ - p.join = function(array, seperator) { - return array.join(seperator); - }; - - /** - * Decreases an array by one element and returns the shortened array. When using an - * array of objects, the data returned from the function must be cast to the object array's - * data type. For example: SomeClass[] items = (SomeClass[]) shorten(originalArray). - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array - * boolean[], byte[], char[], int[], float[], or String[], or an array of objects - * - * @returns Array (the same datatype as the input) - * - * @see append - * @see expand - */ - p.shorten = function(ary) { - var newary = []; - - // copy array into new array - var len = ary.length; - for (var i = 0; i < len; i++) { - newary[i] = ary[i]; - } - newary.pop(); - - return newary; - }; - - /** - * Increases the size of an array. By default, this function doubles the size of the array, - * but the optional newSize parameter provides precise control over the increase in size. - * When using an array of objects, the data returned from the function must be cast to the - * object array's data type. For example: SomeClass[] items = (SomeClass[]) expand(originalArray). - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} ary - * boolean[], byte[], char[], int[], float[], String[], or an array of objects - * @param {int} newSize positive int: new size for the array - * - * @returns Array (the same datatype as the input) - * - * @see contract - */ - p.expand = function(ary, targetSize) { - var temp = ary.slice(0), - newSize = targetSize || ary.length * 2; - temp.length = newSize; - return temp; - }; - - /** - * Copies an array (or part of an array) to another array. The src array is copied to the - * dst array, beginning at the position specified by srcPos and into the position specified - * by dstPos. The number of elements to copy is determined by length. The simplified version - * with two arguments copies an entire array to another of the same size. It is equivalent - * to "arrayCopy(src, 0, dst, 0, src.length)". This function is far more efficient for copying - * array data than iterating through a for and copying each element. - * - * @param {Array} src an array of any data type: the source array - * @param {Array} dest an array of any data type (as long as it's the same as src): the destination array - * @param {int} srcPos starting position in the source array - * @param {int} destPos starting position in the destination array - * @param {int} length number of array elements to be copied - * - * @returns none - */ - p.arrayCopy = function() { // src, srcPos, dest, destPos, length) { - var src, srcPos = 0, dest, destPos = 0, length; - - if (arguments.length === 2) { - // recall itself and copy src to dest from start index 0 to 0 of src.length - src = arguments[0]; - dest = arguments[1]; - length = src.length; - } else if (arguments.length === 3) { - // recall itself and copy src to dest from start index 0 to 0 of length - src = arguments[0]; - dest = arguments[1]; - length = arguments[2]; - } else if (arguments.length === 5) { - src = arguments[0]; - srcPos = arguments[1]; - dest = arguments[2]; - destPos = arguments[3]; - length = arguments[4]; - } - - // copy src to dest from index srcPos to index destPos of length recursivly on objects - for (var i = srcPos, j = destPos; i < length + srcPos; i++, j++) { - if (dest[j] !== undef) { - dest[j] = src[i]; - } else { - throw "array index out of bounds exception"; - } - } - }; - - /** - * Reverses the order of an array. - * - * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]} array - * boolean[], byte[], char[], int[], float[], or String[] - * - * @returns Array (the same datatype as the input) - * - * @see sort - */ - p.reverse = function(array) { - return array.reverse(); - }; - - - //////////////////////////////////////////////////////////////////////////// - // Color functions - //////////////////////////////////////////////////////////////////////////// - - // helper functions for internal blending modes - p.mix = function(a, b, f) { - return a + (((b - a) * f) >> 8); - }; - - p.peg = function(n) { - return (n < 0) ? 0 : ((n > 255) ? 255 : n); - }; - - // blending modes - /** - * These are internal blending modes used for BlendColor() - * - * @param {Color} c1 First Color to blend - * @param {Color} c2 Second Color to blend - * - * @returns {Color} The blended Color - * - * @see BlendColor - * @see Blend - */ - p.modes = (function() { - var ALPHA_MASK = PConstants.ALPHA_MASK, - RED_MASK = PConstants.RED_MASK, - GREEN_MASK = PConstants.GREEN_MASK, - BLUE_MASK = PConstants.BLUE_MASK, - min = Math.min, - max = Math.max; - - function applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) { - var a = min(((c1 & 0xff000000) >>> 24) + f, 0xff) << 24; - - var r = (ar + (((cr - ar) * f) >> 8)); - r = ((r < 0) ? 0 : ((r > 255) ? 255 : r)) << 16; - - var g = (ag + (((cg - ag) * f) >> 8)); - g = ((g < 0) ? 0 : ((g > 255) ? 255 : g)) << 8; - - var b = ab + (((cb - ab) * f) >> 8); - b = (b < 0) ? 0 : ((b > 255) ? 255 : b); - - return (a | r | g | b); - } - - return { - replace: function(c1, c2) { - return c2; - }, - blend: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK), - ag = (c1 & GREEN_MASK), - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK), - bg = (c2 & GREEN_MASK), - bb = (c2 & BLUE_MASK); - - return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 | - (ar + (((br - ar) * f) >> 8)) & RED_MASK | - (ag + (((bg - ag) * f) >> 8)) & GREEN_MASK | - (ab + (((bb - ab) * f) >> 8)) & BLUE_MASK); - }, - add: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24; - return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 | - min(((c1 & RED_MASK) + ((c2 & RED_MASK) >> 8) * f), RED_MASK) & RED_MASK | - min(((c1 & GREEN_MASK) + ((c2 & GREEN_MASK) >> 8) * f), GREEN_MASK) & GREEN_MASK | - min((c1 & BLUE_MASK) + (((c2 & BLUE_MASK) * f) >> 8), BLUE_MASK)); - }, - subtract: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24; - return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 | - max(((c1 & RED_MASK) - ((c2 & RED_MASK) >> 8) * f), GREEN_MASK) & RED_MASK | - max(((c1 & GREEN_MASK) - ((c2 & GREEN_MASK) >> 8) * f), BLUE_MASK) & GREEN_MASK | - max((c1 & BLUE_MASK) - (((c2 & BLUE_MASK) * f) >> 8), 0)); - }, - lightest: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24; - return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 | - max(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f) & RED_MASK | - max(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f) & GREEN_MASK | - max(c1 & BLUE_MASK, ((c2 & BLUE_MASK) * f) >> 8)); - }, - darkest: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK), - ag = (c1 & GREEN_MASK), - ab = (c1 & BLUE_MASK), - br = min(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f), - bg = min(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f), - bb = min(c1 & BLUE_MASK, ((c2 & BLUE_MASK) * f) >> 8); - - return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 | - (ar + (((br - ar) * f) >> 8)) & RED_MASK | - (ag + (((bg - ag) * f) >> 8)) & GREEN_MASK | - (ab + (((bb - ab) * f) >> 8)) & BLUE_MASK); - }, - difference: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = (ar > br) ? (ar - br) : (br - ar), - cg = (ag > bg) ? (ag - bg) : (bg - ag), - cb = (ab > bb) ? (ab - bb) : (bb - ab); - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - exclusion: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = ar + br - ((ar * br) >> 7), - cg = ag + bg - ((ag * bg) >> 7), - cb = ab + bb - ((ab * bb) >> 7); - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - multiply: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = (ar * br) >> 8, - cg = (ag * bg) >> 8, - cb = (ab * bb) >> 8; - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - screen: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = 255 - (((255 - ar) * (255 - br)) >> 8), - cg = 255 - (((255 - ag) * (255 - bg)) >> 8), - cb = 255 - (((255 - ab) * (255 - bb)) >> 8); - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - hard_light: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = (br < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7)), - cg = (bg < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7)), - cb = (bb < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7)); - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - soft_light: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = ((ar * br) >> 7) + ((ar * ar) >> 8) - ((ar * ar * br) >> 15), - cg = ((ag * bg) >> 7) + ((ag * ag) >> 8) - ((ag * ag * bg) >> 15), - cb = ((ab * bb) >> 7) + ((ab * ab) >> 8) - ((ab * ab * bb) >> 15); - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - overlay: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK), - cr = (ar < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7)), - cg = (ag < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7)), - cb = (ab < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7)); - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - dodge: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK); - - var cr = 255; - if (br !== 255) { - cr = (ar << 8) / (255 - br); - cr = (cr < 0) ? 0 : ((cr > 255) ? 255 : cr); - } - - var cg = 255; - if (bg !== 255) { - cg = (ag << 8) / (255 - bg); - cg = (cg < 0) ? 0 : ((cg > 255) ? 255 : cg); - } - - var cb = 255; - if (bb !== 255) { - cb = (ab << 8) / (255 - bb); - cb = (cb < 0) ? 0 : ((cb > 255) ? 255 : cb); - } - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - }, - burn: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = (c1 & BLUE_MASK), - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = (c2 & BLUE_MASK); - - var cr = 0; - if (br !== 0) { - cr = ((255 - ar) << 8) / br; - cr = 255 - ((cr < 0) ? 0 : ((cr > 255) ? 255 : cr)); - } - - var cg = 0; - if (bg !== 0) { - cg = ((255 - ag) << 8) / bg; - cg = 255 - ((cg < 0) ? 0 : ((cg > 255) ? 255 : cg)); - } - - var cb = 0; - if (bb !== 0) { - cb = ((255 - ab) << 8) / bb; - cb = 255 - ((cb < 0) ? 0 : ((cb > 255) ? 255 : cb)); - } - - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb); - } - }; - }()); - - function color$4(aValue1, aValue2, aValue3, aValue4) { - var r, g, b, a; - - if (curColorMode === PConstants.HSB) { - var rgb = p.color.toRGB(aValue1, aValue2, aValue3); - r = rgb[0]; - g = rgb[1]; - b = rgb[2]; - } else { - r = Math.round(255 * (aValue1 / colorModeX)); - g = Math.round(255 * (aValue2 / colorModeY)); - b = Math.round(255 * (aValue3 / colorModeZ)); - } - - a = Math.round(255 * (aValue4 / colorModeA)); - - // Limit values less than 0 and greater than 255 - r = (r < 0) ? 0 : r; - g = (g < 0) ? 0 : g; - b = (b < 0) ? 0 : b; - a = (a < 0) ? 0 : a; - r = (r > 255) ? 255 : r; - g = (g > 255) ? 255 : g; - b = (b > 255) ? 255 : b; - a = (a > 255) ? 255 : a; - - // Create color int - return (a << 24) & PConstants.ALPHA_MASK | (r << 16) & PConstants.RED_MASK | (g << 8) & PConstants.GREEN_MASK | b & PConstants.BLUE_MASK; - } - - function color$2(aValue1, aValue2) { - var a; - - // Color int and alpha - if (aValue1 & PConstants.ALPHA_MASK) { - a = Math.round(255 * (aValue2 / colorModeA)); - // Limit values less than 0 and greater than 255 - a = (a > 255) ? 255 : a; - a = (a < 0) ? 0 : a; - - return aValue1 - (aValue1 & PConstants.ALPHA_MASK) + ((a << 24) & PConstants.ALPHA_MASK); - } - // Grayscale and alpha - if (curColorMode === PConstants.RGB) { - return color$4(aValue1, aValue1, aValue1, aValue2); - } - if (curColorMode === PConstants.HSB) { - return color$4(0, 0, (aValue1 / colorModeX) * colorModeZ, aValue2); - } - } - - function color$1(aValue1) { - // Grayscale - if (aValue1 <= colorModeX && aValue1 >= 0) { - if (curColorMode === PConstants.RGB) { - return color$4(aValue1, aValue1, aValue1, colorModeA); - } - if (curColorMode === PConstants.HSB) { - return color$4(0, 0, (aValue1 / colorModeX) * colorModeZ, colorModeA); - } - } - // Color int - if (aValue1) { - if (aValue1 > 2147483647) { - // Java Overflow - aValue1 -= 4294967296; - } - return aValue1; - } - } - - /** - * Creates colors for storing in variables of the color datatype. The parameters are - * interpreted as RGB or HSB values depending on the current colorMode(). The default - * mode is RGB values from 0 to 255 and therefore, the function call color(255, 204, 0) - * will return a bright yellow color. More about how colors are stored can be found in - * the reference for the color datatype. - * - * @param {int|float} aValue1 red or hue or grey values relative to the current color range. - * Also can be color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00) - * @param {int|float} aValue2 green or saturation values relative to the current color range - * @param {int|float} aValue3 blue or brightness values relative to the current color range - * @param {int|float} aValue4 relative to current color range. Represents alpha - * - * @returns {color} the color - * - * @see colorMode - */ - p.color = function(aValue1, aValue2, aValue3, aValue4) { - - // 4 arguments: (R, G, B, A) or (H, S, B, A) - if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef && aValue4 !== undef) { - return color$4(aValue1, aValue2, aValue3, aValue4); - } - - // 3 arguments: (R, G, B) or (H, S, B) - if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef) { - return color$4(aValue1, aValue2, aValue3, colorModeA); - } - - // 2 arguments: (Color, A) or (Grayscale, A) - if (aValue1 !== undef && aValue2 !== undef) { - return color$2(aValue1, aValue2); - } - - // 1 argument: (Grayscale) or (Color) - if (typeof aValue1 === "number") { - return color$1(aValue1); - } - - // Default - return color$4(colorModeX, colorModeY, colorModeZ, colorModeA); - }; - - // Ease of use function to extract the colour bits into a string - p.color.toString = function(colorInt) { - return "rgba(" + ((colorInt & PConstants.RED_MASK) >>> 16) + "," + ((colorInt & PConstants.GREEN_MASK) >>> 8) + - "," + ((colorInt & PConstants.BLUE_MASK)) + "," + ((colorInt & PConstants.ALPHA_MASK) >>> 24) / 255 + ")"; - }; - - // Easy of use function to pack rgba values into a single bit-shifted color int. - p.color.toInt = function(r, g, b, a) { - return (a << 24) & PConstants.ALPHA_MASK | (r << 16) & PConstants.RED_MASK | (g << 8) & PConstants.GREEN_MASK | b & PConstants.BLUE_MASK; - }; - - // Creates a simple array in [R, G, B, A] format, [255, 255, 255, 255] - p.color.toArray = function(colorInt) { - return [(colorInt & PConstants.RED_MASK) >>> 16, (colorInt & PConstants.GREEN_MASK) >>> 8, - colorInt & PConstants.BLUE_MASK, (colorInt & PConstants.ALPHA_MASK) >>> 24]; - }; - - // Creates a WebGL color array in [R, G, B, A] format. WebGL wants the color ranges between 0 and 1, [1, 1, 1, 1] - p.color.toGLArray = function(colorInt) { - return [((colorInt & PConstants.RED_MASK) >>> 16) / 255, ((colorInt & PConstants.GREEN_MASK) >>> 8) / 255, - (colorInt & PConstants.BLUE_MASK) / 255, ((colorInt & PConstants.ALPHA_MASK) >>> 24) / 255]; - }; - - // HSB conversion function from Mootools, MIT Licensed - p.color.toRGB = function(h, s, b) { - // Limit values greater than range - h = (h > colorModeX) ? colorModeX : h; - s = (s > colorModeY) ? colorModeY : s; - b = (b > colorModeZ) ? colorModeZ : b; - - h = (h / colorModeX) * 360; - s = (s / colorModeY) * 100; - b = (b / colorModeZ) * 100; - - var br = Math.round(b / 100 * 255); - - if (s === 0) { // Grayscale - return [br, br, br]; - } - var hue = h % 360; - var f = hue % 60; - var p = Math.round((b * (100 - s)) / 10000 * 255); - var q = Math.round((b * (6000 - s * f)) / 600000 * 255); - var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255); - switch (Math.floor(hue / 60)) { - case 0: - return [br, t, p]; - case 1: - return [q, br, p]; - case 2: - return [p, br, t]; - case 3: - return [p, q, br]; - case 4: - return [t, p, br]; - case 5: - return [br, p, q]; - } - }; - - function colorToHSB(colorInt) { - var red, green, blue; - - red = ((colorInt & PConstants.RED_MASK) >>> 16) / 255; - green = ((colorInt & PConstants.GREEN_MASK) >>> 8) / 255; - blue = (colorInt & PConstants.BLUE_MASK) / 255; - - var max = p.max(p.max(red,green), blue), - min = p.min(p.min(red,green), blue), - hue, saturation; - - if (min === max) { - return [0, 0, max*colorModeZ]; - } - saturation = (max - min) / max; - - if (red === max) { - hue = (green - blue) / (max - min); - } else if (green === max) { - hue = 2 + ((blue - red) / (max - min)); - } else { - hue = 4 + ((red - green) / (max - min)); - } - - hue /= 6; - - if (hue < 0) { - hue += 1; - } else if (hue > 1) { - hue -= 1; - } - return [hue*colorModeX, saturation*colorModeY, max*colorModeZ]; - } - - /** - * Extracts the brightness value from a color. - * - * @param {color} colInt any value of the color datatype - * - * @returns {float} The brightness color value. - * - * @see red - * @see green - * @see blue - * @see hue - * @see saturation - */ - p.brightness = function(colInt){ - return colorToHSB(colInt)[2]; - }; - - /** - * Extracts the saturation value from a color. - * - * @param {color} colInt any value of the color datatype - * - * @returns {float} The saturation color value. - * - * @see red - * @see green - * @see blue - * @see hue - * @see brightness - */ - p.saturation = function(colInt){ - return colorToHSB(colInt)[1]; - }; - - /** - * Extracts the hue value from a color. - * - * @param {color} colInt any value of the color datatype - * - * @returns {float} The hue color value. - * - * @see red - * @see green - * @see blue - * @see saturation - * @see brightness - */ - p.hue = function(colInt){ - return colorToHSB(colInt)[0]; - }; - - /** - * Extracts the red value from a color, scaled to match current colorMode(). - * This value is always returned as a float so be careful not to assign it to an int value. - * - * @param {color} aColor any value of the color datatype - * - * @returns {float} The red color value. - * - * @see green - * @see blue - * @see alpha - * @see >> right shift - * @see hue - * @see saturation - * @see brightness - */ - p.red = function(aColor) { - return ((aColor & PConstants.RED_MASK) >>> 16) / 255 * colorModeX; - }; - - /** - * Extracts the green value from a color, scaled to match current colorMode(). - * This value is always returned as a float so be careful not to assign it to an int value. - * - * @param {color} aColor any value of the color datatype - * - * @returns {float} The green color value. - * - * @see red - * @see blue - * @see alpha - * @see >> right shift - * @see hue - * @see saturation - * @see brightness - */ - p.green = function(aColor) { - return ((aColor & PConstants.GREEN_MASK) >>> 8) / 255 * colorModeY; - }; - - /** - * Extracts the blue value from a color, scaled to match current colorMode(). - * This value is always returned as a float so be careful not to assign it to an int value. - * - * @param {color} aColor any value of the color datatype - * - * @returns {float} The blue color value. - * - * @see red - * @see green - * @see alpha - * @see >> right shift - * @see hue - * @see saturation - * @see brightness - */ - p.blue = function(aColor) { - return (aColor & PConstants.BLUE_MASK) / 255 * colorModeZ; - }; - - /** - * Extracts the alpha value from a color, scaled to match current colorMode(). - * This value is always returned as a float so be careful not to assign it to an int value. - * - * @param {color} aColor any value of the color datatype - * - * @returns {float} The alpha color value. - * - * @see red - * @see green - * @see blue - * @see >> right shift - * @see hue - * @see saturation - * @see brightness - */ - p.alpha = function(aColor) { - return ((aColor & PConstants.ALPHA_MASK) >>> 24) / 255 * colorModeA; - }; - - /** - * Calculates a color or colors between two colors at a specific increment. - * The amt parameter is the amount to interpolate between the two values where 0.0 - * equal to the first point, 0.1 is very near the first point, 0.5 is half-way in between, etc. - * - * @param {color} c1 interpolate from this color - * @param {color} c2 interpolate to this color - * @param {float} amt between 0.0 and 1.0 - * - * @returns {float} The blended color. - * - * @see blendColor - * @see color - */ - p.lerpColor = function(c1, c2, amt) { - var r, g, b, a, r1, g1, b1, a1, r2, g2, b2, a2; - var hsb1, hsb2, rgb, h, s; - var colorBits1 = p.color(c1); - var colorBits2 = p.color(c2); - - if (curColorMode === PConstants.HSB) { - // Special processing for HSB mode. - // Get HSB and Alpha values for Color 1 and 2 - hsb1 = colorToHSB(colorBits1); - a1 = ((colorBits1 & PConstants.ALPHA_MASK) >>> 24) / colorModeA; - hsb2 = colorToHSB(colorBits2); - a2 = ((colorBits2 & PConstants.ALPHA_MASK) >>> 24) / colorModeA; - - // Return lerp value for each channel, for HSB components - h = p.lerp(hsb1[0], hsb2[0], amt); - s = p.lerp(hsb1[1], hsb2[1], amt); - b = p.lerp(hsb1[2], hsb2[2], amt); - rgb = p.color.toRGB(h, s, b); - // ... and for Alpha-range - a = (p.lerp(a1, a2, amt) * colorModeA + 0.5) | 0; - - return (a << 24) & PConstants.ALPHA_MASK | - (rgb[0] << 16) & PConstants.RED_MASK | - (rgb[1] << 8) & PConstants.GREEN_MASK | - rgb[2] & PConstants.BLUE_MASK; - } - - // Get RGBA values for Color 1 to floats - r1 = (colorBits1 & PConstants.RED_MASK) >>> 16; - g1 = (colorBits1 & PConstants.GREEN_MASK) >>> 8; - b1 = (colorBits1 & PConstants.BLUE_MASK); - a1 = ((colorBits1 & PConstants.ALPHA_MASK) >>> 24) / colorModeA; - - // Get RGBA values for Color 2 to floats - r2 = (colorBits2 & PConstants.RED_MASK) >>> 16; - g2 = (colorBits2 & PConstants.GREEN_MASK) >>> 8; - b2 = (colorBits2 & PConstants.BLUE_MASK); - a2 = ((colorBits2 & PConstants.ALPHA_MASK) >>> 24) / colorModeA; - - // Return lerp value for each channel, INT for color, Float for Alpha-range - r = (p.lerp(r1, r2, amt) + 0.5) | 0; - g = (p.lerp(g1, g2, amt) + 0.5) | 0; - b = (p.lerp(b1, b2, amt) + 0.5) | 0; - a = (p.lerp(a1, a2, amt) * colorModeA + 0.5) | 0; - - return (a << 24) & PConstants.ALPHA_MASK | - (r << 16) & PConstants.RED_MASK | - (g << 8) & PConstants.GREEN_MASK | - b & PConstants.BLUE_MASK; - }; - - /** - * Changes the way Processing interprets color data. By default, fill(), stroke(), and background() - * colors are set by values between 0 and 255 using the RGB color model. It is possible to change the - * numerical range used for specifying colors and to switch color systems. For example, calling colorMode(RGB, 1.0) - * will specify that values are specified between 0 and 1. The limits for defining colors are altered by setting the - * parameters range1, range2, range3, and range 4. - * - * @param {MODE} mode Either RGB or HSB, corresponding to Red/Green/Blue and Hue/Saturation/Brightness - * @param {int|float} range range for all color elements - * @param {int|float} range1 range for the red or hue depending on the current color mode - * @param {int|float} range2 range for the green or saturation depending on the current color mode - * @param {int|float} range3 range for the blue or brightness depending on the current color mode - * @param {int|float} range4 range for the alpha - * - * @returns none - * - * @see background - * @see fill - * @see stroke - */ - p.colorMode = function() { // mode, range1, range2, range3, range4 - curColorMode = arguments[0]; - if (arguments.length > 1) { - colorModeX = arguments[1]; - colorModeY = arguments[2] || arguments[1]; - colorModeZ = arguments[3] || arguments[1]; - colorModeA = arguments[4] || arguments[1]; - } - }; - - /** - * Blends two color values together based on the blending mode given as the MODE parameter. - * The possible modes are described in the reference for the blend() function. - * - * @param {color} c1 color: the first color to blend - * @param {color} c2 color: the second color to blend - * @param {MODE} MODE Either BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, - * SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, or BURN - * - * @returns {float} The blended color. - * - * @see blend - * @see color - */ - p.blendColor = function(c1, c2, mode) { - if (mode === PConstants.REPLACE) { - return p.modes.replace(c1, c2); - } else if (mode === PConstants.BLEND) { - return p.modes.blend(c1, c2); - } else if (mode === PConstants.ADD) { - return p.modes.add(c1, c2); - } else if (mode === PConstants.SUBTRACT) { - return p.modes.subtract(c1, c2); - } else if (mode === PConstants.LIGHTEST) { - return p.modes.lightest(c1, c2); - } else if (mode === PConstants.DARKEST) { - return p.modes.darkest(c1, c2); - } else if (mode === PConstants.DIFFERENCE) { - return p.modes.difference(c1, c2); - } else if (mode === PConstants.EXCLUSION) { - return p.modes.exclusion(c1, c2); - } else if (mode === PConstants.MULTIPLY) { - return p.modes.multiply(c1, c2); - } else if (mode === PConstants.SCREEN) { - return p.modes.screen(c1, c2); - } else if (mode === PConstants.HARD_LIGHT) { - return p.modes.hard_light(c1, c2); - } else if (mode === PConstants.SOFT_LIGHT) { - return p.modes.soft_light(c1, c2); - } else if (mode === PConstants.OVERLAY) { - return p.modes.overlay(c1, c2); - } else if (mode === PConstants.DODGE) { - return p.modes.dodge(c1, c2); - } else if (mode === PConstants.BURN) { - return p.modes.burn(c1, c2); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Canvas-Matrix manipulation - //////////////////////////////////////////////////////////////////////////// - - function saveContext() { - curContext.save(); - } - - function restoreContext() { - curContext.restore(); - isStrokeDirty = true; - isFillDirty = true; - } - - /** - * Prints the current matrix to the text window. - * - * @returns none - * - * @see pushMatrix - * @see popMatrix - * @see resetMatrix - * @see applyMatrix - */ - p.printMatrix = function() { - modelView.print(); - }; - - /** - * Specifies an amount to displace objects within the display window. The x parameter specifies left/right translation, - * the y parameter specifies up/down translation, and the z parameter specifies translations toward/away from the screen. - * Using this function with the z parameter requires using the P3D or OPENGL parameter in combination with size as shown - * in the above example. Transformations apply to everything that happens after and subsequent calls to the function - * accumulates the effect. For example, calling translate(50, 0) and then translate(20, 0) is the same as translate(70, 0). - * If translate() is called within draw(), the transformation is reset when the loop begins again. - * This function can be further controlled by the pushMatrix() and popMatrix(). - * - * @param {int|float} x left/right translation - * @param {int|float} y up/down translation - * @param {int|float} z forward/back translation - * - * @returns none - * - * @see pushMatrix - * @see popMatrix - * @see scale - * @see rotate - * @see rotateX - * @see rotateY - * @see rotateZ - */ - Drawing2D.prototype.translate = function(x, y) { - modelView.translate(x, y); - modelViewInv.invTranslate(x, y); - curContext.translate(x, y); - }; - - Drawing3D.prototype.translate = function(x, y, z) { - modelView.translate(x, y, z); - modelViewInv.invTranslate(x, y, z); - }; - - /** - * Increases or decreases the size of a shape by expanding and contracting vertices. Objects always scale from their - * relative origin to the coordinate system. Scale values are specified as decimal percentages. For example, the - * function call scale(2.0) increases the dimension of a shape by 200%. Transformations apply to everything that - * happens after and subsequent calls to the function multiply the effect. For example, calling scale(2.0) and - * then scale(1.5) is the same as scale(3.0). If scale() is called within draw(), the transformation is reset when - * the loop begins again. Using this fuction with the z parameter requires passing P3D or OPENGL into the size() - * parameter as shown in the example above. This function can be further controlled by pushMatrix() and popMatrix(). - * - * @param {int|float} size percentage to scale the object - * @param {int|float} x percentage to scale the object in the x-axis - * @param {int|float} y percentage to scale the object in the y-axis - * @param {int|float} z percentage to scale the object in the z-axis - * - * @returns none - * - * @see pushMatrix - * @see popMatrix - * @see translate - * @see rotate - * @see rotateX - * @see rotateY - * @see rotateZ - */ - Drawing2D.prototype.scale = function(x, y) { - modelView.scale(x, y); - modelViewInv.invScale(x, y); - curContext.scale(x, y || x); - }; - - Drawing3D.prototype.scale = function(x, y, z) { - modelView.scale(x, y, z); - modelViewInv.invScale(x, y, z); - }; - - - /** - * helper function for applying a transfrom matrix to a 2D context. - */ - Drawing2D.prototype.transform = function(pmatrix) { - var e = pmatrix.array(); - curContext.transform(e[0],e[3],e[1],e[4],e[2],e[5]); - }; - - /** - * helper function for applying a transfrom matrix to a 3D context. - * not currently implemented. - */ - Drawing3D.prototype.transformm = function(pmatrix3d) { - throw("p.transform is currently not supported in 3D mode"); - }; - - - /** - * Pushes the current transformation matrix onto the matrix stack. Understanding pushMatrix() and popMatrix() - * requires understanding the concept of a matrix stack. The pushMatrix() function saves the current coordinate - * system to the stack and popMatrix() restores the prior coordinate system. pushMatrix() and popMatrix() are - * used in conjuction with the other transformation methods and may be embedded to control the scope of - * the transformations. - * - * @returns none - * - * @see popMatrix - * @see translate - * @see rotate - * @see rotateX - * @see rotateY - * @see rotateZ - */ - Drawing2D.prototype.pushMatrix = function() { - userMatrixStack.load(modelView); - userReverseMatrixStack.load(modelViewInv); - saveContext(); - }; - - Drawing3D.prototype.pushMatrix = function() { - userMatrixStack.load(modelView); - userReverseMatrixStack.load(modelViewInv); - }; - - /** - * Pops the current transformation matrix off the matrix stack. Understanding pushing and popping requires - * understanding the concept of a matrix stack. The pushMatrix() function saves the current coordinate system to - * the stack and popMatrix() restores the prior coordinate system. pushMatrix() and popMatrix() are used in - * conjuction with the other transformation methods and may be embedded to control the scope of the transformations. - * - * @returns none - * - * @see popMatrix - * @see pushMatrix - */ - Drawing2D.prototype.popMatrix = function() { - modelView.set(userMatrixStack.pop()); - modelViewInv.set(userReverseMatrixStack.pop()); - restoreContext(); - }; - - Drawing3D.prototype.popMatrix = function() { - modelView.set(userMatrixStack.pop()); - modelViewInv.set(userReverseMatrixStack.pop()); - }; - - /** - * Replaces the current matrix with the identity matrix. The equivalent function in OpenGL is glLoadIdentity(). - * - * @returns none - * - * @see popMatrix - * @see pushMatrix - * @see applyMatrix - * @see printMatrix - */ - Drawing2D.prototype.resetMatrix = function() { - modelView.reset(); - modelViewInv.reset(); - curContext.setTransform(1,0,0,1,0,0); - }; - - Drawing3D.prototype.resetMatrix = function() { - modelView.reset(); - modelViewInv.reset(); - }; - - /** - * Multiplies the current matrix by the one specified through the parameters. This is very slow because it will - * try to calculate the inverse of the transform, so avoid it whenever possible. The equivalent function - * in OpenGL is glMultMatrix(). - * - * @param {int|float} n00-n15 numbers which define the 4x4 matrix to be multiplied - * - * @returns none - * - * @see popMatrix - * @see pushMatrix - * @see resetMatrix - * @see printMatrix - */ - DrawingShared.prototype.applyMatrix = function() { - var a = arguments; - modelView.apply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); - modelViewInv.invApply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); - }; - - Drawing2D.prototype.applyMatrix = function() { - var a = arguments; - for (var cnt = a.length; cnt < 16; cnt++) { - a[cnt] = 0; - } - a[10] = a[15] = 1; - DrawingShared.prototype.applyMatrix.apply(this, a); - }; - - /** - * Rotates a shape around the x-axis the amount specified by the angle parameter. Angles should be - * specified in radians (values from 0 to PI*2) or converted to radians with the radians() function. - * Objects are always rotated around their relative position to the origin and positive numbers - * rotate objects in a counterclockwise direction. Transformations apply to everything that happens - * after and subsequent calls to the function accumulates the effect. For example, calling rotateX(PI/2) - * and then rotateX(PI/2) is the same as rotateX(PI). If rotateX() is called within the draw(), the - * transformation is reset when the loop begins again. This function requires passing P3D or OPENGL - * into the size() parameter as shown in the example above. - * - * @param {int|float} angleInRadians angle of rotation specified in radians - * - * @returns none - * - * @see rotateY - * @see rotateZ - * @see rotate - * @see translate - * @see scale - * @see popMatrix - * @see pushMatrix - */ - p.rotateX = function(angleInRadians) { - modelView.rotateX(angleInRadians); - modelViewInv.invRotateX(angleInRadians); - }; - - /** - * Rotates a shape around the z-axis the amount specified by the angle parameter. Angles should be - * specified in radians (values from 0 to PI*2) or converted to radians with the radians() function. - * Objects are always rotated around their relative position to the origin and positive numbers - * rotate objects in a counterclockwise direction. Transformations apply to everything that happens - * after and subsequent calls to the function accumulates the effect. For example, calling rotateZ(PI/2) - * and then rotateZ(PI/2) is the same as rotateZ(PI). If rotateZ() is called within the draw(), the - * transformation is reset when the loop begins again. This function requires passing P3D or OPENGL - * into the size() parameter as shown in the example above. - * - * @param {int|float} angleInRadians angle of rotation specified in radians - * - * @returns none - * - * @see rotateX - * @see rotateY - * @see rotate - * @see translate - * @see scale - * @see popMatrix - * @see pushMatrix - */ - Drawing2D.prototype.rotateZ = function() { - throw "rotateZ() is not supported in 2D mode. Use rotate(float) instead."; - }; - - Drawing3D.prototype.rotateZ = function(angleInRadians) { - modelView.rotateZ(angleInRadians); - modelViewInv.invRotateZ(angleInRadians); - }; - - /** - * Rotates a shape around the y-axis the amount specified by the angle parameter. Angles should be - * specified in radians (values from 0 to PI*2) or converted to radians with the radians() function. - * Objects are always rotated around their relative position to the origin and positive numbers - * rotate objects in a counterclockwise direction. Transformations apply to everything that happens - * after and subsequent calls to the function accumulates the effect. For example, calling rotateY(PI/2) - * and then rotateY(PI/2) is the same as rotateY(PI). If rotateY() is called within the draw(), the - * transformation is reset when the loop begins again. This function requires passing P3D or OPENGL - * into the size() parameter as shown in the example above. - * - * @param {int|float} angleInRadians angle of rotation specified in radians - * - * @returns none - * - * @see rotateX - * @see rotateZ - * @see rotate - * @see translate - * @see scale - * @see popMatrix - * @see pushMatrix - */ - p.rotateY = function(angleInRadians) { - modelView.rotateY(angleInRadians); - modelViewInv.invRotateY(angleInRadians); - }; - - /** - * Rotates a shape the amount specified by the angle parameter. Angles should be specified in radians - * (values from 0 to TWO_PI) or converted to radians with the radians() function. Objects are always - * rotated around their relative position to the origin and positive numbers rotate objects in a - * clockwise direction. Transformations apply to everything that happens after and subsequent calls - * to the function accumulates the effect. For example, calling rotate(HALF_PI) and then rotate(HALF_PI) - * is the same as rotate(PI). All tranformations are reset when draw() begins again. Technically, - * rotate() multiplies the current transformation matrix by a rotation matrix. This function can be - * further controlled by the pushMatrix() and popMatrix(). - * - * @param {int|float} angleInRadians angle of rotation specified in radians - * - * @returns none - * - * @see rotateX - * @see rotateY - * @see rotateZ - * @see rotate - * @see translate - * @see scale - * @see popMatrix - * @see pushMatrix - */ - Drawing2D.prototype.rotate = function(angleInRadians) { - modelView.rotateZ(angleInRadians); - modelViewInv.invRotateZ(angleInRadians); - curContext.rotate(angleInRadians); - }; - - Drawing3D.prototype.rotate = function(angleInRadians) { - if (arguments.length < 4) { - p.rotateZ(angleInRadians); - } else { - modelView.rotate(angleInRadians, arguments[1], arguments[2], arguments[3]); - modelViewInv.rotate((-angleInRadians), arguments[1], arguments[2], arguments[3]); - } - }; - - /** - * Shears a shape around the x-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to radians - * with the radians() function. Objects are always sheared around their relative position - * to the origin and positive numbers shear objects in a clockwise direction. Transformations - * apply to everything that happens after and subsequent calls to the function accumulates the - * effect. For example, calling shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI) - * - * @param {int|float} angleInRadians angle of rotation specified in radians - * - * @returns none - * - * @see rotateX - * @see rotateY - * @see rotateZ - * @see rotate - * @see translate - * @see scale - * @see popMatrix - * @see pushMatrix - */ - - Drawing2D.prototype.shearX = function(angleInRadians) { - modelView.shearX(angleInRadians); - curContext.transform(1,0,angleInRadians,1,0,0); - }; - - Drawing3D.prototype.shearX = function(angleInRadians) { - modelView.shearX(angleInRadians); - }; - - /** - * Shears a shape around the y-axis the amount specified by the angle parameter. - * Angles should be specified in radians (values from 0 to PI*2) or converted to - * radians with the radians() function. Objects are always sheared around their - * relative position to the origin and positive numbers shear objects in a - * clockwise direction. Transformations apply to everything that happens after - * and subsequent calls to the function accumulates the effect. For example, - * calling shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). - * - * @param {int|float} angleInRadians angle of rotation specified in radians - * - * @returns none - * - * @see rotateX - * @see rotateY - * @see rotateZ - * @see rotate - * @see translate - * @see scale - * @see popMatrix - * @see pushMatrix - * @see shearX - */ - - Drawing2D.prototype.shearY = function(angleInRadians) { - modelView.shearY(angleInRadians); - curContext.transform(1,angleInRadians,0,1,0,0); - }; - - Drawing3D.prototype.shearY = function(angleInRadians) { - modelView.shearY(angleInRadians); - }; - - /** - * The pushStyle() function saves the current style settings and popStyle() restores the prior settings. - * Note that these functions are always used together. They allow you to change the style settings and later - * return to what you had. When a new style is started with pushStyle(), it builds on the current style information. - * The pushStyle() and popStyle() functions can be embedded to provide more control (see the second example - * above for a demonstration.) - * The style information controlled by the following functions are included in the style: fill(), stroke(), tint(), - * strokeWeight(), strokeCap(), strokeJoin(), imageMode(), rectMode(), ellipseMode(), shapeMode(), colorMode(), - * textAlign(), textFont(), textMode(), textSize(), textLeading(), emissive(), specular(), shininess(), ambient() - * - * @returns none - * - * @see popStyle - */ - p.pushStyle = function() { - // Save the canvas state. - saveContext(); - - p.pushMatrix(); - - var newState = { - 'doFill': doFill, - 'currentFillColor': currentFillColor, - 'doStroke': doStroke, - 'currentStrokeColor': currentStrokeColor, - 'curTint': curTint, - 'curRectMode': curRectMode, - 'curColorMode': curColorMode, - 'colorModeX': colorModeX, - 'colorModeZ': colorModeZ, - 'colorModeY': colorModeY, - 'colorModeA': colorModeA, - 'curTextFont': curTextFont, - 'horizontalTextAlignment': horizontalTextAlignment, - 'verticalTextAlignment': verticalTextAlignment, - 'textMode': textMode, - 'curFontName': curFontName, - 'curTextSize': curTextSize, - 'curTextAscent': curTextAscent, - 'curTextDescent': curTextDescent, - 'curTextLeading': curTextLeading - }; - - styleArray.push(newState); - }; - - /** - * The pushStyle() function saves the current style settings and popStyle() restores the prior settings; these - * functions are always used together. They allow you to change the style settings and later return to what you had. - * When a new style is started with pushStyle(), it builds on the current style information. The pushStyle() and - * popStyle() functions can be embedded to provide more control (see the second example above for a demonstration.) - * - * @returns none - * - * @see pushStyle - */ - p.popStyle = function() { - var oldState = styleArray.pop(); - - if (oldState) { - restoreContext(); - - p.popMatrix(); - - doFill = oldState.doFill; - currentFillColor = oldState.currentFillColor; - doStroke = oldState.doStroke; - currentStrokeColor = oldState.currentStrokeColor; - curTint = oldState.curTint; - curRectMode = oldState.curRectMode; - curColorMode = oldState.curColorMode; - colorModeX = oldState.colorModeX; - colorModeZ = oldState.colorModeZ; - colorModeY = oldState.colorModeY; - colorModeA = oldState.colorModeA; - curTextFont = oldState.curTextFont; - curFontName = oldState.curFontName; - curTextSize = oldState.curTextSize; - horizontalTextAlignment = oldState.horizontalTextAlignment; - verticalTextAlignment = oldState.verticalTextAlignment; - textMode = oldState.textMode; - curTextAscent = oldState.curTextAscent; - curTextDescent = oldState.curTextDescent; - curTextLeading = oldState.curTextLeading; - } else { - throw "Too many popStyle() without enough pushStyle()"; - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Time based functions - //////////////////////////////////////////////////////////////////////////// - - /** - * Processing communicates with the clock on your computer. - * The year() function returns the current year as an integer (2003, 2004, 2005, etc). - * - * @returns {float} The current year. - * - * @see millis - * @see second - * @see minute - * @see hour - * @see day - * @see month - */ - p.year = function() { - return new Date().getFullYear(); - }; - /** - * Processing communicates with the clock on your computer. - * The month() function returns the current month as a value from 1 - 12. - * - * @returns {float} The current month. - * - * @see millis - * @see second - * @see minute - * @see hour - * @see day - * @see year - */ - p.month = function() { - return new Date().getMonth() + 1; - }; - /** - * Processing communicates with the clock on your computer. - * The day() function returns the current day as a value from 1 - 31. - * - * @returns {float} The current day. - * - * @see millis - * @see second - * @see minute - * @see hour - * @see month - * @see year - */ - p.day = function() { - return new Date().getDate(); - }; - /** - * Processing communicates with the clock on your computer. - * The hour() function returns the current hour as a value from 0 - 23. - * - * @returns {float} The current hour. - * - * @see millis - * @see second - * @see minute - * @see month - * @see day - * @see year - */ - p.hour = function() { - return new Date().getHours(); - }; - /** - * Processing communicates with the clock on your computer. - * The minute() function returns the current minute as a value from 0 - 59. - * - * @returns {float} The current minute. - * - * @see millis - * @see second - * @see month - * @see hour - * @see day - * @see year - */ - p.minute = function() { - return new Date().getMinutes(); - }; - /** - * Processing communicates with the clock on your computer. - * The second() function returns the current second as a value from 0 - 59. - * - * @returns {float} The current minute. - * - * @see millis - * @see month - * @see minute - * @see hour - * @see day - * @see year - */ - p.second = function() { - return new Date().getSeconds(); - }; - /** - * Returns the number of milliseconds (thousandths of a second) since starting a sketch. - * This information is often used for timing animation sequences. - * - * @returns {long} The number of milliseconds since starting the sketch. - * - * @see month - * @see second - * @see minute - * @see hour - * @see day - * @see year - */ - p.millis = function() { - return Date.now() - start; - }; - - /** - * Executes the code within draw() one time. This functions allows the program to update - * the display window only when necessary, for example when an event registered by - * mousePressed() or keyPressed() occurs. - * In structuring a program, it only makes sense to call redraw() within events such as - * mousePressed(). This is because redraw() does not run draw() immediately (it only sets - * a flag that indicates an update is needed). - * Calling redraw() within draw() has no effect because draw() is continuously called anyway. - * - * @returns none - * - * @see noLoop - * @see loop - */ - function redrawHelper() { - var sec = (Date.now() - timeSinceLastFPS) / 1000; - framesSinceLastFPS++; - var fps = framesSinceLastFPS / sec; - - // recalculate FPS every half second for better accuracy. - if (sec > 0.5) { - timeSinceLastFPS = Date.now(); - framesSinceLastFPS = 0; - p.__frameRate = fps; - } - - p.frameCount++; - } - - Drawing2D.prototype.redraw = function() { - redrawHelper(); - - curContext.lineWidth = lineWidth; - var pmouseXLastEvent = p.pmouseX, - pmouseYLastEvent = p.pmouseY; - p.pmouseX = pmouseXLastFrame; - p.pmouseY = pmouseYLastFrame; - - saveContext(); - p.draw(); - restoreContext(); - - pmouseXLastFrame = p.mouseX; - pmouseYLastFrame = p.mouseY; - p.pmouseX = pmouseXLastEvent; - p.pmouseY = pmouseYLastEvent; - }; - - Drawing3D.prototype.redraw = function() { - redrawHelper(); - - var pmouseXLastEvent = p.pmouseX, - pmouseYLastEvent = p.pmouseY; - p.pmouseX = pmouseXLastFrame; - p.pmouseY = pmouseYLastFrame; - // even if the color buffer isn't cleared with background(), - // the depth buffer needs to be cleared regardless. - curContext.clear(curContext.DEPTH_BUFFER_BIT); - curContextCache = { attributes: {}, locations: {} }; - // Delete all the lighting states and the materials the - // user set in the last draw() call. - p.noLights(); - p.lightFalloff(1, 0, 0); - p.shininess(1); - p.ambient(255, 255, 255); - p.specular(0, 0, 0); - p.emissive(0, 0, 0); - p.camera(); - p.draw(); - - pmouseXLastFrame = p.mouseX; - pmouseYLastFrame = p.mouseY; - p.pmouseX = pmouseXLastEvent; - p.pmouseY = pmouseYLastEvent; - }; - - /** - * Stops Processing from continuously executing the code within draw(). If loop() is - * called, the code in draw() begin to run continuously again. If using noLoop() in - * setup(), it should be the last line inside the block. - * When noLoop() is used, it's not possible to manipulate or access the screen inside event - * handling functions such as mousePressed() or keyPressed(). Instead, use those functions - * to call redraw() or loop(), which will run draw(), which can update the screen properly. - * This means that when noLoop() has been called, no drawing can happen, and functions like - * saveFrame() or loadPixels() may not be used. - * Note that if the sketch is resized, redraw() will be called to update the sketch, even - * after noLoop() has been specified. Otherwise, the sketch would enter an odd state until - * loop() was called. - * - * @returns none - * - * @see redraw - * @see draw - * @see loop - */ - p.noLoop = function() { - doLoop = false; - loopStarted = false; - clearInterval(looping); - curSketch.onPause(); - }; - - /** - * Causes Processing to continuously execute the code within draw(). If noLoop() is called, - * the code in draw() stops executing. - * - * @returns none - * - * @see noLoop - */ - p.loop = function() { - if (loopStarted) { - return; - } - - timeSinceLastFPS = Date.now(); - framesSinceLastFPS = 0; - - looping = window.setInterval(function() { - try { - curSketch.onFrameStart(); - p.redraw(); - curSketch.onFrameEnd(); - } catch(e_loop) { - window.clearInterval(looping); - throw e_loop; - } - }, curMsPerFrame); - doLoop = true; - loopStarted = true; - curSketch.onLoop(); - }; - - /** - * Specifies the number of frames to be displayed every second. If the processor is not - * fast enough to maintain the specified rate, it will not be achieved. For example, the - * function call frameRate(30) will attempt to refresh 30 times a second. It is recommended - * to set the frame rate within setup(). The default rate is 60 frames per second. - * - * @param {int} aRate number of frames per second. - * - * @returns none - * - * @see delay - */ - p.frameRate = function(aRate) { - curFrameRate = aRate; - curMsPerFrame = 1000 / curFrameRate; - - // clear and reset interval - if (doLoop) { - p.noLoop(); - p.loop(); - } - }; - - /** - * Quits/stops/exits the program. - * Rather than terminating immediately, exit() will cause the sketch to exit after draw() - * has completed (or after setup() completes if called during the setup() method). - * - * @returns none - */ - p.exit = function() { - // cleanup - window.clearInterval(looping); - removeInstance(p.externals.canvas.id); - delete(curElement.onmousedown); - - // Step through the libraries to detach them - for (var lib in Processing.lib) { - if (Processing.lib.hasOwnProperty(lib)) { - if (Processing.lib[lib].hasOwnProperty("detach")) { - Processing.lib[lib].detach(p); - } - } - } - - // clean up all event handling - var i = eventHandlers.length; - while (i--) { - detachEventHandler(eventHandlers[i]); - } - curSketch.onExit(); - }; - - //////////////////////////////////////////////////////////////////////////// - // MISC functions - //////////////////////////////////////////////////////////////////////////// - - /** - * Sets the cursor to a predefined symbol, an image, or turns it on if already hidden. - * If you are trying to set an image as the cursor, it is recommended to make the size - * 16x16 or 32x32 pixels. It is not possible to load an image as the cursor if you are - * exporting your program for the Web. The values for parameters x and y must be less - * than the dimensions of the image. - * - * @param {MODE} MODE either ARROW, CROSS, HAND, MOVE, TEXT, WAIT - * @param {PImage} image any variable of type PImage - * @param {int} x the horizonal active spot of the cursor - * @param {int} y the vertical active spot of the cursor - * - * @returns none - * - * @see noCursor - */ - p.cursor = function() { - if (arguments.length > 1 || (arguments.length === 1 && arguments[0] instanceof p.PImage)) { - var image = arguments[0], - x, y; - if (arguments.length >= 3) { - x = arguments[1]; - y = arguments[2]; - if (x < 0 || y < 0 || y >= image.height || x >= image.width) { - throw "x and y must be non-negative and less than the dimensions of the image"; - } - } else { - x = image.width >>> 1; - y = image.height >>> 1; - } - - // see https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property - var imageDataURL = image.toDataURL(); - var style = "url(\"" + imageDataURL + "\") " + x + " " + y + ", default"; - curCursor = curElement.style.cursor = style; - } else if (arguments.length === 1) { - var mode = arguments[0]; - curCursor = curElement.style.cursor = mode; - } else { - curCursor = curElement.style.cursor = oldCursor; - } - }; - - /** - * Hides the cursor from view. - * - * @returns none - * - * @see cursor - */ - p.noCursor = function() { - curCursor = curElement.style.cursor = PConstants.NOCURSOR; - }; - - /** - * Links to a webpage either in the same window or in a new window. The complete URL - * must be specified. - * - * @param {String} href complete url as a String in quotes - * @param {String} target name of the window to load the URL as a string in quotes - * - * @returns none - */ - p.link = function(href, target) { - if (target !== undef) { - window.open(href, target); - } else { - window.location = href; - } - }; - - // PGraphics methods - // These functions exist only for compatibility with P5 - p.beginDraw = noop; - p.endDraw = noop; - - /** - * This function takes content from a canvas and turns it into an ImageData object to be used with a PImage - * - * @returns {ImageData} ImageData object to attach to a PImage (1D array of pixel data) - * - * @see PImage - */ - Drawing2D.prototype.toImageData = function(x, y, w, h) { - x = x !== undef ? x : 0; - y = y !== undef ? y : 0; - w = w !== undef ? w : p.width; - h = h !== undef ? h : p.height; - return curContext.getImageData(x, y, w, h); - }; - - Drawing3D.prototype.toImageData = function(x, y, w, h) { - x = x !== undef ? x : 0; - y = y !== undef ? y : 0; - w = w !== undef ? w : p.width; - h = h !== undef ? h : p.height; - var c = document.createElement("canvas"), - ctx = c.getContext("2d"), - obj = ctx.createImageData(w, h), - uBuff = new Uint8Array(w * h * 4); - curContext.readPixels(x, y, w, h, curContext.RGBA, curContext.UNSIGNED_BYTE, uBuff); - for (var i=0, ul=uBuff.length, obj_data=obj.data; i < ul; i++) { - obj_data[i] = uBuff[(h - 1 - Math.floor(i / 4 / w)) * w * 4 + (i % (w * 4))]; - } - return obj; - }; - - /** - * Displays message in the browser's status area. This is the text area in the lower - * left corner of the browser. The status() function will only work when the - * Processing program is running in a web browser. - * - * @param {String} text any valid String - * - * @returns none - */ - p.status = function(text) { - window.status = text; - }; - - //////////////////////////////////////////////////////////////////////////// - // Binary Functions - //////////////////////////////////////////////////////////////////////////// - - /** - * Converts a byte, char, int, or color to a String containing the equivalent binary - * notation. For example color(0, 102, 153, 255) will convert to the String - * "11111111000000000110011010011001". This function can help make your geeky debugging - * sessions much happier. - * - * @param {byte|char|int|color} num byte, char, int, color: value to convert - * @param {int} numBits number of digits to return - * - * @returns {String} - * - * @see unhex - * @see hex - * @see unbinary - */ - p.binary = function(num, numBits) { - var bit; - if (numBits > 0) { - bit = numBits; - } else if(num instanceof Char) { - bit = 16; - num |= 0; // making it int - } else { - // autodetect, skipping zeros - bit = 32; - while (bit > 1 && !((num >>> (bit - 1)) & 1)) { - bit--; - } - } - var result = ""; - while (bit > 0) { - result += ((num >>> (--bit)) & 1) ? "1" : "0"; - } - return result; - }; - - /** - * Converts a String representation of a binary number to its equivalent integer value. - * For example, unbinary("00001000") will return 8. - * - * @param {String} binaryString String - * - * @returns {Int} - * - * @see hex - * @see binary - * @see unbinary - */ - p.unbinary = function(binaryString) { - var i = binaryString.length - 1, mask = 1, result = 0; - while (i >= 0) { - var ch = binaryString[i--]; - if (ch !== '0' && ch !== '1') { - throw "the value passed into unbinary was not an 8 bit binary number"; - } - if (ch === '1') { - result += mask; - } - mask <<= 1; - } - return result; - }; - - var decimalToHex = function(d, padding) { - //if there is no padding value added, default padding to 8 else go into while statement. - padding = (padding === undef || padding === null) ? padding = 8 : padding; - if (d < 0) { - d = 0xFFFFFFFF + d + 1; - } - var hex = Number(d).toString(16).toUpperCase(); - while (hex.length < padding) { - hex = "0" + hex; - } - if (hex.length >= padding) { - hex = hex.substring(hex.length - padding, hex.length); - } - return hex; - }; - - // note: since we cannot keep track of byte, int types by default the returned string is 8 chars long - // if no 2nd argument is passed. closest compromise we can use to match java implementation Feb 5 2010 - // also the char parser has issues with chars that are not digits or letters IE: !@#$%^&* - /** - * Converts a byte, char, int, or color to a String containing the equivalent hexadecimal notation. - * For example color(0, 102, 153, 255) will convert to the String "FF006699". This function can help - * make your geeky debugging sessions much happier. - * - * @param {byte|char|int|Color} value the value to turn into a hex string - * @param {int} digits the number of digits to return - * - * @returns {String} - * - * @see unhex - * @see binary - * @see unbinary - */ - p.hex = function(value, len) { - if (arguments.length === 1) { - if (value instanceof Char) { - len = 4; - } else { // int or byte, indistinguishable at the moment, default to 8 - len = 8; - } - } - return decimalToHex(value, len); - }; - - function unhexScalar(hex) { - var value = parseInt("0x" + hex, 16); - - // correct for int overflow java expectation - if (value > 2147483647) { - value -= 4294967296; - } - return value; - } - - /** - * Converts a String representation of a hexadecimal number to its equivalent integer value. - * - * @param {String} hex the hex string to convert to an int - * - * @returns {int} - * - * @see hex - * @see binary - * @see unbinary - */ - p.unhex = function(hex) { - if (hex instanceof Array) { - var arr = []; - for (var i = 0; i < hex.length; i++) { - arr.push(unhexScalar(hex[i])); - } - return arr; - } - return unhexScalar(hex); - }; - - // Load a file or URL into strings - /** - * Reads the contents of a file or url and creates a String array of its individual lines. - * The filename parameter can also be a URL to a file found online. If the file is not available or an error occurs, - * null will be returned and an error message will be printed to the console. The error message does not halt - * the program. - * - * @param {String} filename name of the file or url to load - * - * @returns {String[]} - * - * @see loadBytes - * @see saveStrings - * @see saveBytes - */ - p.loadStrings = function(filename) { - if (localStorage[filename]) { - return localStorage[filename].split("\n"); - } - - var filecontent = ajax(filename); - if(typeof filecontent !== "string" || filecontent === "") { - return []; - } - - // deal with the fact that Windows uses \r\n, Unix uses \n, - // Mac uses \r, and we actually expect \n - filecontent = filecontent.replace(/(\r\n?)/g,"\n").replace(/\n$/,""); - - return filecontent.split("\n"); - }; - - // Writes an array of strings to a file, one line per string - /** - * Writes an array of strings to a file, one line per string. This file is saved to the localStorage. - * - * @param {String} filename name of the file to save to localStorage - * @param {String[]} strings string array to be written - * - * @see loadBytes - * @see loadStrings - * @see saveBytes - */ - p.saveStrings = function(filename, strings) { - localStorage[filename] = strings.join('\n'); - }; - - /** - * Reads the contents of a file or url and places it in a byte array. If a file is specified, it must be located in the localStorage. - * The filename parameter can also be a URL to a file found online. - * - * @param {String} filename name of a file in the localStorage or a URL. - * - * @returns {byte[]} - * - * @see loadStrings - * @see saveStrings - * @see saveBytes - */ - p.loadBytes = function(url) { - var string = ajax(url); - var ret = []; - - for (var i = 0; i < string.length; i++) { - ret.push(string.charCodeAt(i)); - } - - return ret; - }; - - //////////////////////////////////////////////////////////////////////////// - // String Functions - //////////////////////////////////////////////////////////////////////////// - /** - * The matchAll() function is identical to match(), except that it returns an array of all matches in - * the specified String, rather than just the first. - * - * @param {String} aString the String to search inside - * @param {String} aRegExp the regexp to be used for matching - * - * @return {String[]} returns an array of matches - * - * @see #match - */ - p.matchAll = function(aString, aRegExp) { - var results = [], - latest; - var regexp = new RegExp(aRegExp, "g"); - while ((latest = regexp.exec(aString)) !== null) { - results.push(latest); - if (latest[0].length === 0) { - ++regexp.lastIndex; - } - } - return results.length > 0 ? results : null; - }; - /** - * The match() function matches a string with a regular expression, and returns the match as an - * array. The first index is the matching expression, and array elements - * [1] and higher represent each of the groups (sequences found in parens). - * - * @param {String} str the String to be searched - * @param {String} regexp the regexp to be used for matching - * - * @return {String[]} an array of matching strings - */ - p.match = function(str, regexp) { - return str.match(regexp); - }; - - //////////////////////////////////////////////////////////////////////////// - // Other java specific functions - //////////////////////////////////////////////////////////////////////////// - - - var logBuffer = []; - - /** - * The println() function writes to the console area of the Processing environment. - * Each call to this function creates a new line of output. Individual elements can be separated with quotes ("") and joined with the string concatenation operator (+). - * - * @param {String} message the string to write to the console - * - * @see #join - * @see #print - */ - p.println = function() { - Processing.logger.println.apply(Processing.logger, arguments); - }; - /** - * The print() function writes to the console area of the Processing environment. - * - * @param {String} message the string to write to the console - * - * @see #join - */ - p.print = function() { - Processing.logger.print.apply(Processing.logger, arguments); - }; - - // Alphanumeric chars arguments automatically converted to numbers when - // passed in, and will come out as numbers. - p.str = function(val) { - if (val instanceof Array) { - var arr = []; - for (var i = 0; i < val.length; i++) { - arr.push(val[i].toString() + ""); - } - return arr; - } - return (val.toString() + ""); - }; - - - // Conversion - function booleanScalar(val) { - if (typeof val === 'number') { - return val !== 0; - } - if (typeof val === 'boolean') { - return val; - } - if (typeof val === 'string') { - return val.toLowerCase() === 'true'; - } - if (val instanceof Char) { - // 1, T or t - return val.code === 49 || val.code === 84 || val.code === 116; - } - } - - /** - * Converts the passed parameter to the function to its boolean value. - * It will return an array of booleans if an array is passed in. - * - * @param {int, byte, string} val the parameter to be converted to boolean - * @param {int[], byte[], string[]} val the array to be converted to boolean[] - * - * @return {boolean|boolean[]} returns a boolean or an array of booleans - */ - p.parseBoolean = function (val) { - if (val instanceof Array) { - var ret = []; - for (var i = 0; i < val.length; i++) { - ret.push(booleanScalar(val[i])); - } - return ret; - } - return booleanScalar(val); - }; - - /** - * Converts the passed parameter to the function to its byte value. - * A byte is a number between -128 and 127. - * It will return an array of bytes if an array is passed in. - * - * @param {int, char} what the parameter to be conveted to byte - * @param {int[], char[]} what the array to be converted to byte[] - * - * @return {byte|byte[]} returns a byte or an array of bytes - */ - p.parseByte = function(what) { - if (what instanceof Array) { - var bytes = []; - for (var i = 0; i < what.length; i++) { - bytes.push((0 - (what[i] & 0x80)) | (what[i] & 0x7F)); - } - return bytes; - } - return (0 - (what & 0x80)) | (what & 0x7F); - }; - - /** - * Converts the passed parameter to the function to its char value. - * It will return an array of chars if an array is passed in. - * - * @param {int, byte} key the parameter to be conveted to char - * @param {int[], byte[]} key the array to be converted to char[] - * - * @return {char|char[]} returns a char or an array of chars - */ - p.parseChar = function(key) { - if (typeof key === "number") { - return new Char(String.fromCharCode(key & 0xFFFF)); - } - if (key instanceof Array) { - var ret = []; - for (var i = 0; i < key.length; i++) { - ret.push(new Char(String.fromCharCode(key[i] & 0xFFFF))); - } - return ret; - } - throw "char() may receive only one argument of type int, byte, int[], or byte[]."; - }; - - // Processing doc claims good argument types are: int, char, byte, boolean, - // String, int[], char[], byte[], boolean[], String[]. - // floats should not work. However, floats with only zeroes right of the - // decimal will work because JS converts those to int. - function floatScalar(val) { - if (typeof val === 'number') { - return val; - } - if (typeof val === 'boolean') { - return val ? 1 : 0; - } - if (typeof val === 'string') { - return parseFloat(val); - } - if (val instanceof Char) { - return val.code; - } - } - - /** - * Converts the passed parameter to the function to its float value. - * It will return an array of floats if an array is passed in. - * - * @param {int, char, boolean, string} val the parameter to be conveted to float - * @param {int[], char[], boolean[], string[]} val the array to be converted to float[] - * - * @return {float|float[]} returns a float or an array of floats - */ - p.parseFloat = function(val) { - if (val instanceof Array) { - var ret = []; - for (var i = 0; i < val.length; i++) { - ret.push(floatScalar(val[i])); - } - return ret; - } - return floatScalar(val); - }; - - function intScalar(val, radix) { - if (typeof val === 'number') { - return val & 0xFFFFFFFF; - } - if (typeof val === 'boolean') { - return val ? 1 : 0; - } - if (typeof val === 'string') { - var number = parseInt(val, radix || 10); // Default to decimal radix. - return number & 0xFFFFFFFF; - } - if (val instanceof Char) { - return val.code; - } - } - - /** - * Converts the passed parameter to the function to its int value. - * It will return an array of ints if an array is passed in. - * - * @param {string, char, boolean, float} val the parameter to be conveted to int - * @param {string[], char[], boolean[], float[]} val the array to be converted to int[] - * @param {int} radix optional the radix of the number (for js compatibility) - * - * @return {int|int[]} returns a int or an array of ints - */ - p.parseInt = function(val, radix) { - if (val instanceof Array) { - var ret = []; - for (var i = 0; i < val.length; i++) { - if (typeof val[i] === 'string' && !/^\s*[+\-]?\d+\s*$/.test(val[i])) { - ret.push(0); - } else { - ret.push(intScalar(val[i], radix)); - } - } - return ret; - } - return intScalar(val, radix); - }; - - p.__int_cast = function(val) { - return 0|val; - }; - - p.__instanceof = function(obj, type) { - if (typeof type !== "function") { - throw "Function is expected as type argument for instanceof operator"; - } - - if (typeof obj === "string") { - // special case for strings - return type === Object || type === String; - } - - if (obj instanceof type) { - // fast check if obj is already of type instance - return true; - } - - if (typeof obj !== "object" || obj === null) { - return false; // not an object or null - } - - var objType = obj.constructor; - if (type.$isInterface) { - // expecting the interface - // queueing interfaces from type and its base classes - var interfaces = []; - while (objType) { - if (objType.$interfaces) { - interfaces = interfaces.concat(objType.$interfaces); - } - objType = objType.$base; - } - while (interfaces.length > 0) { - var i = interfaces.shift(); - if (i === type) { - return true; - } - // wide search in base interfaces - if (i.$interfaces) { - interfaces = interfaces.concat(i.$interfaces); - } - } - return false; - } - - while (objType.hasOwnProperty("$base")) { - objType = objType.$base; - if (objType === type) { - return true; // object was found - } - } - - return false; - }; - - /** - * Defines the dimension of the display window in units of pixels. The size() function must - * be the first line in setup(). If size() is not called, the default size of the window is - * 100x100 pixels. The system variables width and height are set by the parameters passed to - * the size() function. - * - * @param {int} aWidth width of the display window in units of pixels - * @param {int} aHeight height of the display window in units of pixels - * @param {MODE} aMode Either P2D, P3D, JAVA2D, or OPENGL - * - * @see createGraphics - * @see screen - */ - DrawingShared.prototype.size = function(aWidth, aHeight, aMode) { - if (doStroke) { - p.stroke(0); - } - - if (doFill) { - p.fill(255); - } - - // The default 2d context has already been created in the p.init() stage if - // a 3d context was not specified. This is so that a 2d context will be - // available if size() was not called. - var savedProperties = { - fillStyle: curContext.fillStyle, - strokeStyle: curContext.strokeStyle, - lineCap: curContext.lineCap, - lineJoin: curContext.lineJoin - }; - // remove the style width and height properties to ensure that the canvas gets set to - // aWidth and aHeight coming in - if (curElement.style.length > 0 ) { - curElement.style.removeProperty("width"); - curElement.style.removeProperty("height"); - } - - curElement.width = p.width = aWidth || 100; - curElement.height = p.height = aHeight || 100; - - for (var prop in savedProperties) { - if (savedProperties.hasOwnProperty(prop)) { - curContext[prop] = savedProperties[prop]; - } - } - - // make sure to set the default font the first time round. - p.textFont(curTextFont); - - // Set the background to whatever it was called last as if background() was called before size() - // If background() hasn't been called before, set background() to a light gray - p.background(); - - // set 5% for pixels to cache (or 1000) - maxPixelsCached = Math.max(1000, aWidth * aHeight * 0.05); - - // Externalize the context - p.externals.context = curContext; - - for (var i = 0; i < PConstants.SINCOS_LENGTH; i++) { - sinLUT[i] = p.sin(i * (PConstants.PI / 180) * 0.5); - cosLUT[i] = p.cos(i * (PConstants.PI / 180) * 0.5); - } - }; - - Drawing2D.prototype.size = function(aWidth, aHeight, aMode) { - if (curContext === undef) { - // size() was called without p.init() default context, i.e. p.createGraphics() - curContext = curElement.getContext("2d"); - userMatrixStack = new PMatrixStack(); - userReverseMatrixStack = new PMatrixStack(); - modelView = new PMatrix2D(); - modelViewInv = new PMatrix2D(); - } - - DrawingShared.prototype.size.apply(this, arguments); - }; - - Drawing3D.prototype.size = (function() { - var size3DCalled = false; - - return function size(aWidth, aHeight, aMode) { - if (size3DCalled) { - throw "Multiple calls to size() for 3D renders are not allowed."; - } - size3DCalled = true; - - function getGLContext(canvas) { - var ctxNames = ['experimental-webgl', 'webgl', 'webkit-3d'], - gl; - - for (var i=0, l=ctxNames.length; i<l; i++) { - gl = canvas.getContext(ctxNames[i], {antialias: false, preserveDrawingBuffer: true}); - if (gl) { - break; - } - } - - return gl; - } - - // Get the 3D rendering context. - try { - // If the HTML <canvas> dimensions differ from the - // dimensions specified in the size() call in the sketch, for - // 3D sketches, browsers will either not render or render the - // scene incorrectly. To fix this, we need to adjust the - // width and height attributes of the canvas. - curElement.width = p.width = aWidth || 100; - curElement.height = p.height = aHeight || 100; - curContext = getGLContext(curElement); - canTex = curContext.createTexture(); - textTex = curContext.createTexture(); - } catch(e_size) { - Processing.debug(e_size); - } - - if (!curContext) { - throw "WebGL context is not supported on this browser."; - } - - // Set defaults - curContext.viewport(0, 0, curElement.width, curElement.height); - curContext.enable(curContext.DEPTH_TEST); - curContext.enable(curContext.BLEND); - curContext.blendFunc(curContext.SRC_ALPHA, curContext.ONE_MINUS_SRC_ALPHA); - - // Create the program objects to render 2D (points, lines) and - // 3D (spheres, boxes) shapes. Because 2D shapes are not lit, - // lighting calculations are ommitted from this program object. - programObject2D = createProgramObject(curContext, vertexShaderSrc2D, fragmentShaderSrc2D); - - programObjectUnlitShape = createProgramObject(curContext, vertexShaderSrcUnlitShape, fragmentShaderSrcUnlitShape); - - // Set the default point and line width for the 2D and unlit shapes. - p.strokeWeight(1); - - // Now that the programs have been compiled, we can set the default - // states for the lights. - programObject3D = createProgramObject(curContext, vertexShaderSrc3D, fragmentShaderSrc3D); - curContext.useProgram(programObject3D); - - // Assume we aren't using textures by default. - uniformi("usingTexture3d", programObject3D, "usingTexture", usingTexture); - - // Set some defaults. - p.lightFalloff(1, 0, 0); - p.shininess(1); - p.ambient(255, 255, 255); - p.specular(0, 0, 0); - p.emissive(0, 0, 0); - - // Create buffers for 3D primitives - boxBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, boxBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, boxVerts, curContext.STATIC_DRAW); - - boxNormBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, boxNormBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, boxNorms, curContext.STATIC_DRAW); - - boxOutlineBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, boxOutlineBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, boxOutlineVerts, curContext.STATIC_DRAW); - - // used to draw the rectangle and the outline - rectBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, rectBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, rectVerts, curContext.STATIC_DRAW); - - rectNormBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, rectNormBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, rectNorms, curContext.STATIC_DRAW); - - // The sphere vertices are specified dynamically since the user - // can change the level of detail. Everytime the user does that - // using sphereDetail(), the new vertices are calculated. - sphereBuffer = curContext.createBuffer(); - - lineBuffer = curContext.createBuffer(); - - // Shape buffers - fillBuffer = curContext.createBuffer(); - fillColorBuffer = curContext.createBuffer(); - strokeColorBuffer = curContext.createBuffer(); - shapeTexVBO = curContext.createBuffer(); - - pointBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, pointBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 0]), curContext.STATIC_DRAW); - - textBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, textBuffer ); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([1,1,0,-1,1,0,-1,-1,0,1,-1,0]), curContext.STATIC_DRAW); - - textureBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, textureBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0,0,1,0,1,1,0,1]), curContext.STATIC_DRAW); - - indexBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); - curContext.bufferData(curContext.ELEMENT_ARRAY_BUFFER, new Uint16Array([0,1,2,2,3,0]), curContext.STATIC_DRAW); - - cam = new PMatrix3D(); - cameraInv = new PMatrix3D(); - modelView = new PMatrix3D(); - modelViewInv = new PMatrix3D(); - projection = new PMatrix3D(); - p.camera(); - p.perspective(); - - userMatrixStack = new PMatrixStack(); - userReverseMatrixStack = new PMatrixStack(); - // used by both curve and bezier, so just init here - curveBasisMatrix = new PMatrix3D(); - curveToBezierMatrix = new PMatrix3D(); - curveDrawMatrix = new PMatrix3D(); - bezierDrawMatrix = new PMatrix3D(); - bezierBasisInverse = new PMatrix3D(); - bezierBasisMatrix = new PMatrix3D(); - bezierBasisMatrix.set(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0); - - DrawingShared.prototype.size.apply(this, arguments); - }; - }()); - - //////////////////////////////////////////////////////////////////////////// - // Lights - //////////////////////////////////////////////////////////////////////////// - - /** - * Adds an ambient light. Ambient light doesn't come from a specific direction, - * the rays have light have bounced around so much that objects are evenly lit - * from all sides. Ambient lights are almost always used in combination with - * other types of lights. Lights need to be included in the <b>draw()</b> to - * remain persistent in a looping program. Placing them in the <b>setup()</b> - * of a looping program will cause them to only have an effect the first time - * through the loop. The effect of the parameters is determined by the current - * color mode. - * - * @param {int | float} r red or hue value - * @param {int | float} g green or hue value - * @param {int | float} b blue or hue value - * - * @param {int | float} x x position of light (used for falloff) - * @param {int | float} y y position of light (used for falloff) - * @param {int | float} z z position of light (used for falloff) - * - * @returns none - * - * @see lights - * @see directionalLight - * @see pointLight - * @see spotLight - */ - Drawing2D.prototype.ambientLight = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.ambientLight = function(r, g, b, x, y, z) { - if (lightCount === PConstants.MAX_LIGHTS) { - throw "can only create " + PConstants.MAX_LIGHTS + " lights"; - } - - var pos = new PVector(x, y, z); - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.mult(pos, pos); - - // Instead of calling p.color, we do the calculations ourselves to - // reduce property lookups. - var col = color$4(r, g, b, 0); - var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255, - ((col & PConstants.GREEN_MASK) >>> 8) / 255, - (col & PConstants.BLUE_MASK) / 255 ]; - - curContext.useProgram(programObject3D); - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 0); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount); - }; - - /** - * Adds a directional light. Directional light comes from one direction and - * is stronger when hitting a surface squarely and weaker if it hits at a - * gentle angle. After hitting a surface, a directional lights scatters in - * all directions. Lights need to be included in the <b>draw()</b> to remain - * persistent in a looping program. Placing them in the <b>setup()</b> of a - * looping program will cause them to only have an effect the first time - * through the loop. The affect of the <br>r</b>, <br>g</b>, and <br>b</b> - * parameters is determined by the current color mode. The <b>nx</b>, - * <b>ny</b>, and <b>nz</b> parameters specify the direction the light is - * facing. For example, setting <b>ny</b> to -1 will cause the geometry to be - * lit from below (the light is facing directly upward). - * - * @param {int | float} r red or hue value - * @param {int | float} g green or hue value - * @param {int | float} b blue or hue value - * - * @param {int | float} nx direction along the x axis - * @param {int | float} ny direction along the y axis - * @param {int | float} nz direction along the z axis - * - * @returns none - * - * @see lights - * @see ambientLight - * @see pointLight - * @see spotLight - */ - Drawing2D.prototype.directionalLight = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.directionalLight = function(r, g, b, nx, ny, nz) { - if (lightCount === PConstants.MAX_LIGHTS) { - throw "can only create " + PConstants.MAX_LIGHTS + " lights"; - } - - curContext.useProgram(programObject3D); - - var mvm = new PMatrix3D(); - mvm.scale(1, -1, 1); - mvm.apply(modelView.array()); - mvm = mvm.array(); - - // We need to multiply the direction by the model view matrix, but - // the mult function checks the w component of the vector, if it isn't - // present, it uses 1, so we manually multiply. - var dir = [ - mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, - mvm[1] * nx + mvm[5] * ny + mvm[9] * nz, - mvm[2] * nx + mvm[6] * ny + mvm[10] * nz - ]; - - // Instead of calling p.color, we do the calculations ourselves to - // reduce property lookups. - var col = color$4(r, g, b, 0); - var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255, - ((col & PConstants.GREEN_MASK) >>> 8) / 255, - (col & PConstants.BLUE_MASK) / 255 ]; - - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", dir); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 1); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount); - }; - - /** - * Sets the falloff rates for point lights, spot lights, and ambient lights. - * The parameters are used to determine the falloff with the following equation: - * - * d = distance from light position to vertex position - * falloff = 1 / (CONSTANT + d * LINEAR + (d*d) * QUADRATIC) - * - * Like <b>fill()</b>, it affects only the elements which are created after it in the - * code. The default value if <b>LightFalloff(1.0, 0.0, 0.0)</b>. Thinking about an - * ambient light with a falloff can be tricky. It is used, for example, if you - * wanted a region of your scene to be lit ambiently one color and another region - * to be lit ambiently by another color, you would use an ambient light with location - * and falloff. You can think of it as a point light that doesn't care which direction - * a surface is facing. - * - * @param {int | float} constant constant value for determining falloff - * @param {int | float} linear linear value for determining falloff - * @param {int | float} quadratic quadratic value for determining falloff - * - * @returns none - * - * @see lights - * @see ambientLight - * @see pointLight - * @see spotLight - * @see lightSpecular - */ - Drawing2D.prototype.lightFalloff = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.lightFalloff = function(constant, linear, quadratic) { - curContext.useProgram(programObject3D); - uniformf("uFalloff3d", programObject3D, "uFalloff", [constant, linear, quadratic]); - }; - - /** - * Sets the specular color for lights. Like <b>fill()</b>, it affects only the - * elements which are created after it in the code. Specular refers to light - * which bounces off a surface in a perferred direction (rather than bouncing - * in all directions like a diffuse light) and is used for creating highlights. - * The specular quality of a light interacts with the specular material qualities - * set through the <b>specular()</b> and <b>shininess()</b> functions. - * - * @param {int | float} r red or hue value - * @param {int | float} g green or hue value - * @param {int | float} b blue or hue value - * - * @returns none - * - * @see lights - * @see ambientLight - * @see pointLight - * @see spotLight - */ - Drawing2D.prototype.lightSpecular = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.lightSpecular = function(r, g, b) { - - // Instead of calling p.color, we do the calculations ourselves to - // reduce property lookups. - var col = color$4(r, g, b, 0); - var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255, - ((col & PConstants.GREEN_MASK) >>> 8) / 255, - (col & PConstants.BLUE_MASK) / 255 ]; - - curContext.useProgram(programObject3D); - uniformf("uSpecular3d", programObject3D, "uSpecular", normalizedCol); - }; - - /** - * Sets the default ambient light, directional light, falloff, and specular - * values. The defaults are ambientLight(128, 128, 128) and - * directionalLight(128, 128, 128, 0, 0, -1), lightFalloff(1, 0, 0), and - * lightSpecular(0, 0, 0). Lights need to be included in the draw() to remain - * persistent in a looping program. Placing them in the setup() of a looping - * program will cause them to only have an effect the first time through the - * loop. - * - * @returns none - * - * @see ambientLight - * @see directionalLight - * @see pointLight - * @see spotLight - * @see noLights - * - */ - p.lights = function() { - p.ambientLight(128, 128, 128); - p.directionalLight(128, 128, 128, 0, 0, -1); - p.lightFalloff(1, 0, 0); - p.lightSpecular(0, 0, 0); - }; - - /** - * Adds a point light. Lights need to be included in the <b>draw()</b> to remain - * persistent in a looping program. Placing them in the <b>setup()</b> of a - * looping program will cause them to only have an effect the first time through - * the loop. The affect of the <b>r</b>, <b>g</b>, and <b>b</b> parameters - * is determined by the current color mode. The <b>x</b>, <b>y</b>, and <b>z</b> - * parameters set the position of the light. - * - * @param {int | float} r red or hue value - * @param {int | float} g green or hue value - * @param {int | float} b blue or hue value - * @param {int | float} x x coordinate of the light - * @param {int | float} y y coordinate of the light - * @param {int | float} z z coordinate of the light - * - * @returns none - * - * @see lights - * @see directionalLight - * @see ambientLight - * @see spotLight - */ - Drawing2D.prototype.pointLight = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.pointLight = function(r, g, b, x, y, z) { - if (lightCount === PConstants.MAX_LIGHTS) { - throw "can only create " + PConstants.MAX_LIGHTS + " lights"; - } - - // Place the point in view space once instead of once per vertex - // in the shader. - var pos = new PVector(x, y, z); - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.mult(pos, pos); - - // Instead of calling p.color, we do the calculations ourselves to - // reduce property lookups. - var col = color$4(r, g, b, 0); - var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255, - ((col & PConstants.GREEN_MASK) >>> 8) / 255, - (col & PConstants.BLUE_MASK) / 255 ]; - - curContext.useProgram(programObject3D); - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 2); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount); - }; - - /** - * Disable all lighting. Lighting is turned off by default and enabled with - * the lights() method. This function can be used to disable lighting so - * that 2D geometry (which does not require lighting) can be drawn after a - * set of lighted 3D geometry. - * - * @returns none - * - * @see lights - */ - Drawing2D.prototype.noLights = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.noLights = function() { - lightCount = 0; - curContext.useProgram(programObject3D); - uniformi("uLightCount3d", programObject3D, "uLightCount", lightCount); - }; - - /** - * Adds a spot light. Lights need to be included in the <b>draw()</b> to - * remain persistent in a looping program. Placing them in the <b>setup()</b> - * of a looping program will cause them to only have an effect the first time - * through the loop. The affect of the <b>r</b>, <b>g</b>, and <b>b</b> parameters - * is determined by the current color mode. The <b>x</b>, <b>y</b>, and <b>z</b> - * parameters specify the position of the light and <b>nx</b>, <b>ny</b>, <b>nz</b> - * specify the direction or light. The angle parameter affects <b>angle</b> of the - * spotlight cone. - * - * @param {int | float} r red or hue value - * @param {int | float} g green or hue value - * @param {int | float} b blue or hue value - * @param {int | float} x coordinate of the light - * @param {int | float} y coordinate of the light - * @param {int | float} z coordinate of the light - * @param {int | float} nx direction along the x axis - * @param {int | float} ny direction along the y axis - * @param {int | float} nz direction along the z axis - * @param {float} angle angle of the spotlight cone - * @param {float} concentration exponent determining the center bias of the cone - * - * @returns none - * - * @see lights - * @see directionalLight - * @see ambientLight - * @see pointLight - */ - Drawing2D.prototype.spotLight = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.spotLight = function(r, g, b, x, y, z, nx, ny, nz, angle, concentration) { - if (lightCount === PConstants.MAX_LIGHTS) { - throw "can only create " + PConstants.MAX_LIGHTS + " lights"; - } - - curContext.useProgram(programObject3D); - - // multiply the position and direction by the model view matrix - // once per object rather than once per vertex. - var pos = new PVector(x, y, z); - var mvm = new PMatrix3D(); - mvm.scale(1, -1, 1); - mvm.apply(modelView.array()); - mvm.mult(pos, pos); - - // Convert to array since we need to directly access the elements. - mvm = mvm.array(); - - // We need to multiply the direction by the model view matrix, but - // the mult function checks the w component of the vector, if it isn't - // present, it uses 1, so we use a very small value as a work around. - var dir = [ - mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, - mvm[1] * nx + mvm[5] * ny + mvm[9] * nz, - mvm[2] * nx + mvm[6] * ny + mvm[10] * nz - ]; - - // Instead of calling p.color, we do the calculations ourselves to - // reduce property lookups. - var col = color$4(r, g, b, 0); - var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255, - ((col & PConstants.GREEN_MASK) >>> 8) / 255, - (col & PConstants.BLUE_MASK) / 255 ]; - - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); - uniformf("uLights.direction.3d." + lightCount, programObject3D, "uLights" + lightCount + ".direction", dir); - uniformf("uLights.concentration.3d." + lightCount, programObject3D, "uLights" + lightCount + ".concentration", concentration); - uniformf("uLights.angle.3d." + lightCount, programObject3D, "uLights" + lightCount + ".angle", angle); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 3); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount); - }; - - //////////////////////////////////////////////////////////////////////////// - // Camera functions - //////////////////////////////////////////////////////////////////////////// - - /** - * The <b>beginCamera()</b> and <b>endCamera()</b> functions enable advanced customization of the camera space. - * The functions are useful if you want to more control over camera movement, however for most users, the <b>camera()</b> - * function will be sufficient.<br /><br />The camera functions will replace any transformations (such as <b>rotate()</b> - * or <b>translate()</b>) that occur before them in <b>draw()</b>, but they will not automatically replace the camera - * transform itself. For this reason, camera functions should be placed at the beginning of <b>draw()</b> (so that - * transformations happen afterwards), and the <b>camera()</b> function can be used after <b>beginCamera()</b> if - * you want to reset the camera before applying transformations.<br /><br />This function sets the matrix mode to the - * camera matrix so calls such as <b>translate()</b>, <b>rotate()</b>, applyMatrix() and resetMatrix() affect the camera. - * <b>beginCamera()</b> should always be used with a following <b>endCamera()</b> and pairs of <b>beginCamera()</b> and - * <b>endCamera()</b> cannot be nested. - * - * @see camera - * @see endCamera - * @see applyMatrix - * @see resetMatrix - * @see translate - * @see rotate - * @see scale - */ - Drawing2D.prototype.beginCamera = function() { - throw ("beginCamera() is not available in 2D mode"); - }; - - Drawing3D.prototype.beginCamera = function() { - if (manipulatingCamera) { - throw ("You cannot call beginCamera() again before calling endCamera()"); - } - manipulatingCamera = true; - modelView = cameraInv; - modelViewInv = cam; - }; - - /** - * The <b>beginCamera()</b> and <b>endCamera()</b> functions enable advanced customization of the camera space. - * Please see the reference for <b>beginCamera()</b> for a description of how the functions are used. - * - * @see beginCamera - */ - Drawing2D.prototype.endCamera = function() { - throw ("endCamera() is not available in 2D mode"); - }; - - Drawing3D.prototype.endCamera = function() { - if (!manipulatingCamera) { - throw ("You cannot call endCamera() before calling beginCamera()"); - } - modelView.set(cam); - modelViewInv.set(cameraInv); - manipulatingCamera = false; - }; - - /** - * Sets the position of the camera through setting the eye position, the center of the scene, and which axis is facing - * upward. Moving the eye position and the direction it is pointing (the center of the scene) allows the images to be - * seen from different angles. The version without any parameters sets the camera to the default position, pointing to - * the center of the display window with the Y axis as up. The default values are camera(width/2.0, height/2.0, - * (height/2.0) / tan(PI*60.0 / 360.0), width/2.0, height/2.0, 0, 0, 1, 0). This function is similar to gluLookAt() - * in OpenGL, but it first clears the current camera settings. - * - * @param {float} eyeX x-coordinate for the eye - * @param {float} eyeY y-coordinate for the eye - * @param {float} eyeZ z-coordinate for the eye - * @param {float} centerX x-coordinate for the center of the scene - * @param {float} centerY y-coordinate for the center of the scene - * @param {float} centerZ z-coordinate for the center of the scene - * @param {float} upX usually 0.0, 1.0, -1.0 - * @param {float} upY usually 0.0, 1.0, -1.0 - * @param {float} upZ usually 0.0, 1.0, -1.0 - * - * @see beginCamera - * @see endCamera - * @see frustum - */ - p.camera = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { - if (eyeX === undef) { - // Workaround if createGraphics is used. - cameraX = p.width / 2; - cameraY = p.height / 2; - cameraZ = cameraY / Math.tan(cameraFOV / 2); - eyeX = cameraX; - eyeY = cameraY; - eyeZ = cameraZ; - centerX = cameraX; - centerY = cameraY; - centerZ = 0; - upX = 0; - upY = 1; - upZ = 0; - } - - var z = new PVector(eyeX - centerX, eyeY - centerY, eyeZ - centerZ); - var y = new PVector(upX, upY, upZ); - z.normalize(); - var x = PVector.cross(y, z); - y = PVector.cross(z, x); - x.normalize(); - y.normalize(); - - var xX = x.x, - xY = x.y, - xZ = x.z; - - var yX = y.x, - yY = y.y, - yZ = y.z; - - var zX = z.x, - zY = z.y, - zZ = z.z; - - cam.set(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); - - cam.translate(-eyeX, -eyeY, -eyeZ); - - cameraInv.reset(); - cameraInv.invApply(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); - - cameraInv.translate(eyeX, eyeY, eyeZ); - - modelView.set(cam); - modelViewInv.set(cameraInv); - }; - - /** - * Sets a perspective projection applying foreshortening, making distant objects appear smaller than closer ones. The - * parameters define a viewing volume with the shape of truncated pyramid. Objects near to the front of the volume appear - * their actual size, while farther objects appear smaller. This projection simulates the perspective of the world more - * accurately than orthographic projection. The version of perspective without parameters sets the default perspective and - * the version with four parameters allows the programmer to set the area precisely. The default values are: - * perspective(PI/3.0, width/height, cameraZ/10.0, cameraZ*10.0) where cameraZ is ((height/2.0) / tan(PI*60.0/360.0)); - * - * @param {float} fov field-of-view angle (in radians) for vertical direction - * @param {float} aspect ratio of width to height - * @param {float} zNear z-position of nearest clipping plane - * @param {float} zFar z-positions of farthest clipping plane - */ - p.perspective = function(fov, aspect, near, far) { - if (arguments.length === 0) { - //in case canvas is resized - cameraY = curElement.height / 2; - cameraZ = cameraY / Math.tan(cameraFOV / 2); - cameraNear = cameraZ / 10; - cameraFar = cameraZ * 10; - cameraAspect = p.width / p.height; - fov = cameraFOV; - aspect = cameraAspect; - near = cameraNear; - far = cameraFar; - } - - var yMax, yMin, xMax, xMin; - yMax = near * Math.tan(fov / 2); - yMin = -yMax; - xMax = yMax * aspect; - xMin = yMin * aspect; - p.frustum(xMin, xMax, yMin, yMax, near, far); - }; - - /** - * Sets a perspective matrix defined through the parameters. Works like glFrustum, except it wipes out the current - * perspective matrix rather than muliplying itself with it. - * - * @param {float} left left coordinate of the clipping plane - * @param {float} right right coordinate of the clipping plane - * @param {float} bottom bottom coordinate of the clipping plane - * @param {float} top top coordinate of the clipping plane - * @param {float} near near coordinate of the clipping plane - * @param {float} far far coordinate of the clipping plane - * - * @see beginCamera - * @see camera - * @see endCamera - * @see perspective - */ - Drawing2D.prototype.frustum = function() { - throw("Processing.js: frustum() is not supported in 2D mode"); - }; - - Drawing3D.prototype.frustum = function(left, right, bottom, top, near, far) { - frustumMode = true; - projection = new PMatrix3D(); - projection.set((2 * near) / (right - left), 0, (right + left) / (right - left), - 0, 0, (2 * near) / (top - bottom), (top + bottom) / (top - bottom), - 0, 0, 0, -(far + near) / (far - near), -(2 * far * near) / (far - near), - 0, 0, -1, 0); - var proj = new PMatrix3D(); - proj.set(projection); - proj.transpose(); - curContext.useProgram(programObject2D); - uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array()); - curContext.useProgram(programObject3D); - uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array()); - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array()); - }; - - /** - * Sets an orthographic projection and defines a parallel clipping volume. All objects with the same dimension appear - * the same size, regardless of whether they are near or far from the camera. The parameters to this function specify - * the clipping volume where left and right are the minimum and maximum x values, top and bottom are the minimum and - * maximum y values, and near and far are the minimum and maximum z values. If no parameters are given, the default - * is used: ortho(0, width, 0, height, -10, 10). - * - * @param {float} left left plane of the clipping volume - * @param {float} right right plane of the clipping volume - * @param {float} bottom bottom plane of the clipping volume - * @param {float} top top plane of the clipping volume - * @param {float} near maximum distance from the origin to the viewer - * @param {float} far maximum distance from the origin away from the viewer - */ - p.ortho = function(left, right, bottom, top, near, far) { - if (arguments.length === 0) { - left = 0; - right = p.width; - bottom = 0; - top = p.height; - near = -10; - far = 10; - } - - var x = 2 / (right - left); - var y = 2 / (top - bottom); - var z = -2 / (far - near); - - var tx = -(right + left) / (right - left); - var ty = -(top + bottom) / (top - bottom); - var tz = -(far + near) / (far - near); - - projection = new PMatrix3D(); - projection.set(x, 0, 0, tx, 0, y, 0, ty, 0, 0, z, tz, 0, 0, 0, 1); - - var proj = new PMatrix3D(); - proj.set(projection); - proj.transpose(); - curContext.useProgram(programObject2D); - uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array()); - curContext.useProgram(programObject3D); - uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array()); - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array()); - frustumMode = false; - }; - /** - * The printProjection() prints the current projection matrix to the text window. - */ - p.printProjection = function() { - projection.print(); - }; - /** - * The printCamera() function prints the current camera matrix. - */ - p.printCamera = function() { - cam.print(); - }; - - //////////////////////////////////////////////////////////////////////////// - // Shapes - //////////////////////////////////////////////////////////////////////////// - /** - * The box() function renders a box. A box is an extruded rectangle. A box with equal dimension on all sides is a cube. - * Calling this function with only one parameter will create a cube. - * - * @param {int|float} w dimension of the box in the x-dimension - * @param {int|float} h dimension of the box in the y-dimension - * @param {int|float} d dimension of the box in the z-dimension - */ - Drawing2D.prototype.box = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.box = function(w, h, d) { - // user can uniformly scale the box by - // passing in only one argument. - if (!h || !d) { - h = d = w; - } - - // Modeling transformation - var model = new PMatrix3D(); - model.scale(w, h, d); - - // Viewing transformation needs to have Y flipped - // becuase that's what Processing does. - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - if (doFill) { - curContext.useProgram(programObject3D); - uniformMatrix("model3d", programObject3D, "uModel", false, model.array()); - uniformMatrix("view3d", programObject3D, "uView", false, view.array()); - // Fix stitching problems. (lines get occluded by triangles - // since they share the same depth values). This is not entirely - // working, but it's a start for drawing the outline. So - // developers can start playing around with styles. - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - uniformf("color3d", programObject3D, "uColor", fillStyle); - - // Calculating the normal matrix can be expensive, so only - // do it if it's necessary. - if(lightCount > 0){ - // Create the normal transformation matrix. - var v = new PMatrix3D(); - v.set(view); - - var m = new PMatrix3D(); - m.set(model); - - v.mult(m); - - var normalMatrix = new PMatrix3D(); - normalMatrix.set(v); - normalMatrix.invert(); - normalMatrix.transpose(); - - uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); - vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, boxNormBuffer); - } - else{ - disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); - } - - vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, boxBuffer); - - // Turn off per vertex colors. - disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); - disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); - - curContext.drawArrays(curContext.TRIANGLES, 0, boxVerts.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL); - } - - // Draw the box outline. - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); - vertexAttribPointer("vertex2d", programObject2D, "aVertex", 3, boxOutlineBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.drawArrays(curContext.LINES, 0, boxOutlineVerts.length / 3); - } - }; - - /** - * The initSphere() function is a helper function used by <b>sphereDetail()</b> - * This function creates and stores sphere vertices every time the user changes sphere detail. - * - * @see #sphereDetail - */ - var initSphere = function() { - var i; - sphereVerts = []; - - for (i = 0; i < sphereDetailU; i++) { - sphereVerts.push(0); - sphereVerts.push(-1); - sphereVerts.push(0); - sphereVerts.push(sphereX[i]); - sphereVerts.push(sphereY[i]); - sphereVerts.push(sphereZ[i]); - } - sphereVerts.push(0); - sphereVerts.push(-1); - sphereVerts.push(0); - sphereVerts.push(sphereX[0]); - sphereVerts.push(sphereY[0]); - sphereVerts.push(sphereZ[0]); - - var v1, v11, v2; - - // middle rings - var voff = 0; - for (i = 2; i < sphereDetailV; i++) { - v1 = v11 = voff; - voff += sphereDetailU; - v2 = voff; - for (var j = 0; j < sphereDetailU; j++) { - sphereVerts.push(sphereX[v1]); - sphereVerts.push(sphereY[v1]); - sphereVerts.push(sphereZ[v1++]); - sphereVerts.push(sphereX[v2]); - sphereVerts.push(sphereY[v2]); - sphereVerts.push(sphereZ[v2++]); - } - - // close each ring - v1 = v11; - v2 = voff; - - sphereVerts.push(sphereX[v1]); - sphereVerts.push(sphereY[v1]); - sphereVerts.push(sphereZ[v1]); - sphereVerts.push(sphereX[v2]); - sphereVerts.push(sphereY[v2]); - sphereVerts.push(sphereZ[v2]); - } - - // add the northern cap - for (i = 0; i < sphereDetailU; i++) { - v2 = voff + i; - - sphereVerts.push(sphereX[v2]); - sphereVerts.push(sphereY[v2]); - sphereVerts.push(sphereZ[v2]); - sphereVerts.push(0); - sphereVerts.push(1); - sphereVerts.push(0); - } - - sphereVerts.push(sphereX[voff]); - sphereVerts.push(sphereY[voff]); - sphereVerts.push(sphereZ[voff]); - sphereVerts.push(0); - sphereVerts.push(1); - sphereVerts.push(0); - - //set the buffer data - curContext.bindBuffer(curContext.ARRAY_BUFFER, sphereBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(sphereVerts), curContext.STATIC_DRAW); - }; - - /** - * The sphereDetail() function controls the detail used to render a sphere by adjusting the number of - * vertices of the sphere mesh. The default resolution is 30, which creates - * a fairly detailed sphere definition with vertices every 360/30 = 12 - * degrees. If you're going to render a great number of spheres per frame, - * it is advised to reduce the level of detail using this function. - * The setting stays active until <b>sphereDetail()</b> is called again with - * a new parameter and so should <i>not</i> be called prior to every - * <b>sphere()</b> statement, unless you wish to render spheres with - * different settings, e.g. using less detail for smaller spheres or ones - * further away from the camera. To control the detail of the horizontal - * and vertical resolution independently, use the version of the functions - * with two parameters. Calling this function with one parameter sets the number of segments - *(minimum of 3) used per full circle revolution. This is equivalent to calling the function with - * two identical values. - * - * @param {int} ures number of segments used horizontally (longitudinally) per full circle revolution - * @param {int} vres number of segments used vertically (latitudinally) from top to bottom - * - * @see #sphere() - */ - p.sphereDetail = function(ures, vres) { - var i; - - if (arguments.length === 1) { - ures = vres = arguments[0]; - } - - if (ures < 3) { - ures = 3; - } // force a minimum res - if (vres < 2) { - vres = 2; - } // force a minimum res - // if it hasn't changed do nothing - if ((ures === sphereDetailU) && (vres === sphereDetailV)) { - return; - } - - var delta = PConstants.SINCOS_LENGTH / ures; - var cx = new Float32Array(ures); - var cz = new Float32Array(ures); - // calc unit circle in XZ plane - for (i = 0; i < ures; i++) { - cx[i] = cosLUT[((i * delta) % PConstants.SINCOS_LENGTH) | 0]; - cz[i] = sinLUT[((i * delta) % PConstants.SINCOS_LENGTH) | 0]; - } - - // computing vertexlist - // vertexlist starts at south pole - var vertCount = ures * (vres - 1) + 2; - var currVert = 0; - - // re-init arrays to store vertices - sphereX = new Float32Array(vertCount); - sphereY = new Float32Array(vertCount); - sphereZ = new Float32Array(vertCount); - - var angle_step = (PConstants.SINCOS_LENGTH * 0.5) / vres; - var angle = angle_step; - - // step along Y axis - for (i = 1; i < vres; i++) { - var curradius = sinLUT[(angle % PConstants.SINCOS_LENGTH) | 0]; - var currY = -cosLUT[(angle % PConstants.SINCOS_LENGTH) | 0]; - for (var j = 0; j < ures; j++) { - sphereX[currVert] = cx[j] * curradius; - sphereY[currVert] = currY; - sphereZ[currVert++] = cz[j] * curradius; - } - angle += angle_step; - } - sphereDetailU = ures; - sphereDetailV = vres; - - // make the sphere verts and norms - initSphere(); - }; - - /** - * The sphere() function draws a sphere with radius r centered at coordinate 0, 0, 0. - * A sphere is a hollow ball made from tessellated triangles. - * - * @param {int|float} r the radius of the sphere - */ - Drawing2D.prototype.sphere = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.sphere = function() { - var sRad = arguments[0]; - - if ((sphereDetailU < 3) || (sphereDetailV < 2)) { - p.sphereDetail(30); - } - - // Modeling transformation. - var model = new PMatrix3D(); - model.scale(sRad, sRad, sRad); - - // viewing transformation needs to have Y flipped - // becuase that's what Processing does. - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - if (doFill) { - // Calculating the normal matrix can be expensive, so only - // do it if it's necessary. - if(lightCount > 0){ - // Create a normal transformation matrix. - var v = new PMatrix3D(); - v.set(view); - - var m = new PMatrix3D(); - m.set(model); - - v.mult(m); - - var normalMatrix = new PMatrix3D(); - normalMatrix.set(v); - normalMatrix.invert(); - normalMatrix.transpose(); - - uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); - vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, sphereBuffer); - } - else{ - disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); - } - - curContext.useProgram(programObject3D); - disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); - - uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array()); - uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); - vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, sphereBuffer); - - // Turn off per vertex colors. - disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); - - // fix stitching problems. (lines get occluded by triangles - // since they share the same depth values). This is not entirely - // working, but it's a start for drawing the outline. So - // developers can start playing around with styles. - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - uniformf("uColor3d", programObject3D, "uColor", fillStyle); - curContext.drawArrays(curContext.TRIANGLE_STRIP, 0, sphereVerts.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL); - } - - // Draw the sphere outline. - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, sphereBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); - curContext.drawArrays(curContext.LINE_STRIP, 0, sphereVerts.length / 3); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Coordinates - //////////////////////////////////////////////////////////////////////////// - - /** - * Returns the three-dimensional X, Y, Z position in model space. This returns - * the X value for a given coordinate based on the current set of transformations - * (scale, rotate, translate, etc.) The X value can be used to place an object - * in space relative to the location of the original point once the transformations - * are no longer in use.<br /> - * <br /> - * - * @param {int | float} x 3D x coordinate to be mapped - * @param {int | float} y 3D y coordinate to be mapped - * @param {int | float} z 3D z coordinate to be mapped - * - * @returns {float} - * - * @see modelY - * @see modelZ - */ - p.modelX = function(x, y, z) { - var mv = modelView.array(); - var ci = cameraInv.array(); - - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - - var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw; - var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; - - return (ow !== 0) ? ox / ow : ox; - }; - - /** - * Returns the three-dimensional X, Y, Z position in model space. This returns - * the Y value for a given coordinate based on the current set of transformations - * (scale, rotate, translate, etc.) The Y value can be used to place an object in - * space relative to the location of the original point once the transformations - * are no longer in use.<br /> - * <br /> - * - * @param {int | float} x 3D x coordinate to be mapped - * @param {int | float} y 3D y coordinate to be mapped - * @param {int | float} z 3D z coordinate to be mapped - * - * @returns {float} - * - * @see modelX - * @see modelZ - */ - p.modelY = function(x, y, z) { - var mv = modelView.array(); - var ci = cameraInv.array(); - - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - - var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw; - var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; - - return (ow !== 0) ? oy / ow : oy; - }; - - /** - * Returns the three-dimensional X, Y, Z position in model space. This returns - * the Z value for a given coordinate based on the current set of transformations - * (scale, rotate, translate, etc.) The Z value can be used to place an object in - * space relative to the location of the original point once the transformations - * are no longer in use. - * - * @param {int | float} x 3D x coordinate to be mapped - * @param {int | float} y 3D y coordinate to be mapped - * @param {int | float} z 3D z coordinate to be mapped - * - * @returns {float} - * - * @see modelX - * @see modelY - */ - p.modelZ = function(x, y, z) { - var mv = modelView.array(); - var ci = cameraInv.array(); - - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - - var oz = ci[8] * ax + ci[9] * ay + ci[10] * az + ci[11] * aw; - var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; - - return (ow !== 0) ? oz / ow : oz; - }; - - //////////////////////////////////////////////////////////////////////////// - // Material Properties - //////////////////////////////////////////////////////////////////////////// - - /** - * Sets the ambient reflectance for shapes drawn to the screen. This is - * combined with the ambient light component of environment. The color - * components set through the parameters define the reflectance. For example in - * the default color mode, setting v1=255, v2=126, v3=0, would cause all the - * red light to reflect and half of the green light to reflect. Used in combination - * with <b>emissive()</b>, <b>specular()</b>, and <b>shininess()</b> in setting - * the materal properties of shapes. - * - * @param {int | float} gray - * - * @returns none - * - * @see emissive - * @see specular - * @see shininess - */ - Drawing2D.prototype.ambient = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.ambient = function(v1, v2, v3) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - var col = p.color(v1, v2, v3); - uniformf("uMaterialAmbient3d", programObject3D, "uMaterialAmbient", p.color.toGLArray(col).slice(0, 3)); - }; - - /** - * Sets the emissive color of the material used for drawing shapes - * drawn to the screen. Used in combination with ambient(), specular(), - * and shininess() in setting the material properties of shapes. - * - * Can be called in the following ways: - * - * emissive(gray) - * @param {int | float} gray number specifying value between white and black - * - * emissive(color) - * @param {color} color any value of the color datatype - * - * emissive(v1, v2, v3) - * @param {int | float} v1 red or hue value - * @param {int | float} v2 green or saturation value - * @param {int | float} v3 blue or brightness value - * - * @returns none - * - * @see ambient - * @see specular - * @see shininess - */ - Drawing2D.prototype.emissive = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.emissive = function(v1, v2, v3) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - var col = p.color(v1, v2, v3); - uniformf("uMaterialEmissive3d", programObject3D, "uMaterialEmissive", p.color.toGLArray(col).slice(0, 3)); - }; - - /** - * Sets the amount of gloss in the surface of shapes. Used in combination with - * <b>ambient()</b>, <b>specular()</b>, and <b>emissive()</b> in setting the - * material properties of shapes. - * - * @param {float} shine degree of shininess - * - * @returns none - */ - Drawing2D.prototype.shininess = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.shininess = function(shine) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - uniformf("uShininess3d", programObject3D, "uShininess", shine); - }; - - /** - * Sets the specular color of the materials used for shapes drawn to the screen, - * which sets the color of hightlights. Specular refers to light which bounces - * off a surface in a perferred direction (rather than bouncing in all directions - * like a diffuse light). Used in combination with emissive(), ambient(), and - * shininess() in setting the material properties of shapes. - * - * Can be called in the following ways: - * - * specular(gray) - * @param {int | float} gray number specifying value between white and black - * - * specular(gray, alpha) - * @param {int | float} gray number specifying value between white and black - * @param {int | float} alpha opacity - * - * specular(color) - * @param {color} color any value of the color datatype - * - * specular(v1, v2, v3) - * @param {int | float} v1 red or hue value - * @param {int | float} v2 green or saturation value - * @param {int | float} v3 blue or brightness value - * - * specular(v1, v2, v3, alpha) - * @param {int | float} v1 red or hue value - * @param {int | float} v2 green or saturation value - * @param {int | float} v3 blue or brightness value - * @param {int | float} alpha opacity - * - * @returns none - * - * @see ambient - * @see emissive - * @see shininess - */ - Drawing2D.prototype.specular = DrawingShared.prototype.a3DOnlyFunction; - - Drawing3D.prototype.specular = function(v1, v2, v3) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - var col = p.color(v1, v2, v3); - uniformf("uMaterialSpecular3d", programObject3D, "uMaterialSpecular", p.color.toGLArray(col).slice(0, 3)); - }; - - //////////////////////////////////////////////////////////////////////////// - // Coordinates - //////////////////////////////////////////////////////////////////////////// - - /** - * Takes a three-dimensional X, Y, Z position and returns the X value for - * where it will appear on a (two-dimensional) screen. - * - * @param {int | float} x 3D x coordinate to be mapped - * @param {int | float} y 3D y coordinate to be mapped - * @param {int | float} z 3D z optional coordinate to be mapped - * - * @returns {float} - * - * @see screenY - * @see screenZ - */ - p.screenX = function( x, y, z ) { - var mv = modelView.array(); - if( mv.length === 16 ) - { - var ax = mv[ 0]*x + mv[ 1]*y + mv[ 2]*z + mv[ 3]; - var ay = mv[ 4]*x + mv[ 5]*y + mv[ 6]*z + mv[ 7]; - var az = mv[ 8]*x + mv[ 9]*y + mv[10]*z + mv[11]; - var aw = mv[12]*x + mv[13]*y + mv[14]*z + mv[15]; - - var pj = projection.array(); - - var ox = pj[ 0]*ax + pj[ 1]*ay + pj[ 2]*az + pj[ 3]*aw; - var ow = pj[12]*ax + pj[13]*ay + pj[14]*az + pj[15]*aw; - - if ( ow !== 0 ){ - ox /= ow; - } - return p.width * ( 1 + ox ) / 2.0; - } - // We assume that we're in 2D - return modelView.multX(x, y); - }; - - /** - * Takes a three-dimensional X, Y, Z position and returns the Y value for - * where it will appear on a (two-dimensional) screen. - * - * @param {int | float} x 3D x coordinate to be mapped - * @param {int | float} y 3D y coordinate to be mapped - * @param {int | float} z 3D z optional coordinate to be mapped - * - * @returns {float} - * - * @see screenX - * @see screenZ - */ - p.screenY = function screenY( x, y, z ) { - var mv = modelView.array(); - if( mv.length === 16 ) { - var ax = mv[ 0]*x + mv[ 1]*y + mv[ 2]*z + mv[ 3]; - var ay = mv[ 4]*x + mv[ 5]*y + mv[ 6]*z + mv[ 7]; - var az = mv[ 8]*x + mv[ 9]*y + mv[10]*z + mv[11]; - var aw = mv[12]*x + mv[13]*y + mv[14]*z + mv[15]; - - var pj = projection.array(); - - var oy = pj[ 4]*ax + pj[ 5]*ay + pj[ 6]*az + pj[ 7]*aw; - var ow = pj[12]*ax + pj[13]*ay + pj[14]*az + pj[15]*aw; - - if ( ow !== 0 ){ - oy /= ow; - } - return p.height * ( 1 + oy ) / 2.0; - } - // We assume that we're in 2D - return modelView.multY(x, y); - }; - - /** - * Takes a three-dimensional X, Y, Z position and returns the Z value for - * where it will appear on a (two-dimensional) screen. - * - * @param {int | float} x 3D x coordinate to be mapped - * @param {int | float} y 3D y coordinate to be mapped - * @param {int | float} z 3D z coordinate to be mapped - * - * @returns {float} - * - * @see screenX - * @see screenY - */ - p.screenZ = function screenZ( x, y, z ) { - var mv = modelView.array(); - if( mv.length !== 16 ) { - return 0; - } - - var pj = projection.array(); - - var ax = mv[ 0]*x + mv[ 1]*y + mv[ 2]*z + mv[ 3]; - var ay = mv[ 4]*x + mv[ 5]*y + mv[ 6]*z + mv[ 7]; - var az = mv[ 8]*x + mv[ 9]*y + mv[10]*z + mv[11]; - var aw = mv[12]*x + mv[13]*y + mv[14]*z + mv[15]; - - var oz = pj[ 8]*ax + pj[ 9]*ay + pj[10]*az + pj[11]*aw; - var ow = pj[12]*ax + pj[13]*ay + pj[14]*az + pj[15]*aw; - - if ( ow !== 0 ) { - oz /= ow; - } - return ( oz + 1 ) / 2.0; - }; - - //////////////////////////////////////////////////////////////////////////// - // Style functions - //////////////////////////////////////////////////////////////////////////// - /** - * The fill() function sets the color used to fill shapes. For example, if you run <b>fill(204, 102, 0)</b>, all subsequent shapes will be filled with orange. - * This color is either specified in terms of the RGB or HSB color depending on the current <b>colorMode()</b> - *(the default color space is RGB, with each value in the range from 0 to 255). - * <br><br>When using hexadecimal notation to specify a color, use "#" or "0x" before the values (e.g. #CCFFAA, 0xFFCCFFAA). - * The # syntax uses six digits to specify a color (the way colors are specified in HTML and CSS). When using the hexadecimal notation starting with "0x", - * the hexadecimal value must be specified with eight characters; the first two characters define the alpha component and the remainder the red, green, and blue components. - * <br><br>The value for the parameter "gray" must be less than or equal to the current maximum value as specified by <b>colorMode()</b>. The default maximum value is 255. - * <br><br>To change the color of an image (or a texture), use tint(). - * - * @param {int|float} gray number specifying value between white and black - * @param {int|float} value1 red or hue value - * @param {int|float} value2 green or saturation value - * @param {int|float} value3 blue or brightness value - * @param {int|float} alpha opacity of the fill - * @param {Color} color any value of the color datatype - * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00) - * - * @see #noFill() - * @see #stroke() - * @see #tint() - * @see #background() - * @see #colorMode() - */ - DrawingShared.prototype.fill = function() { - var color = p.color.apply(this, arguments); - if(color === currentFillColor && doFill) { - return; - } - doFill = true; - currentFillColor = color; - }; - - Drawing2D.prototype.fill = function() { - DrawingShared.prototype.fill.apply(this, arguments); - isFillDirty = true; - }; - - Drawing3D.prototype.fill = function() { - DrawingShared.prototype.fill.apply(this, arguments); - fillStyle = p.color.toGLArray(currentFillColor); - }; - - function executeContextFill() { - if(doFill) { - if(isFillDirty) { - curContext.fillStyle = p.color.toString(currentFillColor); - isFillDirty = false; - } - curContext.fill(); - } - } - - /** - * The noFill() function disables filling geometry. If both <b>noStroke()</b> and <b>noFill()</b> - * are called, no shapes will be drawn to the screen. - * - * @see #fill() - * - */ - p.noFill = function() { - doFill = false; - }; - - /** - * The stroke() function sets the color used to draw lines and borders around shapes. This color - * is either specified in terms of the RGB or HSB color depending on the - * current <b>colorMode()</b> (the default color space is RGB, with each - * value in the range from 0 to 255). - * <br><br>When using hexadecimal notation to specify a color, use "#" or - * "0x" before the values (e.g. #CCFFAA, 0xFFCCFFAA). The # syntax uses six - * digits to specify a color (the way colors are specified in HTML and CSS). - * When using the hexadecimal notation starting with "0x", the hexadecimal - * value must be specified with eight characters; the first two characters - * define the alpha component and the remainder the red, green, and blue - * components. - * <br><br>The value for the parameter "gray" must be less than or equal - * to the current maximum value as specified by <b>colorMode()</b>. - * The default maximum value is 255. - * - * @param {int|float} gray number specifying value between white and black - * @param {int|float} value1 red or hue value - * @param {int|float} value2 green or saturation value - * @param {int|float} value3 blue or brightness value - * @param {int|float} alpha opacity of the stroke - * @param {Color} color any value of the color datatype - * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00) - * - * @see #fill() - * @see #noStroke() - * @see #tint() - * @see #background() - * @see #colorMode() - */ - DrawingShared.prototype.stroke = function() { - var color = p.color.apply(this, arguments); - if(color === currentStrokeColor && doStroke) { - return; - } - doStroke = true; - currentStrokeColor = color; - }; - - Drawing2D.prototype.stroke = function() { - DrawingShared.prototype.stroke.apply(this, arguments); - isStrokeDirty = true; - }; - - Drawing3D.prototype.stroke = function() { - DrawingShared.prototype.stroke.apply(this, arguments); - strokeStyle = p.color.toGLArray(currentStrokeColor); - }; - - function executeContextStroke() { - if(doStroke) { - if(isStrokeDirty) { - curContext.strokeStyle = p.color.toString(currentStrokeColor); - isStrokeDirty = false; - } - curContext.stroke(); - } - } - - /** - * The noStroke() function disables drawing the stroke (outline). If both <b>noStroke()</b> and - * <b>noFill()</b> are called, no shapes will be drawn to the screen. - * - * @see #stroke() - */ - p.noStroke = function() { - doStroke = false; - }; - - /** - * The strokeWeight() function sets the width of the stroke used for lines, points, and the border around shapes. - * All widths are set in units of pixels. - * - * @param {int|float} w the weight (in pixels) of the stroke - */ - DrawingShared.prototype.strokeWeight = function(w) { - lineWidth = w; - }; - - Drawing2D.prototype.strokeWeight = function(w) { - DrawingShared.prototype.strokeWeight.apply(this, arguments); - curContext.lineWidth = w; - }; - - Drawing3D.prototype.strokeWeight = function(w) { - DrawingShared.prototype.strokeWeight.apply(this, arguments); - - // Processing groups the weight of points and lines under this one function, - // but for WebGL, we need to set a uniform for points and call a function for line. - - curContext.useProgram(programObject2D); - uniformf("pointSize2d", programObject2D, "uPointSize", w); - - curContext.useProgram(programObjectUnlitShape); - uniformf("pointSizeUnlitShape", programObjectUnlitShape, "uPointSize", w); - - curContext.lineWidth(w); - }; - - /** - * The strokeCap() function sets the style for rendering line endings. These ends are either squared, extended, or rounded and - * specified with the corresponding parameters SQUARE, PROJECT, and ROUND. The default cap is ROUND. - * This function is not available with the P2D, P3D, or OPENGL renderers - * - * @param {int} value Either SQUARE, PROJECT, or ROUND - */ - p.strokeCap = function(value) { - drawing.$ensureContext().lineCap = value; - }; - - /** - * The strokeJoin() function sets the style of the joints which connect line segments. - * These joints are either mitered, beveled, or rounded and specified with the corresponding parameters MITER, BEVEL, and ROUND. The default joint is MITER. - * This function is not available with the P2D, P3D, or OPENGL renderers - * - * @param {int} value Either SQUARE, PROJECT, or ROUND - */ - p.strokeJoin = function(value) { - drawing.$ensureContext().lineJoin = value; - }; - - /** - * The smooth() function draws all geometry with smooth (anti-aliased) edges. This will slow down the frame rate of the application, - * but will enhance the visual refinement. <br/><br/> - * Note that smooth() will also improve image quality of resized images, and noSmooth() will disable image (and font) smoothing altogether. - * When working with a 3D sketch, smooth will draw points as circles rather than squares. - * - * @see #noSmooth() - * @see #hint() - * @see #size() - */ - - Drawing2D.prototype.smooth = function() { - renderSmooth = true; - var style = curElement.style; - style.setProperty("image-rendering", "optimizeQuality", "important"); - style.setProperty("-ms-interpolation-mode", "bicubic", "important"); - if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) { - curContext.mozImageSmoothingEnabled = true; - } - }; - - Drawing3D.prototype.smooth = function(){ - renderSmooth = true; - }; - - /** - * The noSmooth() function draws all geometry with jagged (aliased) edges. - * - * @see #smooth() - */ - - Drawing2D.prototype.noSmooth = function() { - renderSmooth = false; - var style = curElement.style; - style.setProperty("image-rendering", "optimizeSpeed", "important"); - style.setProperty("image-rendering", "-moz-crisp-edges", "important"); - style.setProperty("image-rendering", "-webkit-optimize-contrast", "important"); - style.setProperty("image-rendering", "optimize-contrast", "important"); - style.setProperty("-ms-interpolation-mode", "nearest-neighbor", "important"); - if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) { - curContext.mozImageSmoothingEnabled = false; - } - }; - - Drawing3D.prototype.noSmooth = function(){ - renderSmooth = false; - }; - - //////////////////////////////////////////////////////////////////////////// - // Vector drawing functions - //////////////////////////////////////////////////////////////////////////// - /** - * The point() function draws a point, a coordinate in space at the dimension of one pixel. - * The first parameter is the horizontal value for the point, the second - * value is the vertical value for the point, and the optional third value - * is the depth value. Drawing this shape in 3D using the <b>z</b> - * parameter requires the P3D or OPENGL parameter in combination with - * size as shown in the above example. - * - * @param {int|float} x x-coordinate of the point - * @param {int|float} y y-coordinate of the point - * @param {int|float} z z-coordinate of the point - * - * @see #beginShape() - */ - Drawing2D.prototype.point = function(x, y) { - if (!doStroke) { - return; - } - if (!renderSmooth) { - x = Math.round(x); - y = Math.round(y); - } - curContext.fillStyle = p.color.toString(currentStrokeColor); - isFillDirty = true; - // Draw a circle for any point larger than 1px - if (lineWidth > 1) { - curContext.beginPath(); - curContext.arc(x, y, lineWidth / 2, 0, PConstants.TWO_PI, false); - curContext.fill(); - } else { - curContext.fillRect(x, y, 1, 1); - } - }; - - Drawing3D.prototype.point = function(x, y, z) { - var model = new PMatrix3D(); - - // move point to position - model.translate(x, y, z || 0); - model.transpose(); - - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - - if (lineWidth > 0 && doStroke) { - // this will be replaced with the new bit shifting color code - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); - uniformi("uSmooth2d", programObject2D, "uSmooth", renderSmooth); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, pointBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.drawArrays(curContext.POINTS, 0, 1); - } - }; - - /** - * Using the <b>beginShape()</b> and <b>endShape()</b> functions allow creating more complex forms. - * <b>beginShape()</b> begins recording vertices for a shape and <b>endShape()</b> stops recording. - * The value of the <b>MODE</b> parameter tells it which types of shapes to create from the provided vertices. - * With no mode specified, the shape can be any irregular polygon. After calling the <b>beginShape()</b> function, - * a series of <b>vertex()</b> commands must follow. To stop drawing the shape, call <b>endShape()</b>. - * The <b>vertex()</b> function with two parameters specifies a position in 2D and the <b>vertex()</b> - * function with three parameters specifies a position in 3D. Each shape will be outlined with the current - * stroke color and filled with the fill color. - * - * @param {int} MODE either POINTS, LINES, TRIANGLES, TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP. - * - * @see endShape - * @see vertex - * @see curveVertex - * @see bezierVertex - */ - p.beginShape = function(type) { - curShape = type; - curvePoints = []; - vertArray = []; - }; - - /** - * All shapes are constructed by connecting a series of vertices. <b>vertex()</b> is used to specify the vertex - * coordinates for points, lines, triangles, quads, and polygons and is used exclusively within the <b>beginShape()</b> - * and <b>endShape()</b> function. <br /><br />Drawing a vertex in 3D using the <b>z</b> parameter requires the P3D or - * OPENGL parameter in combination with size as shown in the above example.<br /><br />This function is also used to map a - * texture onto the geometry. The <b>texture()</b> function declares the texture to apply to the geometry and the <b>u</b> - * and <b>v</b> coordinates set define the mapping of this texture to the form. By default, the coordinates used for - * <b>u</b> and <b>v</b> are specified in relation to the image's size in pixels, but this relation can be changed with - * <b>textureMode()</b>. - * - * @param {int | float} x x-coordinate of the vertex - * @param {int | float} y y-coordinate of the vertex - * @param {boolean} moveto flag to indicate whether this is a new subpath - * - * @see beginShape - * @see endShape - * @see bezierVertex - * @see curveVertex - * @see texture - */ - - Drawing2D.prototype.vertex = function(x, y, moveTo) { - var vert = []; - - if (firstVert) { firstVert = false; } - vert.isVert = true; - - vert[0] = x; - vert[1] = y; - vert[2] = 0; - vert[3] = 0; - vert[4] = 0; - - // fill and stroke color - vert[5] = currentFillColor; - vert[6] = currentStrokeColor; - - vertArray.push(vert); - if (moveTo) { - vertArray[vertArray.length-1].moveTo = moveTo; - } - }; - - Drawing3D.prototype.vertex = function(x, y, z, u, v) { - var vert = []; - - if (firstVert) { firstVert = false; } - vert.isVert = true; - - if (v === undef && usingTexture) { - v = u; - u = z; - z = 0; - } - - // Convert u and v to normalized coordinates - if (u !== undef && v !== undef) { - if (curTextureMode === PConstants.IMAGE) { - u /= curTexture.width; - v /= curTexture.height; - } - u = u > 1 ? 1 : u; - u = u < 0 ? 0 : u; - v = v > 1 ? 1 : v; - v = v < 0 ? 0 : v; - } - - vert[0] = x; - vert[1] = y; - vert[2] = z || 0; - vert[3] = u || 0; - vert[4] = v || 0; - - // fill rgba - vert[5] = fillStyle[0]; - vert[6] = fillStyle[1]; - vert[7] = fillStyle[2]; - vert[8] = fillStyle[3]; - // stroke rgba - vert[9] = strokeStyle[0]; - vert[10] = strokeStyle[1]; - vert[11] = strokeStyle[2]; - vert[12] = strokeStyle[3]; - //normals - vert[13] = normalX; - vert[14] = normalY; - vert[15] = normalZ; - - vertArray.push(vert); - }; - - /** - * @private - * Renders 3D points created from calls to vertex and beginShape/endShape - * - * @param {Array} vArray an array of vertex coordinate - * @param {Array} cArray an array of colours used for the vertices - * - * @see beginShape - * @see endShape - * @see vertex - */ - var point3D = function(vArray, cArray){ - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - curContext.useProgram(programObjectUnlitShape); - - uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array()); - uniformi("uSmoothUS", programObjectUnlitShape, "uSmooth", renderSmooth); - - vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, pointBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); - - vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, fillColorBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); - - curContext.drawArrays(curContext.POINTS, 0, vArray.length/3); - }; - - /** - * @private - * Renders 3D lines created from calls to beginShape/vertex/endShape - based on the mode specified LINES, LINE_LOOP, etc. - * - * @param {Array} vArray an array of vertex coordinate - * @param {String} mode either LINES, LINE_LOOP, or LINE_STRIP - * @param {Array} cArray an array of colours used for the vertices - * - * @see beginShape - * @see endShape - * @see vertex - */ - var line3D = function(vArray, mode, cArray){ - var ctxMode; - if (mode === "LINES"){ - ctxMode = curContext.LINES; - } - else if(mode === "LINE_LOOP"){ - ctxMode = curContext.LINE_LOOP; - } - else{ - ctxMode = curContext.LINE_STRIP; - } - - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array()); - vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, lineBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); - vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, strokeColorBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); - curContext.drawArrays(ctxMode, 0, vArray.length/3); - }; - - /** - * @private - * Render filled shapes created from calls to beginShape/vertex/endShape - based on the mode specified TRIANGLES, etc. - * - * @param {Array} vArray an array of vertex coordinate - * @param {String} mode either LINES, LINE_LOOP, or LINE_STRIP - * @param {Array} cArray an array of colours used for the vertices - * @param {Array} tArray an array of u,v coordinates for textures - * - * @see beginShape - * @see endShape - * @see vertex - */ - var fill3D = function(vArray, mode, cArray, tArray){ - var ctxMode; - if (mode === "TRIANGLES") { - ctxMode = curContext.TRIANGLES; - } else if(mode === "TRIANGLE_FAN") { - ctxMode = curContext.TRIANGLE_FAN; - } else { - ctxMode = curContext.TRIANGLE_STRIP; - } - - var view = new PMatrix3D(); - view.scale( 1, -1, 1 ); - view.apply( modelView.array() ); - view.transpose(); - - curContext.useProgram( programObject3D ); - uniformMatrix( "model3d", programObject3D, "uModel", false, [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] ); - uniformMatrix( "view3d", programObject3D, "uView", false, view.array() ); - curContext.enable( curContext.POLYGON_OFFSET_FILL ); - curContext.polygonOffset( 1, 1 ); - uniformf( "color3d", programObject3D, "uColor", [-1,0,0,0] ); - vertexAttribPointer( "vertex3d", programObject3D, "aVertex", 3, fillBuffer ); - curContext.bufferData( curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW ); - - // if we are using a texture and a tint, then overwrite the - // contents of the color buffer with the current tint - if ( usingTexture && curTint !== null ){ - curTint3d( cArray ); - } - - vertexAttribPointer( "aColor3d", programObject3D, "aColor", 4, fillColorBuffer ); - curContext.bufferData( curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW ); - - // No support for lights....yet - disableVertexAttribPointer( "aNormal3d", programObject3D, "aNormal" ); - - if ( usingTexture ) { - uniformi( "uUsingTexture3d", programObject3D, "uUsingTexture", usingTexture ); - vertexAttribPointer( "aTexture3d", programObject3D, "aTexture", 2, shapeTexVBO ); - curContext.bufferData( curContext.ARRAY_BUFFER, new Float32Array(tArray), curContext.STREAM_DRAW ); - } - - curContext.drawArrays( ctxMode, 0, vArray.length/3 ); - curContext.disable( curContext.POLYGON_OFFSET_FILL ); - }; - - /** - * this series of three operations is used a lot in Drawing2D.prototype.endShape - * and has been split off as its own function, to tighten the code and allow for - * fewer bugs. - */ - function fillStrokeClose() { - executeContextFill(); - executeContextStroke(); - curContext.closePath(); - } - - /** - * The endShape() function is the companion to beginShape() and may only be called after beginShape(). - * When endshape() is called, all of image data defined since the previous call to beginShape() is written - * into the image buffer. - * - * @param {int} MODE Use CLOSE to close the shape - * - * @see beginShape - */ - Drawing2D.prototype.endShape = function(mode) { - // Duplicated in Drawing3D; too many variables used - if (vertArray.length === 0) { return; } - - var closeShape = mode === PConstants.CLOSE; - - // if the shape is closed, the first element is also the last element - if (closeShape) { - vertArray.push(vertArray[0]); - } - - var lineVertArray = []; - var fillVertArray = []; - var colorVertArray = []; - var strokeVertArray = []; - var texVertArray = []; - var cachedVertArray; - - firstVert = true; - var i, j, k; - var vertArrayLength = vertArray.length; - - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - fillVertArray.push(cachedVertArray[j]); - } - } - - // 5,6,7,8 - // R,G,B,A - fill colour - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 5; j < 9; j++) { - colorVertArray.push(cachedVertArray[j]); - } - } - - // 9,10,11,12 - // R, G, B, A - stroke colour - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) { - strokeVertArray.push(cachedVertArray[j]); - } - } - - // texture u,v - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - texVertArray.push(cachedVertArray[3]); - texVertArray.push(cachedVertArray[4]); - } - - // curveVertex - if ( isCurve && (curShape === PConstants.POLYGON || curShape === undef) ) { - if (vertArrayLength > 3) { - var b = [], - s = 1 - curTightness; - curContext.beginPath(); - curContext.moveTo(vertArray[1][0], vertArray[1][1]); - /* - * Matrix to convert from Catmull-Rom to cubic Bezier - * where t = curTightness - * |0 1 0 0 | - * |(t-1)/6 1 (1-t)/6 0 | - * |0 (1-t)/6 1 (t-1)/6 | - * |0 0 0 0 | - */ - for (i = 1; (i+2) < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - b[0] = [cachedVertArray[0], cachedVertArray[1]]; - b[1] = [cachedVertArray[0] + (s * vertArray[i+1][0] - s * vertArray[i-1][0]) / 6, - cachedVertArray[1] + (s * vertArray[i+1][1] - s * vertArray[i-1][1]) / 6]; - b[2] = [vertArray[i+1][0] + (s * vertArray[i][0] - s * vertArray[i+2][0]) / 6, - vertArray[i+1][1] + (s * vertArray[i][1] - s * vertArray[i+2][1]) / 6]; - b[3] = [vertArray[i+1][0], vertArray[i+1][1]]; - curContext.bezierCurveTo(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]); - } - fillStrokeClose(); - } - } - - // bezierVertex - else if ( isBezier && (curShape === PConstants.POLYGON || curShape === undef) ) { - curContext.beginPath(); - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - if (vertArray[i].isVert) { //if it is a vertex move to the position - if (vertArray[i].moveTo) { - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - } else { - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - } - } else { //otherwise continue drawing bezier - curContext.bezierCurveTo(vertArray[i][0], vertArray[i][1], vertArray[i][2], vertArray[i][3], vertArray[i][4], vertArray[i][5]); - } - } - fillStrokeClose(); - } - - // render the vertices provided - else { - if (curShape === PConstants.POINTS) { - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - if (doStroke) { - p.stroke(cachedVertArray[6]); - } - p.point(cachedVertArray[0], cachedVertArray[1]); - } - } else if (curShape === PConstants.LINES) { - for (i = 0; (i + 1) < vertArrayLength; i+=2) { - cachedVertArray = vertArray[i]; - if (doStroke) { - p.stroke(vertArray[i+1][6]); - } - p.line(cachedVertArray[0], cachedVertArray[1], vertArray[i+1][0], vertArray[i+1][1]); - } - } else if (curShape === PConstants.TRIANGLES) { - for (i = 0; (i + 2) < vertArrayLength; i+=3) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]); - curContext.lineTo(vertArray[i+2][0], vertArray[i+2][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - - if (doFill) { - p.fill(vertArray[i+2][5]); - executeContextFill(); - } - if (doStroke) { - p.stroke(vertArray[i+2][6]); - executeContextStroke(); - } - - curContext.closePath(); - } - } else if (curShape === PConstants.TRIANGLE_STRIP) { - for (i = 0; (i+1) < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(vertArray[i+1][0], vertArray[i+1][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - - if (doStroke) { - p.stroke(vertArray[i+1][6]); - } - if (doFill) { - p.fill(vertArray[i+1][5]); - } - - if (i + 2 < vertArrayLength) { - curContext.lineTo(vertArray[i+2][0], vertArray[i+2][1]); - if (doStroke) { - p.stroke(vertArray[i+2][6]); - } - if (doFill) { - p.fill(vertArray[i+2][5]); - } - } - fillStrokeClose(); - } - } else if (curShape === PConstants.TRIANGLE_FAN) { - if (vertArrayLength > 2) { - curContext.beginPath(); - curContext.moveTo(vertArray[0][0], vertArray[0][1]); - curContext.lineTo(vertArray[1][0], vertArray[1][1]); - curContext.lineTo(vertArray[2][0], vertArray[2][1]); - - if (doFill) { - p.fill(vertArray[2][5]); - executeContextFill(); - } - if (doStroke) { - p.stroke(vertArray[2][6]); - executeContextStroke(); - } - - curContext.closePath(); - for (i = 3; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(vertArray[0][0], vertArray[0][1]); - curContext.lineTo(vertArray[i-1][0], vertArray[i-1][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - - if (doFill) { - p.fill(cachedVertArray[5]); - executeContextFill(); - } - if (doStroke) { - p.stroke(cachedVertArray[6]); - executeContextStroke(); - } - - curContext.closePath(); - } - } - } else if (curShape === PConstants.QUADS) { - for (i = 0; (i + 3) < vertArrayLength; i+=4) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - for (j = 1; j < 4; j++) { - curContext.lineTo(vertArray[i+j][0], vertArray[i+j][1]); - } - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - - if (doFill) { - p.fill(vertArray[i+3][5]); - executeContextFill(); - } - if (doStroke) { - p.stroke(vertArray[i+3][6]); - executeContextStroke(); - } - - curContext.closePath(); - } - } else if (curShape === PConstants.QUAD_STRIP) { - if (vertArrayLength > 3) { - for (i = 0; (i+1) < vertArrayLength; i+=2) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - if (i+3 < vertArrayLength) { - curContext.moveTo(vertArray[i+2][0], vertArray[i+2][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]); - curContext.lineTo(vertArray[i+3][0], vertArray[i+3][1]); - - if (doFill) { - p.fill(vertArray[i+3][5]); - } - if (doStroke) { - p.stroke(vertArray[i+3][6]); - } - } else { - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]); - } - fillStrokeClose(); - } - } - } else { - curContext.beginPath(); - curContext.moveTo(vertArray[0][0], vertArray[0][1]); - for (i = 1; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - if (cachedVertArray.isVert) { //if it is a vertex move to the position - if (cachedVertArray.moveTo) { - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - } else { - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - } - } - } - fillStrokeClose(); - } - } - - // Reset some settings - isCurve = false; - isBezier = false; - curveVertArray = []; - curveVertCount = 0; - - // If the shape is closed, the first element was added as last element. - // We must remove it again to prevent the list of vertices from growing - // over successive calls to endShape(CLOSE) - if (closeShape) { - vertArray.pop(); - } - }; - - Drawing3D.prototype.endShape = function(mode) { - // Duplicated in Drawing3D; too many variables used - if (vertArray.length === 0) { return; } - - var closeShape = mode === PConstants.CLOSE; - var lineVertArray = []; - var fillVertArray = []; - var colorVertArray = []; - var strokeVertArray = []; - var texVertArray = []; - var cachedVertArray; - - firstVert = true; - var i, j, k; - var vertArrayLength = vertArray.length; - - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - fillVertArray.push(cachedVertArray[j]); - } - } - - // 5,6,7,8 - // R,G,B,A - fill colour - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 5; j < 9; j++) { - colorVertArray.push(cachedVertArray[j]); - } - } - - // 9,10,11,12 - // R, G, B, A - stroke colour - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) { - strokeVertArray.push(cachedVertArray[j]); - } - } - - // texture u,v - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - texVertArray.push(cachedVertArray[3]); - texVertArray.push(cachedVertArray[4]); - } - - // if shape is closed, push the first point into the last point (including colours) - if (closeShape) { - fillVertArray.push(vertArray[0][0]); - fillVertArray.push(vertArray[0][1]); - fillVertArray.push(vertArray[0][2]); - - for (i = 5; i < 9; i++) { - colorVertArray.push(vertArray[0][i]); - } - - for (i = 9; i < 13; i++) { - strokeVertArray.push(vertArray[0][i]); - } - - texVertArray.push(vertArray[0][3]); - texVertArray.push(vertArray[0][4]); - } - // End duplication - - // curveVertex - if ( isCurve && (curShape === PConstants.POLYGON || curShape === undef) ) { - lineVertArray = fillVertArray; - if (doStroke) { - line3D(lineVertArray, null, strokeVertArray); - } - if (doFill) { - fill3D(fillVertArray, null, colorVertArray); - } - } - // bezierVertex - else if ( isBezier && (curShape === PConstants.POLYGON || curShape === undef) ) { - lineVertArray = fillVertArray; - lineVertArray.splice(lineVertArray.length - 3); - strokeVertArray.splice(strokeVertArray.length - 4); - if (doStroke) { - line3D(lineVertArray, null, strokeVertArray); - } - if (doFill) { - fill3D(fillVertArray, "TRIANGLES", colorVertArray); - } - } - - // render the vertices provided - else { - if (curShape === PConstants.POINTS) { // if POINTS was the specified parameter in beginShape - for (i = 0; i < vertArrayLength; i++) { // loop through and push the point location information to the array - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - lineVertArray.push(cachedVertArray[j]); - } - } - point3D(lineVertArray, strokeVertArray); // render function for points - } else if (curShape === PConstants.LINES) { // if LINES was the specified parameter in beginShape - for (i = 0; i < vertArrayLength; i++) { // loop through and push the point location information to the array - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - lineVertArray.push(cachedVertArray[j]); - } - } - for (i = 0; i < vertArrayLength; i++) { // loop through and push the color information to the array - cachedVertArray = vertArray[i]; - for (j = 5; j < 9; j++) { - colorVertArray.push(cachedVertArray[j]); - } - } - line3D(lineVertArray, "LINES", strokeVertArray); // render function for lines - } else if (curShape === PConstants.TRIANGLES) { // if TRIANGLES was the specified parameter in beginShape - if (vertArrayLength > 2) { - for (i = 0; (i+2) < vertArrayLength; i+=3) { // loop through the array per triangle - fillVertArray = []; - texVertArray = []; - lineVertArray = []; - colorVertArray = []; - strokeVertArray = []; - for (j = 0; j < 3; j++) { - for (k = 0; k < 3; k++) { // loop through and push - lineVertArray.push(vertArray[i+j][k]); // the line point location information - fillVertArray.push(vertArray[i+j][k]); // and fill point location information - } - } - for (j = 0; j < 3; j++) { // loop through and push the texture information - for (k = 3; k < 5; k++) { - texVertArray.push(vertArray[i+j][k]); - } - } - for (j = 0; j < 3; j++) { - for (k = 5; k < 9; k++) { // loop through and push - colorVertArray.push(vertArray[i+j][k]); // the colour information - strokeVertArray.push(vertArray[i+j][k+4]);// and the stroke information - } - } - if (doStroke) { - line3D(lineVertArray, "LINE_LOOP", strokeVertArray ); // line render function - } - if (doFill || usingTexture) { - fill3D(fillVertArray, "TRIANGLES", colorVertArray, texVertArray); // fill shape render function - } - } - } - } else if (curShape === PConstants.TRIANGLE_STRIP) { // if TRIANGLE_STRIP was the specified parameter in beginShape - if (vertArrayLength > 2) { - for (i = 0; (i+2) < vertArrayLength; i++) { - lineVertArray = []; - fillVertArray = []; - strokeVertArray = []; - colorVertArray = []; - texVertArray = []; - for (j = 0; j < 3; j++) { - for (k = 0; k < 3; k++) { - lineVertArray.push(vertArray[i+j][k]); - fillVertArray.push(vertArray[i+j][k]); - } - } - for (j = 0; j < 3; j++) { - for (k = 3; k < 5; k++) { - texVertArray.push(vertArray[i+j][k]); - } - } - for (j = 0; j < 3; j++) { - for (k = 5; k < 9; k++) { - strokeVertArray.push(vertArray[i+j][k+4]); - colorVertArray.push(vertArray[i+j][k]); - } - } - - if (doFill || usingTexture) { - fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray); - } - if (doStroke) { - line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - } - } - } - } else if (curShape === PConstants.TRIANGLE_FAN) { - if (vertArrayLength > 2) { - for (i = 0; i < 3; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - lineVertArray.push(cachedVertArray[j]); - } - } - for (i = 0; i < 3; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) { - strokeVertArray.push(cachedVertArray[j]); - } - } - if (doStroke) { - line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - } - - for (i = 2; (i+1) < vertArrayLength; i++) { - lineVertArray = []; - strokeVertArray = []; - lineVertArray.push(vertArray[0][0]); - lineVertArray.push(vertArray[0][1]); - lineVertArray.push(vertArray[0][2]); - - strokeVertArray.push(vertArray[0][9]); - strokeVertArray.push(vertArray[0][10]); - strokeVertArray.push(vertArray[0][11]); - strokeVertArray.push(vertArray[0][12]); - - for (j = 0; j < 2; j++) { - for (k = 0; k < 3; k++) { - lineVertArray.push(vertArray[i+j][k]); - } - } - for (j = 0; j < 2; j++) { - for (k = 9; k < 13; k++) { - strokeVertArray.push(vertArray[i+j][k]); - } - } - if (doStroke) { - line3D(lineVertArray, "LINE_STRIP",strokeVertArray); - } - } - if (doFill || usingTexture) { - fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray); - } - } - } else if (curShape === PConstants.QUADS) { - for (i = 0; (i + 3) < vertArrayLength; i+=4) { - lineVertArray = []; - for (j = 0; j < 4; j++) { - cachedVertArray = vertArray[i+j]; - for (k = 0; k < 3; k++) { - lineVertArray.push(cachedVertArray[k]); - } - } - if (doStroke) { - line3D(lineVertArray, "LINE_LOOP",strokeVertArray); - } - - if (doFill) { - fillVertArray = []; - colorVertArray = []; - texVertArray = []; - for (j = 0; j < 3; j++) { - fillVertArray.push(vertArray[i][j]); - } - for (j = 5; j < 9; j++) { - colorVertArray.push(vertArray[i][j]); - } - - for (j = 0; j < 3; j++) { - fillVertArray.push(vertArray[i+1][j]); - } - for (j = 5; j < 9; j++) { - colorVertArray.push(vertArray[i+1][j]); - } - - for (j = 0; j < 3; j++) { - fillVertArray.push(vertArray[i+3][j]); - } - for (j = 5; j < 9; j++) { - colorVertArray.push(vertArray[i+3][j]); - } - - for (j = 0; j < 3; j++) { - fillVertArray.push(vertArray[i+2][j]); - } - for (j = 5; j < 9; j++) { - colorVertArray.push(vertArray[i+2][j]); - } - - if (usingTexture) { - texVertArray.push(vertArray[i+0][3]); - texVertArray.push(vertArray[i+0][4]); - texVertArray.push(vertArray[i+1][3]); - texVertArray.push(vertArray[i+1][4]); - texVertArray.push(vertArray[i+3][3]); - texVertArray.push(vertArray[i+3][4]); - texVertArray.push(vertArray[i+2][3]); - texVertArray.push(vertArray[i+2][4]); - } - - fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray); - } - } - } else if (curShape === PConstants.QUAD_STRIP) { - var tempArray = []; - if (vertArrayLength > 3) { - for (i = 0; i < 2; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - lineVertArray.push(cachedVertArray[j]); - } - } - - for (i = 0; i < 2; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) { - strokeVertArray.push(cachedVertArray[j]); - } - } - - line3D(lineVertArray, "LINE_STRIP", strokeVertArray); - if (vertArrayLength > 4 && vertArrayLength % 2 > 0) { - tempArray = fillVertArray.splice(fillVertArray.length - 3); - vertArray.pop(); - } - for (i = 0; (i+3) < vertArrayLength; i+=2) { - lineVertArray = []; - strokeVertArray = []; - for (j = 0; j < 3; j++) { - lineVertArray.push(vertArray[i+1][j]); - } - for (j = 0; j < 3; j++) { - lineVertArray.push(vertArray[i+3][j]); - } - for (j = 0; j < 3; j++) { - lineVertArray.push(vertArray[i+2][j]); - } - for (j = 0; j < 3; j++) { - lineVertArray.push(vertArray[i+0][j]); - } - for (j = 9; j < 13; j++) { - strokeVertArray.push(vertArray[i+1][j]); - } - for (j = 9; j < 13; j++) { - strokeVertArray.push(vertArray[i+3][j]); - } - for (j = 9; j < 13; j++) { - strokeVertArray.push(vertArray[i+2][j]); - } - for (j = 9; j < 13; j++) { - strokeVertArray.push(vertArray[i+0][j]); - } - if (doStroke) { - line3D(lineVertArray, "LINE_STRIP", strokeVertArray); - } - } - - if (doFill || usingTexture) { - fill3D(fillVertArray, "TRIANGLE_LIST", colorVertArray, texVertArray); - } - } - } - // If the user didn't specify a type (LINES, TRIANGLES, etc) - else { - // If only one vertex was specified, it must be a point - if (vertArrayLength === 1) { - for (j = 0; j < 3; j++) { - lineVertArray.push(vertArray[0][j]); - } - for (j = 9; j < 13; j++) { - strokeVertArray.push(vertArray[0][j]); - } - point3D(lineVertArray,strokeVertArray); - } else { - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) { - lineVertArray.push(cachedVertArray[j]); - } - for (j = 5; j < 9; j++) { - strokeVertArray.push(cachedVertArray[j]); - } - } - if (doStroke && closeShape) { - line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - } else if (doStroke && !closeShape) { - line3D(lineVertArray, "LINE_STRIP", strokeVertArray); - } - - // fill is ignored if textures are used - if (doFill || usingTexture) { - fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray); - } - } - } - // everytime beginShape is followed by a call to - // texture(), texturing it turned back on. We do this to - // figure out if the shape should be textured or filled - // with a color. - usingTexture = false; - curContext.useProgram(programObject3D); - uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture); - } - - // Reset some settings - isCurve = false; - isBezier = false; - curveVertArray = []; - curveVertCount = 0; - }; - - /** - * The function splineForward() setup forward-differencing matrix to be used for speedy - * curve rendering. It's based on using a specific number - * of curve segments and just doing incremental adds for each - * vertex of the segment, rather than running the mathematically - * expensive cubic equation. This function is used by both curveDetail and bezierDetail. - * - * @param {int} segments number of curve segments to use when drawing - * @param {PMatrix3D} matrix target object for the new matrix - */ - var splineForward = function(segments, matrix) { - var f = 1.0 / segments; - var ff = f * f; - var fff = ff * f; - - matrix.set(0, 0, 0, 1, fff, ff, f, 0, 6 * fff, 2 * ff, 0, 0, 6 * fff, 0, 0, 0); - }; - - /** - * The curveInit() function set the number of segments to use when drawing a Catmull-Rom - * curve, and setting the s parameter, which defines how tightly - * the curve fits to each vertex. Catmull-Rom curves are actually - * a subset of this curve type where the s is set to zero. - * This in an internal function used by curveDetail() and curveTightness(). - */ - var curveInit = function() { - // allocate only if/when used to save startup time - if (!curveDrawMatrix) { - curveBasisMatrix = new PMatrix3D(); - curveDrawMatrix = new PMatrix3D(); - curveInited = true; - } - - var s = curTightness; - curveBasisMatrix.set((s - 1) / 2, (s + 3) / 2, (-3 - s) / 2, (1 - s) / 2, - (1 - s), (-5 - s) / 2, (s + 2), (s - 1) / 2, - (s - 1) / 2, 0, (1 - s) / 2, 0, 0, 1, 0, 0); - - splineForward(curveDet, curveDrawMatrix); - - if (!bezierBasisInverse) { - //bezierBasisInverse = bezierBasisMatrix.get(); - //bezierBasisInverse.invert(); - curveToBezierMatrix = new PMatrix3D(); - } - - // TODO only needed for PGraphicsJava2D? if so, move it there - // actually, it's generally useful for other renderers, so keep it - // or hide the implementation elsewhere. - curveToBezierMatrix.set(curveBasisMatrix); - curveToBezierMatrix.preApply(bezierBasisInverse); - - // multiply the basis and forward diff matrices together - // saves much time since this needn't be done for each curve - curveDrawMatrix.apply(curveBasisMatrix); - }; - - /** - * Specifies vertex coordinates for Bezier curves. Each call to <b>bezierVertex()</b> defines the position of two control - * points and one anchor point of a Bezier curve, adding a new segment to a line or shape. The first time - * <b>bezierVertex()</b> is used within a <b>beginShape()</b> call, it must be prefaced with a call to <b>vertex()</b> - * to set the first anchor point. This function must be used between <b>beginShape()</b> and <b>endShape()</b> and only - * when there is no MODE parameter specified to <b>beginShape()</b>. Using the 3D version of requires rendering with P3D - * or OPENGL (see the Environment reference for more information). <br /> <br /> <b>NOTE: </b> Fill does not work properly yet. - * - * @param {float | int} cx1 The x-coordinate of 1st control point - * @param {float | int} cy1 The y-coordinate of 1st control point - * @param {float | int} cz1 The z-coordinate of 1st control point - * @param {float | int} cx2 The x-coordinate of 2nd control point - * @param {float | int} cy2 The y-coordinate of 2nd control point - * @param {float | int} cz2 The z-coordinate of 2nd control point - * @param {float | int} x The x-coordinate of the anchor point - * @param {float | int} y The y-coordinate of the anchor point - * @param {float | int} z The z-coordinate of the anchor point - * - * @see curveVertex - * @see vertex - * @see bezier - */ - Drawing2D.prototype.bezierVertex = function() { - isBezier = true; - var vert = []; - if (firstVert) { - throw ("vertex() must be used at least once before calling bezierVertex()"); - } - - for (var i = 0; i < arguments.length; i++) { - vert[i] = arguments[i]; - } - vertArray.push(vert); - vertArray[vertArray.length -1].isVert = false; - }; - - Drawing3D.prototype.bezierVertex = function() { - isBezier = true; - var vert = []; - if (firstVert) { - throw ("vertex() must be used at least once before calling bezierVertex()"); - } - - if (arguments.length === 9) { - if (bezierDrawMatrix === undef) { - bezierDrawMatrix = new PMatrix3D(); - } - // setup matrix for forward differencing to speed up drawing - var lastPoint = vertArray.length - 1; - splineForward( bezDetail, bezierDrawMatrix ); - bezierDrawMatrix.apply( bezierBasisMatrix ); - var draw = bezierDrawMatrix.array(); - var x1 = vertArray[lastPoint][0], - y1 = vertArray[lastPoint][1], - z1 = vertArray[lastPoint][2]; - var xplot1 = draw[4] * x1 + draw[5] * arguments[0] + draw[6] * arguments[3] + draw[7] * arguments[6]; - var xplot2 = draw[8] * x1 + draw[9] * arguments[0] + draw[10]* arguments[3] + draw[11]* arguments[6]; - var xplot3 = draw[12]* x1 + draw[13]* arguments[0] + draw[14]* arguments[3] + draw[15]* arguments[6]; - - var yplot1 = draw[4] * y1 + draw[5] * arguments[1] + draw[6] * arguments[4] + draw[7] * arguments[7]; - var yplot2 = draw[8] * y1 + draw[9] * arguments[1] + draw[10]* arguments[4] + draw[11]* arguments[7]; - var yplot3 = draw[12]* y1 + draw[13]* arguments[1] + draw[14]* arguments[4] + draw[15]* arguments[7]; - - var zplot1 = draw[4] * z1 + draw[5] * arguments[2] + draw[6] * arguments[5] + draw[7] * arguments[8]; - var zplot2 = draw[8] * z1 + draw[9] * arguments[2] + draw[10]* arguments[5] + draw[11]* arguments[8]; - var zplot3 = draw[12]* z1 + draw[13]* arguments[2] + draw[14]* arguments[5] + draw[15]* arguments[8]; - for (var j = 0; j < bezDetail; j++) { - x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; - y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; - z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; - p.vertex(x1, y1, z1); - } - p.vertex(arguments[6], arguments[7], arguments[8]); - } - }; - - /** - * Sets a texture to be applied to vertex points. The <b>texture()</b> function - * must be called between <b>beginShape()</b> and <b>endShape()</b> and before - * any calls to vertex(). - * - * When textures are in use, the fill color is ignored. Instead, use tint() to - * specify the color of the texture as it is applied to the shape. - * - * @param {PImage} pimage the texture to apply - * - * @returns none - * - * @see textureMode - * @see beginShape - * @see endShape - * @see vertex - */ - p.texture = function(pimage) { - var curContext = drawing.$ensureContext(); - - if (pimage.__texture) { - curContext.bindTexture(curContext.TEXTURE_2D, pimage.__texture); - } else if (pimage.localName === "canvas") { - curContext.bindTexture(curContext.TEXTURE_2D, canTex); - curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, pimage); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR); - curContext.generateMipmap(curContext.TEXTURE_2D); - curTexture.width = pimage.width; - curTexture.height = pimage.height; - } else { - var texture = curContext.createTexture(), - cvs = document.createElement('canvas'), - cvsTextureCtx = cvs.getContext('2d'), - pot; - - // WebGL requires power of two textures - if (pimage.width & (pimage.width-1) === 0) { - cvs.width = pimage.width; - } else { - pot = 1; - while (pot < pimage.width) { - pot *= 2; - } - cvs.width = pot; - } - - if (pimage.height & (pimage.height-1) === 0) { - cvs.height = pimage.height; - } else { - pot = 1; - while (pot < pimage.height) { - pot *= 2; - } - cvs.height = pot; - } - - cvsTextureCtx.drawImage(pimage.sourceImg, 0, 0, pimage.width, pimage.height, 0, 0, cvs.width, cvs.height); - - curContext.bindTexture(curContext.TEXTURE_2D, texture); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR_MIPMAP_LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); - curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, cvs); - curContext.generateMipmap(curContext.TEXTURE_2D); - - pimage.__texture = texture; - curTexture.width = pimage.width; - curTexture.height = pimage.height; - } - - usingTexture = true; - curContext.useProgram(programObject3D); - uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture); - }; - - /** - * Sets the coordinate space for texture mapping. There are two options, IMAGE, - * which refers to the actual coordinates of the image, and NORMALIZED, which - * refers to a normalized space of values ranging from 0 to 1. The default mode - * is IMAGE. In IMAGE, if an image is 100 x 200 pixels, mapping the image onto - * the entire size of a quad would require the points (0,0) (0,100) (100,200) (0,200). - * The same mapping in NORMAL_SPACE is (0,0) (0,1) (1,1) (0,1). - * - * @param MODE either IMAGE or NORMALIZED - * - * @returns none - * - * @see texture - */ - p.textureMode = function(mode){ - curTextureMode = mode; - }; - /** - * The curveVertexSegment() function handle emitting a specific segment of Catmull-Rom curve. Internal helper function used by <b>curveVertex()</b>. - */ - var curveVertexSegment = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { - var x0 = x2; - var y0 = y2; - var z0 = z2; - - var draw = curveDrawMatrix.array(); - - var xplot1 = draw[4] * x1 + draw[5] * x2 + draw[6] * x3 + draw[7] * x4; - var xplot2 = draw[8] * x1 + draw[9] * x2 + draw[10] * x3 + draw[11] * x4; - var xplot3 = draw[12] * x1 + draw[13] * x2 + draw[14] * x3 + draw[15] * x4; - - var yplot1 = draw[4] * y1 + draw[5] * y2 + draw[6] * y3 + draw[7] * y4; - var yplot2 = draw[8] * y1 + draw[9] * y2 + draw[10] * y3 + draw[11] * y4; - var yplot3 = draw[12] * y1 + draw[13] * y2 + draw[14] * y3 + draw[15] * y4; - - var zplot1 = draw[4] * z1 + draw[5] * z2 + draw[6] * z3 + draw[7] * z4; - var zplot2 = draw[8] * z1 + draw[9] * z2 + draw[10] * z3 + draw[11] * z4; - var zplot3 = draw[12] * z1 + draw[13] * z2 + draw[14] * z3 + draw[15] * z4; - - p.vertex(x0, y0, z0); - for (var j = 0; j < curveDet; j++) { - x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3; - y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3; - z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3; - p.vertex(x0, y0, z0); - } - }; - - /** - * Specifies vertex coordinates for curves. This function may only be used between <b>beginShape()</b> and - * <b>endShape()</b> and only when there is no MODE parameter specified to <b>beginShape()</b>. The first and last points - * in a series of <b>curveVertex()</b> lines will be used to guide the beginning and end of a the curve. A minimum of four - * points is required to draw a tiny curve between the second and third points. Adding a fifth point with - * <b>curveVertex()</b> will draw the curve between the second, third, and fourth points. The <b>curveVertex()</b> function - * is an implementation of Catmull-Rom splines. Using the 3D version of requires rendering with P3D or OPENGL (see the - * Environment reference for more information). <br /> <br /><b>NOTE: </b> Fill does not work properly yet. - * - * @param {float | int} x The x-coordinate of the vertex - * @param {float | int} y The y-coordinate of the vertex - * @param {float | int} z The z-coordinate of the vertex - * - * @see curve - * @see beginShape - * @see endShape - * @see vertex - * @see bezierVertex - */ - Drawing2D.prototype.curveVertex = function(x, y) { - isCurve = true; - - p.vertex(x, y); - }; - - Drawing3D.prototype.curveVertex = function(x, y, z) { - isCurve = true; - - if (!curveInited) { - curveInit(); - } - var vert = []; - vert[0] = x; - vert[1] = y; - vert[2] = z; - curveVertArray.push(vert); - curveVertCount++; - - if (curveVertCount > 3) { - curveVertexSegment( curveVertArray[curveVertCount-4][0], - curveVertArray[curveVertCount-4][1], - curveVertArray[curveVertCount-4][2], - curveVertArray[curveVertCount-3][0], - curveVertArray[curveVertCount-3][1], - curveVertArray[curveVertCount-3][2], - curveVertArray[curveVertCount-2][0], - curveVertArray[curveVertCount-2][1], - curveVertArray[curveVertCount-2][2], - curveVertArray[curveVertCount-1][0], - curveVertArray[curveVertCount-1][1], - curveVertArray[curveVertCount-1][2] ); - } - }; - - /** - * The curve() function draws a curved line on the screen. The first and second parameters - * specify the beginning control point and the last two parameters specify - * the ending control point. The middle parameters specify the start and - * stop of the curve. Longer curves can be created by putting a series of - * <b>curve()</b> functions together or using <b>curveVertex()</b>. - * An additional function called <b>curveTightness()</b> provides control - * for the visual quality of the curve. The <b>curve()</b> function is an - * implementation of Catmull-Rom splines. Using the 3D version of requires - * rendering with P3D or OPENGL (see the Environment reference for more - * information). - * - * @param {int|float} x1 coordinates for the beginning control point - * @param {int|float} y1 coordinates for the beginning control point - * @param {int|float} z1 coordinates for the beginning control point - * @param {int|float} x2 coordinates for the first point - * @param {int|float} y2 coordinates for the first point - * @param {int|float} z2 coordinates for the first point - * @param {int|float} x3 coordinates for the second point - * @param {int|float} y3 coordinates for the second point - * @param {int|float} z3 coordinates for the second point - * @param {int|float} x4 coordinates for the ending control point - * @param {int|float} y4 coordinates for the ending control point - * @param {int|float} z4 coordinates for the ending control point - * - * @see #curveVertex() - * @see #curveTightness() - * @see #bezier() - */ - Drawing2D.prototype.curve = function(x1, y1, x2, y2, x3, y3, x4, y4) { - p.beginShape(); - p.curveVertex(x1, y1); - p.curveVertex(x2, y2); - p.curveVertex(x3, y3); - p.curveVertex(x4, y4); - p.endShape(); - }; - - Drawing3D.prototype.curve = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { - if (z4 !== undef) { - p.beginShape(); - p.curveVertex(x1, y1, z1); - p.curveVertex(x2, y2, z2); - p.curveVertex(x3, y3, z3); - p.curveVertex(x4, y4, z4); - p.endShape(); - return; - } - p.beginShape(); - p.curveVertex(x1, y1); - p.curveVertex(z1, x2); - p.curveVertex(y2, z2); - p.curveVertex(x3, y3); - p.endShape(); - }; - - /** - * The curveTightness() function modifies the quality of forms created with <b>curve()</b> and - * <b>curveVertex()</b>. The parameter <b>squishy</b> determines how the - * curve fits to the vertex points. The value 0.0 is the default value for - * <b>squishy</b> (this value defines the curves to be Catmull-Rom splines) - * and the value 1.0 connects all the points with straight lines. - * Values within the range -5.0 and 5.0 will deform the curves but - * will leave them recognizable and as values increase in magnitude, - * they will continue to deform. - * - * @param {float} tightness amount of deformation from the original vertices - * - * @see #curve() - * @see #curveVertex() - * - */ - p.curveTightness = function(tightness) { - curTightness = tightness; - }; - - /** - * The curveDetail() function sets the resolution at which curves display. The default value is 20. - * This function is only useful when using the P3D or OPENGL renderer. - * - * @param {int} detail resolution of the curves - * - * @see curve() - * @see curveVertex() - * @see curveTightness() - */ - p.curveDetail = function(detail) { - curveDet = detail; - curveInit(); - }; - - /** - * Modifies the location from which rectangles draw. The default mode is rectMode(CORNER), which - * specifies the location to be the upper left corner of the shape and uses the third and fourth - * parameters of rect() to specify the width and height. The syntax rectMode(CORNERS) uses the - * first and second parameters of rect() to set the location of one corner and uses the third and - * fourth parameters to set the opposite corner. The syntax rectMode(CENTER) draws the image from - * its center point and uses the third and forth parameters of rect() to specify the image's width - * and height. The syntax rectMode(RADIUS) draws the image from its center point and uses the third - * and forth parameters of rect() to specify half of the image's width and height. The parameter must - * be written in ALL CAPS because Processing is a case sensitive language. Note: In version 125, the - * mode named CENTER_RADIUS was shortened to RADIUS. - * - * @param {MODE} MODE Either CORNER, CORNERS, CENTER, or RADIUS - * - * @see rect - */ - p.rectMode = function(aRectMode) { - curRectMode = aRectMode; - }; - - /** - * Modifies the location from which images draw. The default mode is imageMode(CORNER), which specifies - * the location to be the upper left corner and uses the fourth and fifth parameters of image() to set - * the image's width and height. The syntax imageMode(CORNERS) uses the second and third parameters of - * image() to set the location of one corner of the image and uses the fourth and fifth parameters to - * set the opposite corner. Use imageMode(CENTER) to draw images centered at the given x and y position. - * The parameter to imageMode() must be written in ALL CAPS because Processing is a case sensitive language. - * - * @param {MODE} MODE Either CORNER, CORNERS, or CENTER - * - * @see loadImage - * @see PImage - * @see image - * @see background - */ - p.imageMode = function(mode) { - switch (mode) { - case PConstants.CORNER: - imageModeConvert = imageModeCorner; - break; - case PConstants.CORNERS: - imageModeConvert = imageModeCorners; - break; - case PConstants.CENTER: - imageModeConvert = imageModeCenter; - break; - default: - throw "Invalid imageMode"; - } - }; - - /** - * The origin of the ellipse is modified by the ellipseMode() function. The default configuration is - * ellipseMode(CENTER), which specifies the location of the ellipse as the center of the shape. The RADIUS - * mode is the same, but the width and height parameters to ellipse() specify the radius of the ellipse, - * rather than the diameter. The CORNER mode draws the shape from the upper-left corner of its bounding box. - * The CORNERS mode uses the four parameters to ellipse() to set two opposing corners of the ellipse's bounding - * box. The parameter must be written in "ALL CAPS" because Processing is a case sensitive language. - * - * @param {MODE} MODE Either CENTER, RADIUS, CORNER, or CORNERS. - * - * @see ellipse - */ - p.ellipseMode = function(aEllipseMode) { - curEllipseMode = aEllipseMode; - }; - - /** - * The arc() function draws an arc in the display window. - * Arcs are drawn along the outer edge of an ellipse defined by the - * <b>x</b>, <b>y</b>, <b>width</b> and <b>height</b> parameters. - * The origin or the arc's ellipse may be changed with the - * <b>ellipseMode()</b> function. - * The <b>start</b> and <b>stop</b> parameters specify the angles - * at which to draw the arc. - * - * @param {float} a x-coordinate of the arc's ellipse - * @param {float} b y-coordinate of the arc's ellipse - * @param {float} c width of the arc's ellipse - * @param {float} d height of the arc's ellipse - * @param {float} start angle to start the arc, specified in radians - * @param {float} stop angle to stop the arc, specified in radians - * - * @see #ellipseMode() - * @see #ellipse() - */ - p.arc = function(x, y, width, height, start, stop) { - if (width <= 0 || stop < start) { return; } - - if (curEllipseMode === PConstants.CORNERS) { - width = width - x; - height = height - y; - } else if (curEllipseMode === PConstants.RADIUS) { - x = x - width; - y = y - height; - width = width * 2; - height = height * 2; - } else if (curEllipseMode === PConstants.CENTER) { - x = x - width/2; - y = y - height/2; - } - // make sure that we're starting at a useful point - while (start < 0) { - start += PConstants.TWO_PI; - stop += PConstants.TWO_PI; - } - if (stop - start > PConstants.TWO_PI) { - start = 0; - stop = PConstants.TWO_PI; - } - var hr = width / 2, - vr = height / 2, - centerX = x + hr, - centerY = y + vr, - step = 1/(hr+vr); - - var drawSlice = (function(x, y, start, step, stop) { - return function(p, closed, i, a, e) { - i = 0; - a = start; - e = stop + step; - p.beginShape(); - if(closed) { p.vertex(x-0.5, y-0.5); } - for (; a < e; i++, a = i*step + start) { - p.vertex( - (x + Math.cos(a) * hr)|0, - (y + Math.sin(a) * vr)|0 - ); - } - p.endShape(closed ? PConstants.CLOSE : undefined); - }; - }(centerX+0.5, centerY+0.5, start, step, stop)); - - if (doFill) { - var savedStroke = doStroke; - doStroke = false; - drawSlice(p, true); - doStroke = savedStroke; - } - - if (doStroke) { - var savedFill = doFill; - doFill = false; - drawSlice(p); - doFill = savedFill; - } - }; - - /** - * Draws a line (a direct path between two points) to the screen. The version of line() with four parameters - * draws the line in 2D. To color a line, use the stroke() function. A line cannot be filled, therefore the - * fill() method will not affect the color of a line. 2D lines are drawn with a width of one pixel by default, - * but this can be changed with the strokeWeight() function. The version with six parameters allows the line - * to be placed anywhere within XYZ space. Drawing this shape in 3D using the z parameter requires the P3D or - * OPENGL parameter in combination with size. - * - * @param {int|float} x1 x-coordinate of the first point - * @param {int|float} y1 y-coordinate of the first point - * @param {int|float} z1 z-coordinate of the first point - * @param {int|float} x2 x-coordinate of the second point - * @param {int|float} y2 y-coordinate of the second point - * @param {int|float} z2 z-coordinate of the second point - * - * @see strokeWeight - * @see strokeJoin - * @see strokeCap - * @see beginShape - */ - Drawing2D.prototype.line = function(x1, y1, x2, y2) { - if (!doStroke) { - return; - } - if (!renderSmooth) { - x1 = Math.round(x1); - x2 = Math.round(x2); - y1 = Math.round(y1); - y2 = Math.round(y2); - } - - // A line is only defined if it has different start and end coordinates. - // If they are the same, we call point instead. - if (x1 === x2 && y1 === y2) { - p.point(x1, y1); - return; - } - - var swap = undef, - lineCap = undef, - drawCrisp = true, - currentModelView = modelView.array(), - identityMatrix = [1, 0, 0, 0, 1, 0]; - // Test if any transformations have been applied to the sketch - for (var i = 0; i < 6 && drawCrisp; i++) { - drawCrisp = currentModelView[i] === identityMatrix[i]; - } - /* Draw crisp lines if the line is vertical or horizontal with the following method - * If any transformations have been applied to the sketch, don't make the line crisp - * If the line is directed up or to the left, reverse it by swapping x1/x2 or y1/y2 - * Make the line 1 pixel longer to work around cross-platform canvas implementations - * If the lineWidth is odd, translate the line by 0.5 in the perpendicular direction - * Even lineWidths do not need to be translated because the canvas will draw them on pixel boundaries - * Change the cap to butt-end to work around cross-platform canvas implementations - * Reverse the translate and lineCap canvas state changes after drawing the line - */ - if (drawCrisp) { - if (x1 === x2) { - if (y1 > y2) { - swap = y1; - y1 = y2; - y2 = swap; - } - y2++; - if (lineWidth % 2 === 1) { - curContext.translate(0.5, 0.0); - } - } else if (y1 === y2) { - if (x1 > x2) { - swap = x1; - x1 = x2; - x2 = swap; - } - x2++; - if (lineWidth % 2 === 1) { - curContext.translate(0.0, 0.5); - } - } - if (lineWidth === 1) { - lineCap = curContext.lineCap; - curContext.lineCap = 'butt'; - } - } - curContext.beginPath(); - curContext.moveTo(x1 || 0, y1 || 0); - curContext.lineTo(x2 || 0, y2 || 0); - executeContextStroke(); - if (drawCrisp) { - if (x1 === x2 && lineWidth % 2 === 1) { - curContext.translate(-0.5, 0.0); - } else if (y1 === y2 && lineWidth % 2 === 1) { - curContext.translate(0.0, -0.5); - } - if (lineWidth === 1) { - curContext.lineCap = lineCap; - } - } - }; - - Drawing3D.prototype.line = function(x1, y1, z1, x2, y2, z2) { - if (y2 === undef || z2 === undef) { // 2D line called in 3D context - z2 = 0; - y2 = x2; - x2 = z1; - z1 = 0; - } - - // a line is only defined if it has different start and end coordinates. - // If they are the same, we call point instead. - if (x1===x2 && y1===y2 && z1===z2) { - p.point(x1,y1,z1); - return; - } - - var lineVerts = [x1, y1, z1, x2, y2, z2]; - - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - - uniformMatrix("uModel2d", programObject2D, "uModel", false, [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); - - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, lineBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(lineVerts), curContext.STREAM_DRAW); - curContext.drawArrays(curContext.LINES, 0, 2); - } - }; - - /** - * Draws a Bezier curve on the screen. These curves are defined by a series of anchor and control points. The first - * two parameters specify the first anchor point and the last two parameters specify the other anchor point. The - * middle parameters specify the control points which define the shape of the curve. Bezier curves were developed - * by French engineer Pierre Bezier. Using the 3D version of requires rendering with P3D or OPENGL (see the - * Environment reference for more information). - * - * @param {int | float} x1,y1,z1 coordinates for the first anchor point - * @param {int | float} cx1,cy1,cz1 coordinates for the first control point - * @param {int | float} cx2,cy2,cz2 coordinates for the second control point - * @param {int | float} x2,y2,z2 coordinates for the second anchor point - * - * @see bezierVertex - * @see curve - */ - Drawing2D.prototype.bezier = function() { - if (arguments.length !== 8) { - throw("You must use 8 parameters for bezier() in 2D mode"); - } - - p.beginShape(); - p.vertex( arguments[0], arguments[1] ); - p.bezierVertex( arguments[2], arguments[3], - arguments[4], arguments[5], - arguments[6], arguments[7] ); - p.endShape(); - }; - - Drawing3D.prototype.bezier = function() { - if (arguments.length !== 12) { - throw("You must use 12 parameters for bezier() in 3D mode"); - } - - p.beginShape(); - p.vertex( arguments[0], arguments[1], arguments[2] ); - p.bezierVertex( arguments[3], arguments[4], arguments[5], - arguments[6], arguments[7], arguments[8], - arguments[9], arguments[10], arguments[11] ); - p.endShape(); - }; - - /** - * Sets the resolution at which Beziers display. The default value is 20. This function is only useful when using the P3D - * or OPENGL renderer as the default (JAVA2D) renderer does not use this information. - * - * @param {int} detail resolution of the curves - * - * @see curve - * @see curveVertex - * @see curveTightness - */ - p.bezierDetail = function( detail ){ - bezDetail = detail; - }; - - /** - * The bezierPoint() function evalutes quadratic bezier at point t for points a, b, c, d. - * The parameter t varies between 0 and 1. The a and d parameters are the - * on-curve points, b and c are the control points. To make a two-dimensional - * curve, call this function once with the x coordinates and a second time - * with the y coordinates to get the location of a bezier curve at t. - * - * @param {float} a coordinate of first point on the curve - * @param {float} b coordinate of first control point - * @param {float} c coordinate of second control point - * @param {float} d coordinate of second point on the curve - * @param {float} t value between 0 and 1 - * - * @see #bezier() - * @see #bezierVertex() - * @see #curvePoint() - */ - p.bezierPoint = function(a, b, c, d, t) { - return (1 - t) * (1 - t) * (1 - t) * a + 3 * (1 - t) * (1 - t) * t * b + 3 * (1 - t) * t * t * c + t * t * t * d; - }; - - /** - * The bezierTangent() function calculates the tangent of a point on a Bezier curve. There is a good - * definition of "tangent" at Wikipedia: <a href="http://en.wikipedia.org/wiki/Tangent" target="new">http://en.wikipedia.org/wiki/Tangent</a> - * - * @param {float} a coordinate of first point on the curve - * @param {float} b coordinate of first control point - * @param {float} c coordinate of second control point - * @param {float} d coordinate of second point on the curve - * @param {float} t value between 0 and 1 - * - * @see #bezier() - * @see #bezierVertex() - * @see #curvePoint() - */ - p.bezierTangent = function(a, b, c, d, t) { - return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b)); - }; - - /** - * The curvePoint() function evalutes the Catmull-Rom curve at point t for points a, b, c, d. The - * parameter t varies between 0 and 1, a and d are points on the curve, - * and b and c are the control points. This can be done once with the x - * coordinates and a second time with the y coordinates to get the - * location of a curve at t. - * - * @param {int|float} a coordinate of first point on the curve - * @param {int|float} b coordinate of second point on the curve - * @param {int|float} c coordinate of third point on the curve - * @param {int|float} d coordinate of fourth point on the curve - * @param {float} t value between 0 and 1 - * - * @see #curve() - * @see #curveVertex() - * @see #bezierPoint() - */ - p.curvePoint = function(a, b, c, d, t) { - return 0.5 * ((2 * b) + (-a + c) * t + (2 * a - 5 * b + 4 * c - d) * t * t + (-a + 3 * b - 3 * c + d) * t * t * t); - }; - - /** - * The curveTangent() function calculates the tangent of a point on a Catmull-Rom curve. - * There is a good definition of "tangent" at Wikipedia: <a href="http://en.wikipedia.org/wiki/Tangent" target="new">http://en.wikipedia.org/wiki/Tangent</a>. - * - * @param {int|float} a coordinate of first point on the curve - * @param {int|float} b coordinate of first control point - * @param {int|float} c coordinate of second control point - * @param {int|float} d coordinate of second point on the curve - * @param {float} t value between 0 and 1 - * - * @see #curve() - * @see #curveVertex() - * @see #curvePoint() - * @see #bezierTangent() - */ - p.curveTangent = function(a, b, c, d, t) { - return 0.5 * ((-a + c) + 2 * (2 * a - 5 * b + 4 * c - d) * t + 3 * (-a + 3 * b - 3 * c + d) * t * t); - }; - - /** - * A triangle is a plane created by connecting three points. The first two arguments specify the first point, - * the middle two arguments specify the second point, and the last two arguments specify the third point. - * - * @param {int | float} x1 x-coordinate of the first point - * @param {int | float} y1 y-coordinate of the first point - * @param {int | float} x2 x-coordinate of the second point - * @param {int | float} y2 y-coordinate of the second point - * @param {int | float} x3 x-coordinate of the third point - * @param {int | float} y3 y-coordinate of the third point - */ - p.triangle = function(x1, y1, x2, y2, x3, y3) { - p.beginShape(PConstants.TRIANGLES); - p.vertex(x1, y1, 0); - p.vertex(x2, y2, 0); - p.vertex(x3, y3, 0); - p.endShape(); - }; - - /** - * A quad is a quadrilateral, a four sided polygon. It is similar to a rectangle, but the angles between its - * edges are not constrained to ninety degrees. The first pair of parameters (x1,y1) sets the first vertex - * and the subsequent pairs should proceed clockwise or counter-clockwise around the defined shape. - * - * @param {float | int} x1 x-coordinate of the first corner - * @param {float | int} y1 y-coordinate of the first corner - * @param {float | int} x2 x-coordinate of the second corner - * @param {float | int} y2 y-coordinate of the second corner - * @param {float | int} x3 x-coordinate of the third corner - * @param {float | int} y3 y-coordinate of the third corner - * @param {float | int} x4 x-coordinate of the fourth corner - * @param {float | int} y4 y-coordinate of the fourth corner - */ - p.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { - p.beginShape(PConstants.QUADS); - p.vertex(x1, y1, 0); - p.vertex(x2, y2, 0); - p.vertex(x3, y3, 0); - p.vertex(x4, y4, 0); - p.endShape(); - }; - - var roundedRect$2d = function(x, y, width, height, tl, tr, br, bl) { - if (bl === undef) { - tr = tl; - br = tl; - bl = tl; - } - var halfWidth = width / 2, - halfHeight = height / 2; - if (tl > halfWidth || tl > halfHeight) { - tl = Math.min(halfWidth, halfHeight); - } - if (tr > halfWidth || tr > halfHeight) { - tr = Math.min(halfWidth, halfHeight); - } - if (br > halfWidth || br > halfHeight) { - br = Math.min(halfWidth, halfHeight); - } - if (bl > halfWidth || bl > halfHeight) { - bl = Math.min(halfWidth, halfHeight); - } - // Translate the stroke by (0.5, 0.5) to draw a crisp border - if (!doFill || doStroke) { - curContext.translate(0.5, 0.5); - } - curContext.beginPath(); - curContext.moveTo(x + tl, y); - curContext.lineTo(x + width - tr, y); - curContext.quadraticCurveTo(x + width, y, x + width, y + tr); - curContext.lineTo(x + width, y + height - br); - curContext.quadraticCurveTo(x + width, y + height, x + width - br, y + height); - curContext.lineTo(x + bl, y + height); - curContext.quadraticCurveTo(x, y + height, x, y + height - bl); - curContext.lineTo(x, y + tl); - curContext.quadraticCurveTo(x, y, x + tl, y); - if (!doFill || doStroke) { - curContext.translate(-0.5, -0.5); - } - executeContextFill(); - executeContextStroke(); - }; - - /** - * Draws a rectangle to the screen. A rectangle is a four-sided shape with every angle at ninety - * degrees. The first two parameters set the location, the third sets the width, and the fourth - * sets the height. The origin is changed with the rectMode() function. - * - * @param {int|float} x x-coordinate of the rectangle - * @param {int|float} y y-coordinate of the rectangle - * @param {int|float} width width of the rectangle - * @param {int|float} height height of the rectangle - * - * @see rectMode - * @see quad - */ - Drawing2D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { - if (!width && !height) { - return; - } - - if (curRectMode === PConstants.CORNERS) { - width -= x; - height -= y; - } else if (curRectMode === PConstants.RADIUS) { - width *= 2; - height *= 2; - x -= width / 2; - y -= height / 2; - } else if (curRectMode === PConstants.CENTER) { - x -= width / 2; - y -= height / 2; - } - - if (!renderSmooth) { - x = Math.round(x); - y = Math.round(y); - width = Math.round(width); - height = Math.round(height); - } - if (tl !== undef) { - roundedRect$2d(x, y, width, height, tl, tr, br, bl); - return; - } - - // Translate the line by (0.5, 0.5) to draw a crisp rectangle border - if (doStroke && lineWidth % 2 === 1) { - curContext.translate(0.5, 0.5); - } - curContext.beginPath(); - curContext.rect(x, y, width, height); - executeContextFill(); - executeContextStroke(); - if (doStroke && lineWidth % 2 === 1) { - curContext.translate(-0.5, -0.5); - } - }; - - Drawing3D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { - if (tl !== undef) { - throw "rect() with rounded corners is not supported in 3D mode"; - } - - if (curRectMode === PConstants.CORNERS) { - width -= x; - height -= y; - } else if (curRectMode === PConstants.RADIUS) { - width *= 2; - height *= 2; - x -= width / 2; - y -= height / 2; - } else if (curRectMode === PConstants.CENTER) { - x -= width / 2; - y -= height / 2; - } - - // Modeling transformation - var model = new PMatrix3D(); - model.translate(x, y, 0); - model.scale(width, height, 1); - model.transpose(); - - // viewing transformation needs to have Y flipped - // becuase that's what Processing does. - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, rectBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.drawArrays(curContext.LINE_LOOP, 0, rectVerts.length / 3); - } - - if (doFill) { - curContext.useProgram(programObject3D); - uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array()); - uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); - - // fix stitching problems. (lines get occluded by triangles - // since they share the same depth values). This is not entirely - // working, but it's a start for drawing the outline. So - // developers can start playing around with styles. - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - - uniformf("color3d", programObject3D, "uColor", fillStyle); - - if(lightCount > 0){ - var v = new PMatrix3D(); - v.set(view); - - var m = new PMatrix3D(); - m.set(model); - - v.mult(m); - - var normalMatrix = new PMatrix3D(); - normalMatrix.set(v); - normalMatrix.invert(); - normalMatrix.transpose(); - - uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); - vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, rectNormBuffer); - } - else{ - disableVertexAttribPointer("normal3d", programObject3D, "aNormal"); - } - - vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, rectBuffer); - - curContext.drawArrays(curContext.TRIANGLE_FAN, 0, rectVerts.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL); - } - }; - - /** - * Draws an ellipse (oval) in the display window. An ellipse with an equal <b>width</b> and <b>height</b> is a circle. - * The first two parameters set the location, the third sets the width, and the fourth sets the height. The origin may be - * changed with the <b>ellipseMode()</b> function. - * - * @param {float|int} x x-coordinate of the ellipse - * @param {float|int} y y-coordinate of the ellipse - * @param {float|int} width width of the ellipse - * @param {float|int} height height of the ellipse - * - * @see ellipseMode - */ - Drawing2D.prototype.ellipse = function(x, y, width, height) { - x = x || 0; - y = y || 0; - - if (width <= 0 && height <= 0) { - return; - } - - if (curEllipseMode === PConstants.RADIUS) { - width *= 2; - height *= 2; - } else if (curEllipseMode === PConstants.CORNERS) { - width = width - x; - height = height - y; - x += width / 2; - y += height / 2; - } else if (curEllipseMode === PConstants.CORNER) { - x += width / 2; - y += height / 2; - } - - // Shortcut for drawing a 2D circle - if (width === height) { - curContext.beginPath(); - curContext.arc(x, y, width / 2, 0, PConstants.TWO_PI, false); - executeContextFill(); - executeContextStroke(); - } else { - var w = width / 2, - h = height / 2, - C = 0.5522847498307933, - c_x = C * w, - c_y = C * h; - - p.beginShape(); - p.vertex(x + w, y); - p.bezierVertex(x + w, y - c_y, x + c_x, y - h, x, y - h); - p.bezierVertex(x - c_x, y - h, x - w, y - c_y, x - w, y); - p.bezierVertex(x - w, y + c_y, x - c_x, y + h, x, y + h); - p.bezierVertex(x + c_x, y + h, x + w, y + c_y, x + w, y); - p.endShape(); - } - }; - - Drawing3D.prototype.ellipse = function(x, y, width, height) { - x = x || 0; - y = y || 0; - - if (width <= 0 && height <= 0) { - return; - } - - if (curEllipseMode === PConstants.RADIUS) { - width *= 2; - height *= 2; - } else if (curEllipseMode === PConstants.CORNERS) { - width = width - x; - height = height - y; - x += width / 2; - y += height / 2; - } else if (curEllipseMode === PConstants.CORNER) { - x += width / 2; - y += height / 2; - } - - var w = width / 2, - h = height / 2, - C = 0.5522847498307933, - c_x = C * w, - c_y = C * h; - - p.beginShape(); - p.vertex(x + w, y); - p.bezierVertex(x + w, y - c_y, 0, x + c_x, y - h, 0, x, y - h, 0); - p.bezierVertex(x - c_x, y - h, 0, x - w, y - c_y, 0, x - w, y, 0); - p.bezierVertex(x - w, y + c_y, 0, x - c_x, y + h, 0, x, y + h, 0); - p.bezierVertex(x + c_x, y + h, 0, x + w, y + c_y, 0, x + w, y, 0); - p.endShape(); - - if (doFill) { - //temporary workaround to not working fills for bezier -- will fix later - var xAv = 0, yAv = 0, i, j; - for (i = 0; i < vertArray.length; i++) { - xAv += vertArray[i][0]; - yAv += vertArray[i][1]; - } - xAv /= vertArray.length; - yAv /= vertArray.length; - var vert = [], - fillVertArray = [], - colorVertArray = []; - vert[0] = xAv; - vert[1] = yAv; - vert[2] = 0; - vert[3] = 0; - vert[4] = 0; - vert[5] = fillStyle[0]; - vert[6] = fillStyle[1]; - vert[7] = fillStyle[2]; - vert[8] = fillStyle[3]; - vert[9] = strokeStyle[0]; - vert[10] = strokeStyle[1]; - vert[11] = strokeStyle[2]; - vert[12] = strokeStyle[3]; - vert[13] = normalX; - vert[14] = normalY; - vert[15] = normalZ; - vertArray.unshift(vert); - for (i = 0; i < vertArray.length; i++) { - for (j = 0; j < 3; j++) { - fillVertArray.push(vertArray[i][j]); - } - for (j = 5; j < 9; j++) { - colorVertArray.push(vertArray[i][j]); - } - } - fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray); - } - }; - - /** - * Sets the current normal vector. This is for drawing three dimensional shapes and surfaces and - * specifies a vector perpendicular to the surface of the shape which determines how lighting affects - * it. Processing attempts to automatically assign normals to shapes, but since that's imperfect, - * this is a better option when you want more control. This function is identical to glNormal3f() in OpenGL. - * - * @param {float} nx x direction - * @param {float} ny y direction - * @param {float} nz z direction - * - * @see beginShape - * @see endShape - * @see lights - */ - p.normal = function(nx, ny, nz) { - if (arguments.length !== 3 || !(typeof nx === "number" && typeof ny === "number" && typeof nz === "number")) { - throw "normal() requires three numeric arguments."; - } - - normalX = nx; - normalY = ny; - normalZ = nz; - - if (curShape !== 0) { - if (normalMode === PConstants.NORMAL_MODE_AUTO) { - normalMode = PConstants.NORMAL_MODE_SHAPE; - } else if (normalMode === PConstants.NORMAL_MODE_SHAPE) { - normalMode = PConstants.NORMAL_MODE_VERTEX; - } - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Raster drawing functions - //////////////////////////////////////////////////////////////////////////// - - /** - * Saves an image from the display window. Images are saved in TIFF, TARGA, JPEG, and PNG format - * depending on the extension within the filename parameter. For example, "image.tif" will have - * a TIFF image and "image.png" will save a PNG image. If no extension is included in the filename, - * the image will save in TIFF format and .tif will be added to the name. These files are saved to - * the sketch's folder, which may be opened by selecting "Show sketch folder" from the "Sketch" menu. - * It is not possible to use save() while running the program in a web browser. All images saved - * from the main drawing window will be opaque. To save images without a background, use createGraphics(). - * - * @param {String} filename any sequence of letters and numbers - * - * @see saveFrame - * @see createGraphics - */ - p.save = function(file, img) { - // file is unused at the moment - // may implement this differently in later release - if (img !== undef) { - return window.open(img.toDataURL(),"_blank"); - } - return window.open(p.externals.canvas.toDataURL(),"_blank"); - }; - - var saveNumber = 0; - - p.saveFrame = function(file) { - if(file === undef) { - // use default name template if parameter is not specified - file = "screen-####.png"; - } - // Increment changeable part: screen-0000.png, screen-0001.png, ... - var frameFilename = file.replace(/#+/, function(all) { - var s = "" + (saveNumber++); - while(s.length < all.length) { - s = "0" + s; - } - return s; - }); - p.save(frameFilename); - }; - - var utilityContext2d = document.createElement("canvas").getContext("2d"); - - var canvasDataCache = [undef, undef, undef]; // we need three for now - - function getCanvasData(obj, w, h) { - var canvasData = canvasDataCache.shift(); - - if (canvasData === undef) { - canvasData = {}; - canvasData.canvas = document.createElement("canvas"); - canvasData.context = canvasData.canvas.getContext('2d'); - } - - canvasDataCache.push(canvasData); - - var canvas = canvasData.canvas, context = canvasData.context, - width = w || obj.width, height = h || obj.height; - - canvas.width = width; - canvas.height = height; - - if (!obj) { - context.clearRect(0, 0, width, height); - } else if ("data" in obj) { // ImageData - context.putImageData(obj, 0, 0); - } else { - context.clearRect(0, 0, width, height); - context.drawImage(obj, 0, 0, width, height); - } - return canvasData; - } - - /** - * Handle the sketch code for pixels[] and pixels.length - * parser code converts pixels[] to getPixels() - * or setPixels(), .length becomes getLength() - */ - function buildPixelsObject(pImage) { - return { - - getLength: (function(aImg) { - return function() { - if (aImg.isRemote) { - throw "Image is loaded remotely. Cannot get length."; - } else { - return aImg.imageData.data.length ? aImg.imageData.data.length/4 : 0; - } - }; - }(pImage)), - - getPixel: (function(aImg) { - return function(i) { - var offset = i*4, - data = aImg.imageData.data; - - if (aImg.isRemote) { - throw "Image is loaded remotely. Cannot get pixels."; - } - - return (data[offset+3] << 24) & PConstants.ALPHA_MASK | - (data[offset] << 16) & PConstants.RED_MASK | - (data[offset+1] << 8) & PConstants.GREEN_MASK | - data[offset+2] & PConstants.BLUE_MASK; - }; - }(pImage)), - - setPixel: (function(aImg) { - return function(i, c) { - var offset = i*4, - data = aImg.imageData.data; - - if (aImg.isRemote) { - throw "Image is loaded remotely. Cannot set pixel."; - } - - data[offset+0] = (c & PConstants.RED_MASK) >>> 16; - data[offset+1] = (c & PConstants.GREEN_MASK) >>> 8; - data[offset+2] = (c & PConstants.BLUE_MASK); - data[offset+3] = (c & PConstants.ALPHA_MASK) >>> 24; - aImg.__isDirty = true; - }; - }(pImage)), - - toArray: (function(aImg) { - return function() { - var arr = [], - data = aImg.imageData.data, - length = aImg.width * aImg.height; - - if (aImg.isRemote) { - throw "Image is loaded remotely. Cannot get pixels."; - } - - for (var i = 0, offset = 0; i < length; i++, offset += 4) { - arr.push( (data[offset+3] << 24) & PConstants.ALPHA_MASK | - (data[offset] << 16) & PConstants.RED_MASK | - (data[offset+1] << 8) & PConstants.GREEN_MASK | - data[offset+2] & PConstants.BLUE_MASK ); - } - return arr; - }; - }(pImage)), - - set: (function(aImg) { - return function(arr) { - var offset, - data, - c; - if (this.isRemote) { - throw "Image is loaded remotely. Cannot set pixels."; - } - - data = aImg.imageData.data; - for (var i = 0, aL = arr.length; i < aL; i++) { - c = arr[i]; - offset = i*4; - - data[offset+0] = (c & PConstants.RED_MASK) >>> 16; - data[offset+1] = (c & PConstants.GREEN_MASK) >>> 8; - data[offset+2] = (c & PConstants.BLUE_MASK); - data[offset+3] = (c & PConstants.ALPHA_MASK) >>> 24; - } - aImg.__isDirty = true; - }; - }(pImage)) - - }; - } - - /** - * Datatype for storing images. Processing can display .gif, .jpg, .tga, and .png images. Images may be - * displayed in 2D and 3D space. Before an image is used, it must be loaded with the loadImage() function. - * The PImage object contains fields for the width and height of the image, as well as an array called - * pixels[] which contains the values for every pixel in the image. A group of methods, described below, - * allow easy access to the image's pixels and alpha channel and simplify the process of compositing. - * Before using the pixels[] array, be sure to use the loadPixels() method on the image to make sure that the - * pixel data is properly loaded. To create a new image, use the createImage() function (do not use new PImage()). - * - * @param {int} width image width - * @param {int} height image height - * @param {MODE} format Either RGB, ARGB, ALPHA (grayscale alpha channel) - * - * @returns {PImage} - * - * @see loadImage - * @see imageMode - * @see createImage - */ - var PImage = function(aWidth, aHeight, aFormat) { - - // Keep track of whether or not the cached imageData has been touched. - this.__isDirty = false; - - if (aWidth instanceof HTMLImageElement) { - // convert an <img> to a PImage - this.fromHTMLImageData(aWidth); - } else if (aHeight || aFormat) { - this.width = aWidth || 1; - this.height = aHeight || 1; - - // Stuff a canvas into sourceImg so image() calls can use drawImage like an <img> - var canvas = this.sourceImg = document.createElement("canvas"); - canvas.width = this.width; - canvas.height = this.height; - - var imageData = this.imageData = canvas.getContext('2d').createImageData(this.width, this.height); - this.format = (aFormat === PConstants.ARGB || aFormat === PConstants.ALPHA) ? aFormat : PConstants.RGB; - if (this.format === PConstants.RGB) { - // Set the alpha channel of an RGB image to opaque. - for (var i = 3, data = this.imageData.data, len = data.length; i < len; i += 4) { - data[i] = 255; - } - } - - this.__isDirty = true; - this.updatePixels(); - } else { - this.width = 0; - this.height = 0; - this.imageData = utilityContext2d.createImageData(1, 1); - this.format = PConstants.ARGB; - } - - this.pixels = buildPixelsObject(this); - }; - PImage.prototype = { - - /** - * Temporary hack to deal with cross-Processing-instance created PImage. See - * tickets #1623 and #1644. - */ - __isPImage: true, - - /** - * @member PImage - * Updates the image with the data in its pixels[] array. Use in conjunction with loadPixels(). If - * you're only reading pixels from the array, there's no need to call updatePixels(). - * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the rule - * is that any time you want to manipulate the pixels[] array, you must first call loadPixels(), and - * after changes have been made, call updatePixels(). Even if the renderer may not seem to use this - * function in the current Processing release, this will always be subject to change. - * Currently, none of the renderers use the additional parameters to updatePixels(). - */ - updatePixels: function() { - var canvas = this.sourceImg; - if (canvas && canvas instanceof HTMLCanvasElement && this.__isDirty) { - canvas.getContext('2d').putImageData(this.imageData, 0, 0); - } - this.__isDirty = false; - }, - - fromHTMLImageData: function(htmlImg) { - // convert an <img> to a PImage - var canvasData = getCanvasData(htmlImg); - try { - var imageData = canvasData.context.getImageData(0, 0, htmlImg.width, htmlImg.height); - this.fromImageData(imageData); - } catch(e) { - if (htmlImg.width && htmlImg.height) { - this.isRemote = true; - this.width = htmlImg.width; - this.height = htmlImg.height; - } - } - this.sourceImg = htmlImg; - }, - - 'get': function(x, y, w, h) { - if (!arguments.length) { - return p.get(this); - } - if (arguments.length === 2) { - return p.get(x, y, this); - } - if (arguments.length === 4) { - return p.get(x, y, w, h, this); - } - }, - - /** - * @member PImage - * Changes the color of any pixel or writes an image directly into the image. The x and y parameter - * specify the pixel or the upper-left corner of the image. The color parameter specifies the color value. - * Setting the color of a single pixel with set(x, y) is easy, but not as fast as putting the data - * directly into pixels[]. The equivalent statement to "set(x, y, #000000)" using pixels[] is - * "pixels[y*width+x] = #000000". Processing requires calling loadPixels() to load the display window - * data into the pixels[] array before getting the values and calling updatePixels() to update the window. - * - * @param {int} x x-coordinate of the pixel or upper-left corner of the image - * @param {int} y y-coordinate of the pixel or upper-left corner of the image - * @param {color} color any value of the color datatype - * - * @see get - * @see pixels[] - * @see copy - */ - 'set': function(x, y, c) { - p.set(x, y, c, this); - this.__isDirty = true; - }, - - /** - * @member PImage - * Blends a region of pixels into the image specified by the img parameter. These copies utilize full - * alpha channel support and a choice of the following modes to blend the colors of source pixels (A) - * with the ones of pixels in the destination image (B): - * BLEND - linear interpolation of colours: C = A*factor + B - * ADD - additive blending with white clip: C = min(A*factor + B, 255) - * SUBTRACT - subtractive blending with black clip: C = max(B - A*factor, 0) - * DARKEST - only the darkest colour succeeds: C = min(A*factor, B) - * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B) - * DIFFERENCE - subtract colors from underlying image. - * EXCLUSION - similar to DIFFERENCE, but less extreme. - * MULTIPLY - Multiply the colors, result will always be darker. - * SCREEN - Opposite multiply, uses inverse values of the colors. - * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and screens light values. - * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower. - * SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not as harsh. - * DODGE - Lightens light tones and increases contrast, ignores darks. Called "Color Dodge" in Illustrator and Photoshop. - * BURN - Darker areas are applied, increasing contrast, ignores lights. Called "Color Burn" in Illustrator and Photoshop. - * All modes use the alpha information (highest byte) of source image pixels as the blending factor. - * If the source and destination regions are different sizes, the image will be automatically resized to - * match the destination size. If the srcImg parameter is not used, the display window is used as the source image. - * This function ignores imageMode(). - * - * @param {int} x X coordinate of the source's upper left corner - * @param {int} y Y coordinate of the source's upper left corner - * @param {int} width source image width - * @param {int} height source image height - * @param {int} dx X coordinate of the destinations's upper left corner - * @param {int} dy Y coordinate of the destinations's upper left corner - * @param {int} dwidth destination image width - * @param {int} dheight destination image height - * @param {PImage} srcImg an image variable referring to the source image - * @param {MODE} MODE Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION, - * MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN - * - * @see alpha - * @see copy - */ - blend: function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE) { - if (arguments.length === 9) { - p.blend(this, srcImg, x, y, width, height, dx, dy, dwidth, dheight, this); - } else if (arguments.length === 10) { - p.blend(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE, this); - } - delete this.sourceImg; - }, - - /** - * @member PImage - * Copies a region of pixels from one image into another. If the source and destination regions - * aren't the same size, it will automatically resize source pixels to fit the specified target region. - * No alpha information is used in the process, however if the source image has an alpha channel set, - * it will be copied as well. This function ignores imageMode(). - * - * @param {int} sx X coordinate of the source's upper left corner - * @param {int} sy Y coordinate of the source's upper left corner - * @param {int} swidth source image width - * @param {int} sheight source image height - * @param {int} dx X coordinate of the destinations's upper left corner - * @param {int} dy Y coordinate of the destinations's upper left corner - * @param {int} dwidth destination image width - * @param {int} dheight destination image height - * @param {PImage} srcImg an image variable referring to the source image - * - * @see alpha - * @see blend - */ - copy: function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) { - if (arguments.length === 8) { - p.blend(this, srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, PConstants.REPLACE, this); - } else if (arguments.length === 9) { - p.blend(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight, PConstants.REPLACE, this); - } - delete this.sourceImg; - }, - - /** - * @member PImage - * Filters an image as defined by one of the following modes: - * THRESHOLD - converts the image to black and white pixels depending if they are above or below - * the threshold defined by the level parameter. The level must be between 0.0 (black) and 1.0(white). - * If no level is specified, 0.5 is used. - * GRAY - converts any colors in the image to grayscale equivalents - * INVERT - sets each pixel to its inverse value - * POSTERIZE - limits each channel of the image to the number of colors specified as the level parameter - * BLUR - executes a Guassian blur with the level parameter specifying the extent of the blurring. - * If no level parameter is used, the blur is equivalent to Guassian blur of radius 1. - * OPAQUE - sets the alpha channel to entirely opaque. - * ERODE - reduces the light areas with the amount defined by the level parameter. - * DILATE - increases the light areas with the amount defined by the level parameter - * - * @param {MODE} MODE Either THRESHOLD, GRAY, INVERT, POSTERIZE, BLUR, OPAQUE, ERODE, or DILATE - * @param {int|float} param in the range from 0 to 1 - */ - filter: function(mode, param) { - if (arguments.length === 2) { - p.filter(mode, param, this); - } else if (arguments.length === 1) { - // no param specified, send null to show its invalid - p.filter(mode, null, this); - } - delete this.sourceImg; - }, - - /** - * @member PImage - * Saves the image into a file. Images are saved in TIFF, TARGA, JPEG, and PNG format depending on - * the extension within the filename parameter. For example, "image.tif" will have a TIFF image and - * "image.png" will save a PNG image. If no extension is included in the filename, the image will save - * in TIFF format and .tif will be added to the name. These files are saved to the sketch's folder, - * which may be opened by selecting "Show sketch folder" from the "Sketch" menu. It is not possible to - * use save() while running the program in a web browser. - * To save an image created within the code, rather than through loading, it's necessary to make the - * image with the createImage() function so it is aware of the location of the program and can therefore - * save the file to the right place. See the createImage() reference for more information. - * - * @param {String} filename a sequence of letters and numbers - */ - save: function(file){ - p.save(file,this); - }, - - /** - * @member PImage - * Resize the image to a new width and height. To make the image scale proportionally, use 0 as the - * value for the wide or high parameter. - * - * @param {int} wide the resized image width - * @param {int} high the resized image height - * - * @see get - */ - resize: function(w, h) { - if (this.isRemote) { // Remote images cannot access imageData - throw "Image is loaded remotely. Cannot resize."; - } - if (this.width !== 0 || this.height !== 0) { - // make aspect ratio if w or h is 0 - if (w === 0 && h !== 0) { - w = Math.floor(this.width / this.height * h); - } else if (h === 0 && w !== 0) { - h = Math.floor(this.height / this.width * w); - } - // put 'this.imageData' into a new canvas - var canvas = getCanvasData(this.imageData).canvas; - // pull imageData object out of canvas into ImageData object - var imageData = getCanvasData(canvas, w, h).context.getImageData(0, 0, w, h); - // set this as new pimage - this.fromImageData(imageData); - } - }, - - /** - * @member PImage - * Masks part of an image from displaying by loading another image and using it as an alpha channel. - * This mask image should only contain grayscale data, but only the blue color channel is used. The - * mask image needs to be the same size as the image to which it is applied. - * In addition to using a mask image, an integer array containing the alpha channel data can be - * specified directly. This method is useful for creating dynamically generated alpha masks. This - * array must be of the same length as the target image's pixels array and should contain only grayscale - * data of values between 0-255. - * - * @param {PImage} maskImg any PImage object used as the alpha channel for "img", needs to be same - * size as "img" - * @param {int[]} maskArray any array of Integer numbers used as the alpha channel, needs to be same - * length as the image's pixel array - */ - mask: function(mask) { - var obj = this.toImageData(), - i, - size; - - if (mask instanceof PImage || mask.__isPImage) { - if (mask.width === this.width && mask.height === this.height) { - mask = mask.toImageData(); - - for (i = 2, size = this.width * this.height * 4; i < size; i += 4) { - // using it as an alpha channel - obj.data[i + 1] = mask.data[i]; - // but only the blue color channel - } - } else { - throw "mask must have the same dimensions as PImage."; - } - } else if (mask instanceof Array) { - if (this.width * this.height === mask.length) { - for (i = 0, size = mask.length; i < size; ++i) { - obj.data[i * 4 + 3] = mask[i]; - } - } else { - throw "mask array must be the same length as PImage pixels array."; - } - } - - this.fromImageData(obj); - }, - - // These are intentionally left blank for PImages, we work live with pixels and draw as necessary - /** - * @member PImage - * Loads the pixel data for the image into its pixels[] array. This function must always be called - * before reading from or writing to pixels[]. - * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the - * rule is that any time you want to manipulate the pixels[] array, you must first call loadPixels(), - * and after changes have been made, call updatePixels(). Even if the renderer may not seem to use - * this function in the current Processing release, this will always be subject to change. - */ - loadPixels: noop, - - toImageData: function() { - if (this.isRemote) { - return this.sourceImg; - } - - if (!this.__isDirty) { - return this.imageData; - } - - var canvasData = getCanvasData(this.sourceImg); - return canvasData.context.getImageData(0, 0, this.width, this.height); - }, - - toDataURL: function() { - if (this.isRemote) { // Remote images cannot access imageData - throw "Image is loaded remotely. Cannot create dataURI."; - } - var canvasData = getCanvasData(this.imageData); - return canvasData.canvas.toDataURL(); - }, - - fromImageData: function(canvasImg) { - var w = canvasImg.width, - h = canvasImg.height, - canvas = document.createElement('canvas'), - ctx = canvas.getContext('2d'); - - this.width = canvas.width = w; - this.height = canvas.height = h; - - ctx.putImageData(canvasImg, 0, 0); - - // changed for 0.9 - this.format = PConstants.ARGB; - - this.imageData = canvasImg; - this.sourceImg = canvas; - } - }; - - p.PImage = PImage; - - /** - * Creates a new PImage (the datatype for storing images). This provides a fresh buffer of pixels to play - * with. Set the size of the buffer with the width and height parameters. The format parameter defines how - * the pixels are stored. See the PImage reference for more information. - * Be sure to include all three parameters, specifying only the width and height (but no format) will - * produce a strange error. - * Advanced users please note that createImage() should be used instead of the syntax new PImage(). - * - * @param {int} width image width - * @param {int} height image height - * @param {MODE} format Either RGB, ARGB, ALPHA (grayscale alpha channel) - * - * @returns {PImage} - * - * @see PImage - * @see PGraphics - */ - p.createImage = function(w, h, mode) { - return new PImage(w,h,mode); - }; - - // Loads an image for display. Type is an extension. Callback is fired on load. - /** - * Loads an image into a variable of type PImage. Four types of images ( .gif, .jpg, .tga, .png) images may - * be loaded. To load correctly, images must be located in the data directory of the current sketch. In most - * cases, load all images in setup() to preload them at the start of the program. Loading images inside draw() - * will reduce the speed of a program. - * The filename parameter can also be a URL to a file found online. For security reasons, a Processing sketch - * found online can only download files from the same server from which it came. Getting around this restriction - * requires a signed applet. - * The extension parameter is used to determine the image type in cases where the image filename does not end - * with a proper extension. Specify the extension as the second parameter to loadImage(), as shown in the - * third example on this page. - * If an image is not loaded successfully, the null value is returned and an error message will be printed to - * the console. The error message does not halt the program, however the null value may cause a NullPointerException - * if your code does not check whether the value returned from loadImage() is null. - * Depending on the type of error, a PImage object may still be returned, but the width and height of the image - * will be set to -1. This happens if bad image data is returned or cannot be decoded properly. Sometimes this happens - * with image URLs that produce a 403 error or that redirect to a password prompt, because loadImage() will attempt - * to interpret the HTML as image data. - * - * @param {String} filename name of file to load, can be .gif, .jpg, .tga, or a handful of other image - * types depending on your platform. - * @param {String} extension the type of image to load, for example "png", "gif", "jpg" - * - * @returns {PImage} - * - * @see PImage - * @see image - * @see imageMode - * @see background - */ - p.loadImage = function(file, type, callback) { - // if type is specified, we just ignore it - - var pimg; - // if image is in the preloader cache return a new PImage - if (curSketch.imageCache.images[file]) { - pimg = new PImage(curSketch.imageCache.images[file]); - pimg.loaded = true; - return pimg; - } - // else async load it - pimg = new PImage(); - var img = document.createElement('img'); - - pimg.sourceImg = img; - - img.onload = (function(aImage, aPImage, aCallback) { - var image = aImage; - var pimg = aPImage; - var callback = aCallback; - return function() { - // change the <img> object into a PImage now that its loaded - pimg.fromHTMLImageData(image); - pimg.loaded = true; - if (callback) { - callback(); - } - }; - }(img, pimg, callback)); - - img.src = file; // needs to be called after the img.onload function is declared or it wont work in opera - return pimg; - }; - - // async loading of large images, same functionality as loadImage above - /** - * This function load images on a separate thread so that your sketch does not freeze while images load during - * setup(). While the image is loading, its width and height will be 0. If an error occurs while loading the image, - * its width and height will be set to -1. You'll know when the image has loaded properly because its width and - * height will be greater than 0. Asynchronous image loading (particularly when downloading from a server) can - * dramatically improve performance. - * The extension parameter is used to determine the image type in cases where the image filename does not end - * with a proper extension. Specify the extension as the second parameter to requestImage(). - * - * @param {String} filename name of file to load, can be .gif, .jpg, .tga, or a handful of other image - * types depending on your platform. - * @param {String} extension the type of image to load, for example "png", "gif", "jpg" - * - * @returns {PImage} - * - * @see PImage - * @see loadImage - */ - p.requestImage = p.loadImage; - - function get$2(x,y) { - var data; - // return the color at x,y (int) of curContext - if (x >= p.width || x < 0 || y < 0 || y >= p.height) { - // x,y is outside image return transparent black - return 0; - } - - // loadPixels() has been called - if (isContextReplaced) { - var offset = ((0|x) + p.width * (0|y)) * 4; - data = p.imageData.data; - return (data[offset + 3] << 24) & PConstants.ALPHA_MASK | - (data[offset] << 16) & PConstants.RED_MASK | - (data[offset + 1] << 8) & PConstants.GREEN_MASK | - data[offset + 2] & PConstants.BLUE_MASK; - } - - // x,y is inside canvas space - data = p.toImageData(0|x, 0|y, 1, 1).data; - return (data[3] << 24) & PConstants.ALPHA_MASK | - (data[0] << 16) & PConstants.RED_MASK | - (data[1] << 8) & PConstants.GREEN_MASK | - data[2] & PConstants.BLUE_MASK; - } - function get$3(x,y,img) { - if (img.isRemote) { // Remote images cannot access imageData - throw "Image is loaded remotely. Cannot get x,y."; - } - // PImage.get(x,y) was called, return the color (int) at x,y of img - var offset = y * img.width * 4 + (x * 4), - data = img.imageData.data; - return (data[offset + 3] << 24) & PConstants.ALPHA_MASK | - (data[offset] << 16) & PConstants.RED_MASK | - (data[offset + 1] << 8) & PConstants.GREEN_MASK | - data[offset + 2] & PConstants.BLUE_MASK; - } - function get$4(x, y, w, h) { - // return a PImage of w and h from cood x,y of curContext - var c = new PImage(w, h, PConstants.ARGB); - c.fromImageData(p.toImageData(x, y, w, h)); - return c; - } - function get$5(x, y, w, h, img) { - if (img.isRemote) { // Remote images cannot access imageData - throw "Image is loaded remotely. Cannot get x,y,w,h."; - } - // PImage.get(x,y,w,h) was called, return x,y,w,h PImage of img - // offset start point needs to be *4 - var c = new PImage(w, h, PConstants.ARGB), cData = c.imageData.data, - imgWidth = img.width, imgHeight = img.height, imgData = img.imageData.data; - // Don't need to copy pixels from the image outside ranges. - var startRow = Math.max(0, -y), startColumn = Math.max(0, -x), - stopRow = Math.min(h, imgHeight - y), stopColumn = Math.min(w, imgWidth - x); - for (var i = startRow; i < stopRow; ++i) { - var sourceOffset = ((y + i) * imgWidth + (x + startColumn)) * 4; - var targetOffset = (i * w + startColumn) * 4; - for (var j = startColumn; j < stopColumn; ++j) { - cData[targetOffset++] = imgData[sourceOffset++]; - cData[targetOffset++] = imgData[sourceOffset++]; - cData[targetOffset++] = imgData[sourceOffset++]; - cData[targetOffset++] = imgData[sourceOffset++]; - } - } - c.__isDirty = true; - return c; - } - - // Gets a single pixel or block of pixels from the current Canvas Context or a PImage - /** - * Reads the color of any pixel or grabs a section of an image. If no parameters are specified, the entire - * image is returned. Get the value of one pixel by specifying an x,y coordinate. Get a section of the display - * window by specifying an additional width and height parameter. If the pixel requested is outside of the image - * window, black is returned. The numbers returned are scaled according to the current color ranges, but only RGB - * values are returned by this function. For example, even though you may have drawn a shape with colorMode(HSB), - * the numbers returned will be in RGB. - * Getting the color of a single pixel with get(x, y) is easy, but not as fast as grabbing the data directly - * from pixels[]. The equivalent statement to "get(x, y)" using pixels[] is "pixels[y*width+x]". Processing - * requires calling loadPixels() to load the display window data into the pixels[] array before getting the values. - * This function ignores imageMode(). - * - * @param {int} x x-coordinate of the pixel - * @param {int} y y-coordinate of the pixel - * @param {int} width width of pixel rectangle to get - * @param {int} height height of pixel rectangle to get - * - * @returns {Color|PImage} - * - * @see set - * @see pixels[] - * @see imageMode - */ - p.get = function(x, y, w, h, img) { - // for 0 2 and 4 arguments use curContext, otherwise PImage.get was called - if (img !== undefined) { - return get$5(x, y, w, h, img); - } - if (h !== undefined) { - return get$4(x, y, w, h); - } - if (w !== undefined) { - return get$3(x, y, w); - } - if (y !== undefined) { - return get$2(x, y); - } - if (x !== undefined) { - // PImage.get() was called, return a new PImage - return get$5(0, 0, x.width, x.height, x); - } - - return get$4(0, 0, p.width, p.height); - }; - - /** - * Creates and returns a new <b>PGraphics</b> object of the types P2D, P3D, and JAVA2D. Use this class if you need to draw - * into an off-screen graphics buffer. It's not possible to use <b>createGraphics()</b> with OPENGL, because it doesn't - * allow offscreen use. The DXF and PDF renderers require the filename parameter. <br /><br /> It's important to call - * any drawing commands between beginDraw() and endDraw() statements. This is also true for any commands that affect - * drawing, such as smooth() or colorMode().<br /><br /> Unlike the main drawing surface which is completely opaque, - * surfaces created with createGraphics() can have transparency. This makes it possible to draw into a graphics and - * maintain the alpha channel. - * - * @param {int} width width in pixels - * @param {int} height height in pixels - * @param {int} renderer Either P2D, P3D, JAVA2D, PDF, DXF - * @param {String} filename the name of the file (not supported yet) - */ - p.createGraphics = function(w, h, render) { - var pg = new Processing(); - pg.size(w, h, render); - pg.background(0,0); - return pg; - }; - - // pixels caching - function resetContext() { - if(isContextReplaced) { - curContext = originalContext; - isContextReplaced = false; - - p.updatePixels(); - } - } - function SetPixelContextWrapper() { - function wrapFunction(newContext, name) { - function wrapper() { - resetContext(); - curContext[name].apply(curContext, arguments); - } - newContext[name] = wrapper; - } - function wrapProperty(newContext, name) { - function getter() { - resetContext(); - return curContext[name]; - } - function setter(value) { - resetContext(); - curContext[name] = value; - } - p.defineProperty(newContext, name, { get: getter, set: setter }); - } - for(var n in curContext) { - if(typeof curContext[n] === 'function') { - wrapFunction(this, n); - } else { - wrapProperty(this, n); - } - } - } - function replaceContext() { - if(isContextReplaced) { - return; - } - p.loadPixels(); - if(proxyContext === null) { - originalContext = curContext; - proxyContext = new SetPixelContextWrapper(); - } - isContextReplaced = true; - curContext = proxyContext; - setPixelsCached = 0; - } - - function set$3(x, y, c) { - if (x < p.width && x >= 0 && y >= 0 && y < p.height) { - replaceContext(); - p.pixels.setPixel((0|x)+p.width*(0|y), c); - if(++setPixelsCached > maxPixelsCached) { - resetContext(); - } - } - } - function set$4(x, y, obj, img) { - if (img.isRemote) { // Remote images cannot access imageData - throw "Image is loaded remotely. Cannot set x,y."; - } - var c = p.color.toArray(obj); - var offset = y * img.width * 4 + (x*4); - var data = img.imageData.data; - data[offset] = c[0]; - data[offset+1] = c[1]; - data[offset+2] = c[2]; - data[offset+3] = c[3]; - } - - // Paints a pixel array into the canvas - /** - * Changes the color of any pixel or writes an image directly into the display window. The x and y parameters - * specify the pixel to change and the color parameter specifies the color value. The color parameter is affected - * by the current color mode (the default is RGB values from 0 to 255). When setting an image, the x and y - * parameters define the coordinates for the upper-left corner of the image. - * Setting the color of a single pixel with set(x, y) is easy, but not as fast as putting the data directly - * into pixels[]. The equivalent statement to "set(x, y, #000000)" using pixels[] is "pixels[y*width+x] = #000000". - * You must call loadPixels() to load the display window data into the pixels[] array before setting the values - * and calling updatePixels() to update the window with any changes. This function ignores imageMode(). - * - * @param {int} x x-coordinate of the pixel - * @param {int} y y-coordinate of the pixel - * @param {Color} obj any value of the color datatype - * @param {PImage} img any valid variable of type PImage - * - * @see get - * @see pixels[] - * @see imageMode - */ - p.set = function(x, y, obj, img) { - var color, oldFill; - if (arguments.length === 3) { - // called p.set(), was it with a color or a img ? - if (typeof obj === "number") { - set$3(x, y, obj); - } else if (obj instanceof PImage || obj.__isPImage) { - p.image(obj, x, y); - } - } else if (arguments.length === 4) { - // PImage.set(x,y,c) was called, set coordinate x,y color to c of img - set$4(x, y, obj, img); - } - }; - p.imageData = {}; - - // handle the sketch code for pixels[] - // parser code converts pixels[] to getPixels() or setPixels(), - // .length becomes getLength() - /** - * Array containing the values for all the pixels in the display window. These values are of the color datatype. - * This array is the size of the display window. For example, if the image is 100x100 pixels, there will be 10000 - * values and if the window is 200x300 pixels, there will be 60000 values. The index value defines the position - * of a value within the array. For example, the statment color b = pixels[230] will set the variable b to be - * equal to the value at that location in the array. - * Before accessing this array, the data must loaded with the loadPixels() function. After the array data has - * been modified, the updatePixels() function must be run to update the changes. - * - * @param {int} index must not exceed the size of the array - * - * @see loadPixels - * @see updatePixels - * @see get - * @see set - * @see PImage - */ - p.pixels = { - getLength: function() { return p.imageData.data.length ? p.imageData.data.length/4 : 0; }, - getPixel: function(i) { - var offset = i*4, data = p.imageData.data; - return (data[offset+3] << 24) & 0xff000000 | - (data[offset+0] << 16) & 0x00ff0000 | - (data[offset+1] << 8) & 0x0000ff00 | - data[offset+2] & 0x000000ff; - }, - setPixel: function(i,c) { - var offset = i*4, data = p.imageData.data; - data[offset+0] = (c & 0x00ff0000) >>> 16; // RED_MASK - data[offset+1] = (c & 0x0000ff00) >>> 8; // GREEN_MASK - data[offset+2] = (c & 0x000000ff); // BLUE_MASK - data[offset+3] = (c & 0xff000000) >>> 24; // ALPHA_MASK - }, - toArray: function() { - var arr = [], length = p.imageData.width * p.imageData.height, data = p.imageData.data; - for (var i = 0, offset = 0; i < length; i++, offset += 4) { - arr.push((data[offset+3] << 24) & 0xff000000 | - (data[offset+0] << 16) & 0x00ff0000 | - (data[offset+1] << 8) & 0x0000ff00 | - data[offset+2] & 0x000000ff); - } - return arr; - }, - set: function(arr) { - for (var i = 0, aL = arr.length; i < aL; i++) { - this.setPixel(i, arr[i]); - } - } - }; - - // Gets a 1-Dimensional pixel array from Canvas - /** - * Loads the pixel data for the display window into the pixels[] array. This function must always be called - * before reading from or writing to pixels[]. - * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the rule is that - * any time you want to manipulate the pixels[] array, you must first call loadPixels(), and after changes - * have been made, call updatePixels(). Even if the renderer may not seem to use this function in the current - * Processing release, this will always be subject to change. - * - * @see pixels[] - * @see updatePixels - */ - p.loadPixels = function() { - p.imageData = drawing.$ensureContext().getImageData(0, 0, p.width, p.height); - }; - - // Draws a 1-Dimensional pixel array to Canvas - /** - * Updates the display window with the data in the pixels[] array. Use in conjunction with loadPixels(). If - * you're only reading pixels from the array, there's no need to call updatePixels() unless there are changes. - * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the rule is that - * any time you want to manipulate the pixels[] array, you must first call loadPixels(), and after changes - * have been made, call updatePixels(). Even if the renderer may not seem to use this function in the current - * Processing release, this will always be subject to change. - * Currently, none of the renderers use the additional parameters to updatePixels(), however this may be - * implemented in the future. - * - * @see loadPixels - * @see pixels[] - */ - p.updatePixels = function() { - if (p.imageData) { - drawing.$ensureContext().putImageData(p.imageData, 0, 0); - } - }; - - /** - * Set various hints and hacks for the renderer. This is used to handle obscure rendering features that cannot be - * implemented in a consistent manner across renderers. Many options will often graduate to standard features - * instead of hints over time. - * hint(ENABLE_OPENGL_4X_SMOOTH) - Enable 4x anti-aliasing for OpenGL. This can help force anti-aliasing if - * it has not been enabled by the user. On some graphics cards, this can also be set by the graphics driver's - * control panel, however not all cards make this available. This hint must be called immediately after the - * size() command because it resets the renderer, obliterating any settings and anything drawn (and like size(), - * re-running the code that came before it again). - * hint(DISABLE_OPENGL_2X_SMOOTH) - In Processing 1.0, Processing always enables 2x smoothing when the OpenGL - * renderer is used. This hint disables the default 2x smoothing and returns the smoothing behavior found in - * earlier releases, where smooth() and noSmooth() could be used to enable and disable smoothing, though the - * quality was inferior. - * hint(ENABLE_NATIVE_FONTS) - Use the native version fonts when they are installed, rather than the bitmapped - * version from a .vlw file. This is useful with the JAVA2D renderer setting, as it will improve font rendering - * speed. This is not enabled by default, because it can be misleading while testing because the type will look - * great on your machine (because you have the font installed) but lousy on others' machines if the identical - * font is unavailable. This option can only be set per-sketch, and must be called before any use of textFont(). - * hint(DISABLE_DEPTH_TEST) - Disable the zbuffer, allowing you to draw on top of everything at will. When depth - * testing is disabled, items will be drawn to the screen sequentially, like a painting. This hint is most often - * used to draw in 3D, then draw in 2D on top of it (for instance, to draw GUI controls in 2D on top of a 3D - * interface). Starting in release 0149, this will also clear the depth buffer. Restore the default with - * hint(ENABLE_DEPTH_TEST), but note that with the depth buffer cleared, any 3D drawing that happens later in - * draw() will ignore existing shapes on the screen. - * hint(ENABLE_DEPTH_SORT) - Enable primitive z-sorting of triangles and lines in P3D and OPENGL. This can slow - * performance considerably, and the algorithm is not yet perfect. Restore the default with hint(DISABLE_DEPTH_SORT). - * hint(DISABLE_OPENGL_ERROR_REPORT) - Speeds up the OPENGL renderer setting by not checking for errors while - * running. Undo with hint(ENABLE_OPENGL_ERROR_REPORT). - * As of release 0149, unhint() has been removed in favor of adding additional ENABLE/DISABLE constants to reset - * the default behavior. This prevents the double negatives, and also reinforces which hints can be enabled or disabled. - * - * @param {MODE} item constant: name of the hint to be enabled or disabled - * - * @see PGraphics - * @see createGraphics - * @see size - */ - p.hint = function(which) { - var curContext = drawing.$ensureContext(); - if (which === PConstants.DISABLE_DEPTH_TEST) { - curContext.disable(curContext.DEPTH_TEST); - curContext.depthMask(false); - curContext.clear(curContext.DEPTH_BUFFER_BIT); - } - else if (which === PConstants.ENABLE_DEPTH_TEST) { - curContext.enable(curContext.DEPTH_TEST); - curContext.depthMask(true); - } - else if (which === PConstants.ENABLE_OPENGL_2X_SMOOTH || - which === PConstants.ENABLE_OPENGL_4X_SMOOTH){ - renderSmooth = true; - } - else if (which === PConstants.DISABLE_OPENGL_2X_SMOOTH){ - renderSmooth = false; - } - }; - - /** - * The background() function sets the color used for the background of the Processing window. - * The default background is light gray. In the <b>draw()</b> function, the background color is used to clear the display window at the beginning of each frame. - * An image can also be used as the background for a sketch, however its width and height must be the same size as the sketch window. - * To resize an image 'b' to the size of the sketch window, use b.resize(width, height). - * Images used as background will ignore the current <b>tint()</b> setting. - * For the main drawing surface, the alpha value will be ignored. However, - * alpha can be used on PGraphics objects from <b>createGraphics()</b>. This is - * the only way to set all the pixels partially transparent, for instance. - * If the 'gray' parameter is passed in the function sets the background to a grayscale value, based on the - * current colorMode. - * <p> - * Note that background() should be called before any transformations occur, - * because some implementations may require the current transformation matrix - * to be identity before drawing. - * - * @param {int|float} gray specifies a value between white and black - * @param {int|float} value1 red or hue value (depending on the current color mode) - * @param {int|float} value2 green or saturation value (depending on the current color mode) - * @param {int|float} value3 blue or brightness value (depending on the current color mode) - * @param {int|float} alpha opacity of the background - * @param {Color} color any value of the color datatype - * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00) - * @param {PImage} image an instance of a PImage to use as a background - * - * @see #stroke() - * @see #fill() - * @see #tint() - * @see #colorMode() - */ - var backgroundHelper = function(arg1, arg2, arg3, arg4) { - var obj; - - if (arg1 instanceof PImage || arg1.__isPImage) { - obj = arg1; - - if (!obj.loaded) { - throw "Error using image in background(): PImage not loaded."; - } - if(obj.width !== p.width || obj.height !== p.height){ - throw "Background image must be the same dimensions as the canvas."; - } - } else { - obj = p.color(arg1, arg2, arg3, arg4); - } - - backgroundObj = obj; - }; - - Drawing2D.prototype.background = function(arg1, arg2, arg3, arg4) { - if (arg1 !== undef) { - backgroundHelper(arg1, arg2, arg3, arg4); - } - - if (backgroundObj instanceof PImage || backgroundObj.__isPImage) { - saveContext(); - curContext.setTransform(1, 0, 0, 1, 0, 0); - p.image(backgroundObj, 0, 0); - restoreContext(); - } else { - saveContext(); - curContext.setTransform(1, 0, 0, 1, 0, 0); - - // If the background is transparent - if (p.alpha(backgroundObj) !== colorModeA) { - curContext.clearRect(0,0, p.width, p.height); - } - curContext.fillStyle = p.color.toString(backgroundObj); - curContext.fillRect(0, 0, p.width, p.height); - isFillDirty = true; - restoreContext(); - } - }; - - Drawing3D.prototype.background = function(arg1, arg2, arg3, arg4) { - if (arguments.length > 0) { - backgroundHelper(arg1, arg2, arg3, arg4); - } - - var c = p.color.toGLArray(backgroundObj); - curContext.clearColor(c[0], c[1], c[2], c[3]); - curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT); - - // An image as a background in 3D is not implemented yet - }; - - // Draws an image to the Canvas - /** - * Displays images to the screen. The images must be in the sketch's "data" directory to load correctly. Select "Add - * file..." from the "Sketch" menu to add the image. Processing currently works with GIF, JPEG, and Targa images. The - * color of an image may be modified with the tint() function and if a GIF has transparency, it will maintain its - * transparency. The img parameter specifies the image to display and the x and y parameters define the location of - * the image from its upper-left corner. The image is displayed at its original size unless the width and height - * parameters specify a different size. The imageMode() function changes the way the parameters work. A call to - * imageMode(CORNERS) will change the width and height parameters to define the x and y values of the opposite - * corner of the image. - * - * @param {PImage} img the image to display - * @param {int|float} x x-coordinate of the image - * @param {int|float} y y-coordinate of the image - * @param {int|float} width width to display the image - * @param {int|float} height height to display the image - * - * @see loadImage - * @see PImage - * @see imageMode - * @see tint - * @see background - * @see alpha - */ - Drawing2D.prototype.image = function(img, x, y, w, h) { - // Fix fractional positions - x = Math.round(x); - y = Math.round(y); - - if (img.width > 0) { - var wid = w || img.width; - var hgt = h || img.height; - - var bounds = imageModeConvert(x || 0, y || 0, w || img.width, h || img.height, arguments.length < 4); - var fastImage = !!img.sourceImg && curTint === null; - if (fastImage) { - var htmlElement = img.sourceImg; - if (img.__isDirty) { - img.updatePixels(); - } - // Using HTML element's width and height in case if the image was resized. - curContext.drawImage(htmlElement, 0, 0, - htmlElement.width, htmlElement.height, bounds.x, bounds.y, bounds.w, bounds.h); - } else { - var obj = img.toImageData(); - - // Tint the image - if (curTint !== null) { - curTint(obj); - img.__isDirty = true; - } - - curContext.drawImage(getCanvasData(obj).canvas, 0, 0, - img.width, img.height, bounds.x, bounds.y, bounds.w, bounds.h); - } - } - }; - - Drawing3D.prototype.image = function(img, x, y, w, h) { - if (img.width > 0) { - // Fix fractional positions - x = Math.round(x); - y = Math.round(y); - w = w || img.width; - h = h || img.height; - - p.beginShape(p.QUADS); - p.texture(img); - p.vertex(x, y, 0, 0, 0); - p.vertex(x, y+h, 0, 0, h); - p.vertex(x+w, y+h, 0, w, h); - p.vertex(x+w, y, 0, w, 0); - p.endShape(); - } - }; - - /** - * The tint() function sets the fill value for displaying images. Images can be tinted to - * specified colors or made transparent by setting the alpha. - * <br><br>To make an image transparent, but not change it's color, - * use white as the tint color and specify an alpha value. For instance, - * tint(255, 128) will make an image 50% transparent (unless - * <b>colorMode()</b> has been used). - * - * <br><br>When using hexadecimal notation to specify a color, use "#" or - * "0x" before the values (e.g. #CCFFAA, 0xFFCCFFAA). The # syntax uses six - * digits to specify a color (the way colors are specified in HTML and CSS). - * When using the hexadecimal notation starting with "0x", the hexadecimal - * value must be specified with eight characters; the first two characters - * define the alpha component and the remainder the red, green, and blue - * components. - * <br><br>The value for the parameter "gray" must be less than or equal - * to the current maximum value as specified by <b>colorMode()</b>. - * The default maximum value is 255. - * <br><br>The tint() method is also used to control the coloring of - * textures in 3D. - * - * @param {int|float} gray any valid number - * @param {int|float} alpha opacity of the image - * @param {int|float} value1 red or hue value - * @param {int|float} value2 green or saturation value - * @param {int|float} value3 blue or brightness value - * @param {int|float} color any value of the color datatype - * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00) - * - * @see #noTint() - * @see #image() - */ - p.tint = function(a1, a2, a3, a4) { - var tintColor = p.color(a1, a2, a3, a4); - var r = p.red(tintColor) / colorModeX; - var g = p.green(tintColor) / colorModeY; - var b = p.blue(tintColor) / colorModeZ; - var a = p.alpha(tintColor) / colorModeA; - curTint = function(obj) { - var data = obj.data, - length = 4 * obj.width * obj.height; - for (var i = 0; i < length;) { - data[i++] *= r; - data[i++] *= g; - data[i++] *= b; - data[i++] *= a; - } - }; - // for overriding the color buffer when 3d rendering - curTint3d = function(data){ - for (var i = 0; i < data.length;) { - data[i++] = r; - data[i++] = g; - data[i++] = b; - data[i++] = a; - } - }; - }; - - /** - * The noTint() function removes the current fill value for displaying images and reverts to displaying images with their original hues. - * - * @see #tint() - * @see #image() - */ - p.noTint = function() { - curTint = null; - curTint3d = null; - }; - - /** - * Copies a region of pixels from the display window to another area of the display window and copies a region of pixels from an - * image used as the srcImg parameter into the display window. If the source and destination regions aren't the same size, it will - * automatically resize the source pixels to fit the specified target region. No alpha information is used in the process, however - * if the source image has an alpha channel set, it will be copied as well. This function ignores imageMode(). - * - * @param {int} x X coordinate of the source's upper left corner - * @param {int} y Y coordinate of the source's upper left corner - * @param {int} width source image width - * @param {int} height source image height - * @param {int} dx X coordinate of the destination's upper left corner - * @param {int} dy Y coordinate of the destination's upper left corner - * @param {int} dwidth destination image width - * @param {int} dheight destination image height - * @param {PImage} srcImg image variable referring to the source image - * - * @see blend - * @see get - */ - p.copy = function(src, sx, sy, sw, sh, dx, dy, dw, dh) { - if (dh === undef) { - // shift everything, and introduce p - dh = dw; - dw = dy; - dy = dx; - dx = sh; - sh = sw; - sw = sy; - sy = sx; - sx = src; - src = p; - } - p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, PConstants.REPLACE); - }; - - /** - * Blends a region of pixels from one image into another (or in itself again) with full alpha channel support. There - * is a choice of the following modes to blend the source pixels (A) with the ones of pixels in the destination image (B): - * BLEND - linear interpolation of colours: C = A*factor + B - * ADD - additive blending with white clip: C = min(A*factor + B, 255) - * SUBTRACT - subtractive blending with black clip: C = max(B - A*factor, 0) - * DARKEST - only the darkest colour succeeds: C = min(A*factor, B) - * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B) - * DIFFERENCE - subtract colors from underlying image. - * EXCLUSION - similar to DIFFERENCE, but less extreme. - * MULTIPLY - Multiply the colors, result will always be darker. - * SCREEN - Opposite multiply, uses inverse values of the colors. - * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and screens light values. - * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower. - * SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not as harsh. - * DODGE - Lightens light tones and increases contrast, ignores darks. Called "Color Dodge" in Illustrator and Photoshop. - * BURN - Darker areas are applied, increasing contrast, ignores lights. Called "Color Burn" in Illustrator and Photoshop. - * All modes use the alpha information (highest byte) of source image pixels as the blending factor. If the source and - * destination regions are different sizes, the image will be automatically resized to match the destination size. If the - * srcImg parameter is not used, the display window is used as the source image. This function ignores imageMode(). - * - * @param {int} x X coordinate of the source's upper left corner - * @param {int} y Y coordinate of the source's upper left corner - * @param {int} width source image width - * @param {int} height source image height - * @param {int} dx X coordinate of the destination's upper left corner - * @param {int} dy Y coordinate of the destination's upper left corner - * @param {int} dwidth destination image width - * @param {int} dheight destination image height - * @param {PImage} srcImg image variable referring to the source image - * @param {PImage} MODE Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, - * OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN - * @see filter - */ - p.blend = function(src, sx, sy, sw, sh, dx, dy, dw, dh, mode, pimgdest) { - if (src.isRemote) { - throw "Image is loaded remotely. Cannot blend image."; - } - - if (mode === undef) { - // shift everything, and introduce p - mode = dh; - dh = dw; - dw = dy; - dy = dx; - dx = sh; - sh = sw; - sw = sy; - sy = sx; - sx = src; - src = p; - } - - var sx2 = sx + sw, - sy2 = sy + sh, - dx2 = dx + dw, - dy2 = dy + dh, - dest = pimgdest || p; - - // check if pimgdest is there and pixels, if so this was a call from pimg.blend - if (pimgdest === undef || mode === undef) { - p.loadPixels(); - } - - src.loadPixels(); - - if (src === p && p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) { - p.blit_resize(p.get(sx, sy, sx2 - sx, sy2 - sy), 0, 0, sx2 - sx - 1, sy2 - sy - 1, - dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); - } else { - p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); - } - - if (pimgdest === undef) { - p.updatePixels(); - } - }; - - // helper function for filter() - var buildBlurKernel = function(r) { - var radius = p.floor(r * 3.5), i; - radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248); - if (p.shared.blurRadius !== radius) { - p.shared.blurRadius = radius; - p.shared.blurKernelSize = 1 + (p.shared.blurRadius<<1); - p.shared.blurKernel = new Float32Array(p.shared.blurKernelSize); - var sharedBlurKernal = p.shared.blurKernel; - var sharedBlurKernelSize = p.shared.blurKernelSize; - var sharedBlurRadius = p.shared.blurRadius; - // init blurKernel - for (i = 0; i < sharedBlurKernelSize; i++) { - sharedBlurKernal[i] = 0; - } - var radiusiSquared = (radius - 1) * (radius - 1); - for (i = 1; i < radius; i++) { - sharedBlurKernal[radius + i] = sharedBlurKernal[radius-i] = radiusiSquared; - } - sharedBlurKernal[radius] = radius * radius; - } - }; - - var blurARGB = function(r, aImg) { - var sum, cr, cg, cb, ca, c, m; - var read, ri, ym, ymi, bk0; - var wh = aImg.pixels.getLength(); - var r2 = new Float32Array(wh); - var g2 = new Float32Array(wh); - var b2 = new Float32Array(wh); - var a2 = new Float32Array(wh); - var yi = 0; - var x, y, i, offset; - - buildBlurKernel(r); - - var aImgHeight = aImg.height; - var aImgWidth = aImg.width; - var sharedBlurKernelSize = p.shared.blurKernelSize; - var sharedBlurRadius = p.shared.blurRadius; - var sharedBlurKernal = p.shared.blurKernel; - var pix = aImg.imageData.data; - - for (y = 0; y < aImgHeight; y++) { - for (x = 0; x < aImgWidth; x++) { - cb = cg = cr = ca = sum = 0; - read = x - sharedBlurRadius; - if (read<0) { - bk0 = -read; - read = 0; - } else { - if (read >= aImgWidth) { - break; - } - bk0=0; - } - for (i = bk0; i < sharedBlurKernelSize; i++) { - if (read >= aImgWidth) { - break; - } - offset = (read + yi) *4; - m = sharedBlurKernal[i]; - ca += m * pix[offset + 3]; - cr += m * pix[offset]; - cg += m * pix[offset + 1]; - cb += m * pix[offset + 2]; - sum += m; - read++; - } - ri = yi + x; - a2[ri] = ca / sum; - r2[ri] = cr / sum; - g2[ri] = cg / sum; - b2[ri] = cb / sum; - } - yi += aImgWidth; - } - - yi = 0; - ym = -sharedBlurRadius; - ymi = ym*aImgWidth; - - for (y = 0; y < aImgHeight; y++) { - for (x = 0; x < aImgWidth; x++) { - cb = cg = cr = ca = sum = 0; - if (ym<0) { - bk0 = ri = -ym; - read = x; - } else { - if (ym >= aImgHeight) { - break; - } - bk0 = 0; - ri = ym; - read = x + ymi; - } - for (i = bk0; i < sharedBlurKernelSize; i++) { - if (ri >= aImgHeight) { - break; - } - m = sharedBlurKernal[i]; - ca += m * a2[read]; - cr += m * r2[read]; - cg += m * g2[read]; - cb += m * b2[read]; - sum += m; - ri++; - read += aImgWidth; - } - offset = (x + yi) *4; - pix[offset] = cr / sum; - pix[offset + 1] = cg / sum; - pix[offset + 2] = cb / sum; - pix[offset + 3] = ca / sum; - } - yi += aImgWidth; - ymi += aImgWidth; - ym++; - } - }; - - // helper funtion for ERODE and DILATE modes of filter() - var dilate = function(isInverted, aImg) { - var currIdx = 0; - var maxIdx = aImg.pixels.getLength(); - var out = new Int32Array(maxIdx); - var currRowIdx, maxRowIdx, colOrig, colOut, currLum; - var idxRight, idxLeft, idxUp, idxDown, - colRight, colLeft, colUp, colDown, - lumRight, lumLeft, lumUp, lumDown; - - if (!isInverted) { - // erosion (grow light areas) - while (currIdx<maxIdx) { - currRowIdx = currIdx; - maxRowIdx = currIdx + aImg.width; - while (currIdx < maxRowIdx) { - colOrig = colOut = aImg.pixels.getPixel(currIdx); - idxLeft = currIdx - 1; - idxRight = currIdx + 1; - idxUp = currIdx - aImg.width; - idxDown = currIdx + aImg.width; - if (idxLeft < currRowIdx) { - idxLeft = currIdx; - } - if (idxRight >= maxRowIdx) { - idxRight = currIdx; - } - if (idxUp < 0) { - idxUp = 0; - } - if (idxDown >= maxIdx) { - idxDown = currIdx; - } - colUp = aImg.pixels.getPixel(idxUp); - colLeft = aImg.pixels.getPixel(idxLeft); - colDown = aImg.pixels.getPixel(idxDown); - colRight = aImg.pixels.getPixel(idxRight); - - // compute luminance - currLum = 77*(colOrig>>16&0xff) + 151*(colOrig>>8&0xff) + 28*(colOrig&0xff); - lumLeft = 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff); - lumRight = 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff); - lumUp = 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff); - lumDown = 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff); - - if (lumLeft > currLum) { - colOut = colLeft; - currLum = lumLeft; - } - if (lumRight > currLum) { - colOut = colRight; - currLum = lumRight; - } - if (lumUp > currLum) { - colOut = colUp; - currLum = lumUp; - } - if (lumDown > currLum) { - colOut = colDown; - currLum = lumDown; - } - out[currIdx++] = colOut; - } - } - } else { - // dilate (grow dark areas) - while (currIdx < maxIdx) { - currRowIdx = currIdx; - maxRowIdx = currIdx + aImg.width; - while (currIdx < maxRowIdx) { - colOrig = colOut = aImg.pixels.getPixel(currIdx); - idxLeft = currIdx - 1; - idxRight = currIdx + 1; - idxUp = currIdx - aImg.width; - idxDown = currIdx + aImg.width; - if (idxLeft < currRowIdx) { - idxLeft = currIdx; - } - if (idxRight >= maxRowIdx) { - idxRight = currIdx; - } - if (idxUp < 0) { - idxUp = 0; - } - if (idxDown >= maxIdx) { - idxDown = currIdx; - } - colUp = aImg.pixels.getPixel(idxUp); - colLeft = aImg.pixels.getPixel(idxLeft); - colDown = aImg.pixels.getPixel(idxDown); - colRight = aImg.pixels.getPixel(idxRight); - - // compute luminance - currLum = 77*(colOrig>>16&0xff) + 151*(colOrig>>8&0xff) + 28*(colOrig&0xff); - lumLeft = 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff); - lumRight = 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff); - lumUp = 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff); - lumDown = 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff); - - if (lumLeft < currLum) { - colOut = colLeft; - currLum = lumLeft; - } - if (lumRight < currLum) { - colOut = colRight; - currLum = lumRight; - } - if (lumUp < currLum) { - colOut = colUp; - currLum = lumUp; - } - if (lumDown < currLum) { - colOut = colDown; - currLum = lumDown; - } - out[currIdx++]=colOut; - } - } - } - aImg.pixels.set(out); - //p.arraycopy(out,0,pixels,0,maxIdx); - }; - - /** - * Filters the display window as defined by one of the following modes: - * THRESHOLD - converts the image to black and white pixels depending if they are above or below the threshold - * defined by the level parameter. The level must be between 0.0 (black) and 1.0(white). If no level is specified, 0.5 is used. - * GRAY - converts any colors in the image to grayscale equivalents - * INVERT - sets each pixel to its inverse value - * POSTERIZE - limits each channel of the image to the number of colors specified as the level parameter - * BLUR - executes a Guassian blur with the level parameter specifying the extent of the blurring. If no level parameter is - * used, the blur is equivalent to Guassian blur of radius 1. - * OPAQUE - sets the alpha channel to entirely opaque. - * ERODE - reduces the light areas with the amount defined by the level parameter. - * DILATE - increases the light areas with the amount defined by the level parameter. - * - * @param {MODE} MODE Either THRESHOLD, GRAY, INVERT, POSTERIZE, BLUR, OPAQUE, ERODE, or DILATE - * @param {int|float} level defines the quality of the filter - * - * @see blend - */ - p.filter = function(kind, param, aImg){ - var img, col, lum, i; - - if (arguments.length === 3) { - aImg.loadPixels(); - img = aImg; - } else { - p.loadPixels(); - img = p; - } - - if (param === undef) { - param = null; - } - if (img.isRemote) { // Remote images cannot access imageData - throw "Image is loaded remotely. Cannot filter image."; - } - // begin filter process - var imglen = img.pixels.getLength(); - switch (kind) { - case PConstants.BLUR: - var radius = param || 1; // if no param specified, use 1 (default for p5) - blurARGB(radius, img); - break; - - case PConstants.GRAY: - if (img.format === PConstants.ALPHA) { //trouble - // for an alpha image, convert it to an opaque grayscale - for (i = 0; i < imglen; i++) { - col = 255 - img.pixels.getPixel(i); - img.pixels.setPixel(i,(0xff000000 | (col << 16) | (col << 8) | col)); - } - img.format = PConstants.RGB; //trouble - } else { - for (i = 0; i < imglen; i++) { - col = img.pixels.getPixel(i); - lum = (77*(col>>16&0xff) + 151*(col>>8&0xff) + 28*(col&0xff))>>8; - img.pixels.setPixel(i,((col & PConstants.ALPHA_MASK) | lum<<16 | lum<<8 | lum)); - } - } - break; - - case PConstants.INVERT: - for (i = 0; i < imglen; i++) { - img.pixels.setPixel(i, (img.pixels.getPixel(i) ^ 0xffffff)); - } - break; - - case PConstants.POSTERIZE: - if (param === null) { - throw "Use filter(POSTERIZE, int levels) instead of filter(POSTERIZE)"; - } - var levels = p.floor(param); - if ((levels < 2) || (levels > 255)) { - throw "Levels must be between 2 and 255 for filter(POSTERIZE, levels)"; - } - var levels1 = levels - 1; - for (i = 0; i < imglen; i++) { - var rlevel = (img.pixels.getPixel(i) >> 16) & 0xff; - var glevel = (img.pixels.getPixel(i) >> 8) & 0xff; - var blevel = img.pixels.getPixel(i) & 0xff; - rlevel = (((rlevel * levels) >> 8) * 255) / levels1; - glevel = (((glevel * levels) >> 8) * 255) / levels1; - blevel = (((blevel * levels) >> 8) * 255) / levels1; - img.pixels.setPixel(i, ((0xff000000 & img.pixels.getPixel(i)) | (rlevel << 16) | (glevel << 8) | blevel)); - } - break; - - case PConstants.OPAQUE: - for (i = 0; i < imglen; i++) { - img.pixels.setPixel(i, (img.pixels.getPixel(i) | 0xff000000)); - } - img.format = PConstants.RGB; //trouble - break; - - case PConstants.THRESHOLD: - if (param === null) { - param = 0.5; - } - if ((param < 0) || (param > 1)) { - throw "Level must be between 0 and 1 for filter(THRESHOLD, level)"; - } - var thresh = p.floor(param * 255); - for (i = 0; i < imglen; i++) { - var max = p.max((img.pixels.getPixel(i) & PConstants.RED_MASK) >> 16, p.max((img.pixels.getPixel(i) & PConstants.GREEN_MASK) >> 8, (img.pixels.getPixel(i) & PConstants.BLUE_MASK))); - img.pixels.setPixel(i, ((img.pixels.getPixel(i) & PConstants.ALPHA_MASK) | ((max < thresh) ? 0x000000 : 0xffffff))); - } - break; - - case PConstants.ERODE: - dilate(true, img); - break; - - case PConstants.DILATE: - dilate(false, img); - break; - } - img.updatePixels(); - }; - - - // shared variables for blit_resize(), filter_new_scanline(), filter_bilinear(), filter() - // change this in the future to not be exposed to p - p.shared = { - fracU: 0, - ifU: 0, - fracV: 0, - ifV: 0, - u1: 0, - u2: 0, - v1: 0, - v2: 0, - sX: 0, - sY: 0, - iw: 0, - iw1: 0, - ih1: 0, - ul: 0, - ll: 0, - ur: 0, - lr: 0, - cUL: 0, - cLL: 0, - cUR: 0, - cLR: 0, - srcXOffset: 0, - srcYOffset: 0, - r: 0, - g: 0, - b: 0, - a: 0, - srcBuffer: null, - blurRadius: 0, - blurKernelSize: 0, - blurKernel: null - }; - - p.intersect = function(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) { - var sw = sx2 - sx1 + 1; - var sh = sy2 - sy1 + 1; - var dw = dx2 - dx1 + 1; - var dh = dy2 - dy1 + 1; - if (dx1 < sx1) { - dw += dx1 - sx1; - if (dw > sw) { - dw = sw; - } - } else { - var w = sw + sx1 - dx1; - if (dw > w) { - dw = w; - } - } - if (dy1 < sy1) { - dh += dy1 - sy1; - if (dh > sh) { - dh = sh; - } - } else { - var h = sh + sy1 - dy1; - if (dh > h) { - dh = h; - } - } - return ! (dw <= 0 || dh <= 0); - }; - - var blendFuncs = {}; - blendFuncs[PConstants.BLEND] = p.modes.blend; - blendFuncs[PConstants.ADD] = p.modes.add; - blendFuncs[PConstants.SUBTRACT] = p.modes.subtract; - blendFuncs[PConstants.LIGHTEST] = p.modes.lightest; - blendFuncs[PConstants.DARKEST] = p.modes.darkest; - blendFuncs[PConstants.REPLACE] = p.modes.replace; - blendFuncs[PConstants.DIFFERENCE] = p.modes.difference; - blendFuncs[PConstants.EXCLUSION] = p.modes.exclusion; - blendFuncs[PConstants.MULTIPLY] = p.modes.multiply; - blendFuncs[PConstants.SCREEN] = p.modes.screen; - blendFuncs[PConstants.OVERLAY] = p.modes.overlay; - blendFuncs[PConstants.HARD_LIGHT] = p.modes.hard_light; - blendFuncs[PConstants.SOFT_LIGHT] = p.modes.soft_light; - blendFuncs[PConstants.DODGE] = p.modes.dodge; - blendFuncs[PConstants.BURN] = p.modes.burn; - - p.blit_resize = function(img, srcX1, srcY1, srcX2, srcY2, destPixels, - screenW, screenH, destX1, destY1, destX2, destY2, mode) { - var x, y; - if (srcX1 < 0) { - srcX1 = 0; - } - if (srcY1 < 0) { - srcY1 = 0; - } - if (srcX2 >= img.width) { - srcX2 = img.width - 1; - } - if (srcY2 >= img.height) { - srcY2 = img.height - 1; - } - var srcW = srcX2 - srcX1; - var srcH = srcY2 - srcY1; - var destW = destX2 - destX1; - var destH = destY2 - destY1; - - if (destW <= 0 || destH <= 0 || srcW <= 0 || srcH <= 0 || destX1 >= screenW || - destY1 >= screenH || srcX1 >= img.width || srcY1 >= img.height) { - return; - } - - var dx = Math.floor(srcW / destW * PConstants.PRECISIONF); - var dy = Math.floor(srcH / destH * PConstants.PRECISIONF); - - var pshared = p.shared; - - pshared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * PConstants.PRECISIONF); - pshared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * PConstants.PRECISIONF); - if (destX1 < 0) { - destW += destX1; - destX1 = 0; - } - if (destY1 < 0) { - destH += destY1; - destY1 = 0; - } - destW = Math.min(destW, screenW - destX1); - destH = Math.min(destH, screenH - destY1); - - var destOffset = destY1 * screenW + destX1; - var destColor; - - pshared.srcBuffer = img.imageData.data; - pshared.iw = img.width; - pshared.iw1 = img.width - 1; - pshared.ih1 = img.height - 1; - - // cache for speed - var filterBilinear = p.filter_bilinear, - filterNewScanline = p.filter_new_scanline, - blendFunc = blendFuncs[mode], - blendedColor, - idx, - cULoffset, - cURoffset, - cLLoffset, - cLRoffset, - ALPHA_MASK = PConstants.ALPHA_MASK, - RED_MASK = PConstants.RED_MASK, - GREEN_MASK = PConstants.GREEN_MASK, - BLUE_MASK = PConstants.BLUE_MASK, - PREC_MAXVAL = PConstants.PREC_MAXVAL, - PRECISIONB = PConstants.PRECISIONB, - PREC_RED_SHIFT = PConstants.PREC_RED_SHIFT, - PREC_ALPHA_SHIFT = PConstants.PREC_ALPHA_SHIFT, - srcBuffer = pshared.srcBuffer, - min = Math.min; - - for (y = 0; y < destH; y++) { - - pshared.sX = pshared.srcXOffset; - pshared.fracV = pshared.srcYOffset & PREC_MAXVAL; - pshared.ifV = PREC_MAXVAL - pshared.fracV; - pshared.v1 = (pshared.srcYOffset >> PRECISIONB) * pshared.iw; - pshared.v2 = min((pshared.srcYOffset >> PRECISIONB) + 1, pshared.ih1) * pshared.iw; - - for (x = 0; x < destW; x++) { - idx = (destOffset + x) * 4; - - destColor = (destPixels[idx + 3] << 24) & - ALPHA_MASK | (destPixels[idx] << 16) & - RED_MASK | (destPixels[idx + 1] << 8) & - GREEN_MASK | destPixels[idx + 2] & BLUE_MASK; - - pshared.fracU = pshared.sX & PREC_MAXVAL; - pshared.ifU = PREC_MAXVAL - pshared.fracU; - pshared.ul = (pshared.ifU * pshared.ifV) >> PRECISIONB; - pshared.ll = (pshared.ifU * pshared.fracV) >> PRECISIONB; - pshared.ur = (pshared.fracU * pshared.ifV) >> PRECISIONB; - pshared.lr = (pshared.fracU * pshared.fracV) >> PRECISIONB; - pshared.u1 = (pshared.sX >> PRECISIONB); - pshared.u2 = min(pshared.u1 + 1, pshared.iw1); - - cULoffset = (pshared.v1 + pshared.u1) * 4; - cURoffset = (pshared.v1 + pshared.u2) * 4; - cLLoffset = (pshared.v2 + pshared.u1) * 4; - cLRoffset = (pshared.v2 + pshared.u2) * 4; - - pshared.cUL = (srcBuffer[cULoffset + 3] << 24) & - ALPHA_MASK | (srcBuffer[cULoffset] << 16) & - RED_MASK | (srcBuffer[cULoffset + 1] << 8) & - GREEN_MASK | srcBuffer[cULoffset + 2] & BLUE_MASK; - - pshared.cUR = (srcBuffer[cURoffset + 3] << 24) & - ALPHA_MASK | (srcBuffer[cURoffset] << 16) & - RED_MASK | (srcBuffer[cURoffset + 1] << 8) & - GREEN_MASK | srcBuffer[cURoffset + 2] & BLUE_MASK; - - pshared.cLL = (srcBuffer[cLLoffset + 3] << 24) & - ALPHA_MASK | (srcBuffer[cLLoffset] << 16) & - RED_MASK | (srcBuffer[cLLoffset + 1] << 8) & - GREEN_MASK | srcBuffer[cLLoffset + 2] & BLUE_MASK; - - pshared.cLR = (srcBuffer[cLRoffset + 3] << 24) & - ALPHA_MASK | (srcBuffer[cLRoffset] << 16) & - RED_MASK | (srcBuffer[cLRoffset + 1] << 8) & - GREEN_MASK | srcBuffer[cLRoffset + 2] & BLUE_MASK; - - pshared.r = ((pshared.ul * ((pshared.cUL & RED_MASK) >> 16) + - pshared.ll * ((pshared.cLL & RED_MASK) >> 16) + - pshared.ur * ((pshared.cUR & RED_MASK) >> 16) + - pshared.lr * ((pshared.cLR & RED_MASK) >> 16)) << PREC_RED_SHIFT) & RED_MASK; - pshared.g = ((pshared.ul * (pshared.cUL & GREEN_MASK) + - pshared.ll * (pshared.cLL & GREEN_MASK) + - pshared.ur * (pshared.cUR & GREEN_MASK) + - pshared.lr * (pshared.cLR & GREEN_MASK)) >>> PRECISIONB) & GREEN_MASK; - pshared.b = (pshared.ul * (pshared.cUL & BLUE_MASK) + - pshared.ll * (pshared.cLL & BLUE_MASK) + - pshared.ur * (pshared.cUR & BLUE_MASK) + - pshared.lr * (pshared.cLR & BLUE_MASK)) >>> PRECISIONB; - pshared.a = ((pshared.ul * ((pshared.cUL & ALPHA_MASK) >>> 24) + - pshared.ll * ((pshared.cLL & ALPHA_MASK) >>> 24) + - pshared.ur * ((pshared.cUR & ALPHA_MASK) >>> 24) + - pshared.lr * ((pshared.cLR & ALPHA_MASK) >>> 24)) << PREC_ALPHA_SHIFT) & ALPHA_MASK; - - blendedColor = blendFunc(destColor, (pshared.a | pshared.r | pshared.g | pshared.b)); - - destPixels[idx] = (blendedColor & RED_MASK) >>> 16; - destPixels[idx + 1] = (blendedColor & GREEN_MASK) >>> 8; - destPixels[idx + 2] = (blendedColor & BLUE_MASK); - destPixels[idx + 3] = (blendedColor & ALPHA_MASK) >>> 24; - - pshared.sX += dx; - } - destOffset += screenW; - pshared.srcYOffset += dy; - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Font handling - //////////////////////////////////////////////////////////////////////////// - - /** - * loadFont() Loads a font into a variable of type PFont. - * - * @param {String} name filename of the font to load - * @param {int|float} size option font size (used internally) - * - * @returns {PFont} new PFont object - * - * @see #PFont - * @see #textFont - * @see #text - * @see #createFont - */ - p.loadFont = function(name, size) { - if (name === undef) { - throw("font name required in loadFont."); - } - if (name.indexOf(".svg") === -1) { - if (size === undef) { - size = curTextFont.size; - } - return PFont.get(name, size); - } - // If the font is a glyph, calculate by SVG table - var font = p.loadGlyphs(name); - - return { - name: name, - css: '12px sans-serif', - glyph: true, - units_per_em: font.units_per_em, - horiz_adv_x: 1 / font.units_per_em * font.horiz_adv_x, - ascent: font.ascent, - descent: font.descent, - width: function(str) { - var width = 0; - var len = str.length; - for (var i = 0; i < len; i++) { - try { - width += parseFloat(p.glyphLook(p.glyphTable[name], str[i]).horiz_adv_x); - } - catch(e) { - Processing.debug(e); - } - } - return width / p.glyphTable[name].units_per_em; - } - }; - }; - - /** - * createFont() Loads a font into a variable of type PFont. - * Smooth and charset are ignored in Processing.js. - * - * @param {String} name filename of the font to load - * @param {int|float} size font size in pixels - * @param {boolean} smooth not used in Processing.js - * @param {char[]} charset not used in Processing.js - * - * @returns {PFont} new PFont object - * - * @see #PFont - * @see #textFont - * @see #text - * @see #loadFont - */ - p.createFont = function(name, size) { - // because Processing.js only deals with real fonts, - // createFont is simply a wrapper for loadFont/2 - return p.loadFont(name, size); - }; - - /** - * textFont() Sets the current font. - * - * @param {PFont} pfont the PFont to load as current text font - * @param {int|float} size optional font size in pixels - * - * @see #createFont - * @see #loadFont - * @see #PFont - * @see #text - */ - p.textFont = function(pfont, size) { - if (size !== undef) { - // If we're using an SVG glyph font, don't load from cache - if (!pfont.glyph) { - pfont = PFont.get(pfont.name, size); - } - curTextSize = size; - } - curTextFont = pfont; - curFontName = curTextFont.name; - curTextAscent = curTextFont.ascent; - curTextDescent = curTextFont.descent; - curTextLeading = curTextFont.leading; - var curContext = drawing.$ensureContext(); - curContext.font = curTextFont.css; - }; - - /** - * textSize() Sets the current font size in pixels. - * - * @param {int|float} size font size in pixels - * - * @see #textFont - * @see #loadFont - * @see #PFont - * @see #text - */ - p.textSize = function(size) { - curTextFont = PFont.get(curFontName, size); - curTextSize = size; - // recache metrics - curTextAscent = curTextFont.ascent; - curTextDescent = curTextFont.descent; - curTextLeading = curTextFont.leading; - var curContext = drawing.$ensureContext(); - curContext.font = curTextFont.css; - }; - - /** - * textAscent() returns the maximum height a character extends above the baseline of the - * current font at its current size, in pixels. - * - * @returns {float} height of the current font above the baseline, at its current size, in pixels - * - * @see #textDescent - */ - p.textAscent = function() { - return curTextAscent; - }; - - /** - * textDescent() returns the maximum depth a character will protrude below the baseline of - * the current font at its current size, in pixels. - * - * @returns {float} depth of the current font below the baseline, at its current size, in pixels - * - * @see #textAscent - */ - p.textDescent = function() { - return curTextDescent; - }; - - /** - * textLeading() Sets the current font's leading, which is the distance - * from baseline to baseline over consecutive lines, with additional vertical - * spacing taking into account. Usually this value is 1.2 or 1.25 times the - * textsize, but this value can be changed to effect vertically compressed - * or stretched text. - * - * @param {int|float} the desired baseline-to-baseline size in pixels - */ - p.textLeading = function(leading) { - curTextLeading = leading; - }; - - /** - * textAlign() Sets the current alignment for drawing text. - * - * @param {int} ALIGN Horizontal alignment, either LEFT, CENTER, or RIGHT - * @param {int} YALIGN optional vertical alignment, either TOP, BOTTOM, CENTER, or BASELINE - * - * @see #loadFont - * @see #PFont - * @see #text - */ - p.textAlign = function(xalign, yalign) { - horizontalTextAlignment = xalign; - verticalTextAlignment = yalign || PConstants.BASELINE; - }; - - /** - * toP5String converts things with arbitrary data type into - * string values, for text rendering. - * - * @param {any} any object that can be converted into a string - * - * @return {String} the string representation of the input - */ - function toP5String(obj) { - if(obj instanceof String) { - return obj; - } - if(typeof obj === 'number') { - // check if an int - if(obj === (0 | obj)) { - return obj.toString(); - } - return p.nf(obj, 0, 3); - } - if(obj === null || obj === undef) { - return ""; - } - return obj.toString(); - } - - /** - * textWidth() Calculates and returns the width of any character or text string in pixels. - * - * @param {char|String} str char or String to be measured - * - * @return {float} width of char or String in pixels - * - * @see #loadFont - * @see #PFont - * @see #text - * @see #textFont - */ - Drawing2D.prototype.textWidth = function(str) { - var lines = toP5String(str).split(/\r?\n/g), width = 0; - var i, linesCount = lines.length; - - curContext.font = curTextFont.css; - for (i = 0; i < linesCount; ++i) { - width = Math.max(width, curTextFont.measureTextWidth(lines[i])); - } - return width | 0; - }; - - Drawing3D.prototype.textWidth = function(str) { - var lines = toP5String(str).split(/\r?\n/g), width = 0; - var i, linesCount = lines.length; - if (textcanvas === undef) { - textcanvas = document.createElement("canvas"); - } - - var textContext = textcanvas.getContext("2d"); - textContext.font = curTextFont.css; - - for (i = 0; i < linesCount; ++i) { - width = Math.max(width, textContext.measureText(lines[i]).width); - } - return width | 0; - }; - - // A lookup table for characters that can not be referenced by Object - p.glyphLook = function(font, chr) { - try { - switch (chr) { - case "1": - return font.one; - case "2": - return font.two; - case "3": - return font.three; - case "4": - return font.four; - case "5": - return font.five; - case "6": - return font.six; - case "7": - return font.seven; - case "8": - return font.eight; - case "9": - return font.nine; - case "0": - return font.zero; - case " ": - return font.space; - case "$": - return font.dollar; - case "!": - return font.exclam; - case '"': - return font.quotedbl; - case "#": - return font.numbersign; - case "%": - return font.percent; - case "&": - return font.ampersand; - case "'": - return font.quotesingle; - case "(": - return font.parenleft; - case ")": - return font.parenright; - case "*": - return font.asterisk; - case "+": - return font.plus; - case ",": - return font.comma; - case "-": - return font.hyphen; - case ".": - return font.period; - case "/": - return font.slash; - case "_": - return font.underscore; - case ":": - return font.colon; - case ";": - return font.semicolon; - case "<": - return font.less; - case "=": - return font.equal; - case ">": - return font.greater; - case "?": - return font.question; - case "@": - return font.at; - case "[": - return font.bracketleft; - case "\\": - return font.backslash; - case "]": - return font.bracketright; - case "^": - return font.asciicircum; - case "`": - return font.grave; - case "{": - return font.braceleft; - case "|": - return font.bar; - case "}": - return font.braceright; - case "~": - return font.asciitilde; - // If the character is not 'special', access it by object reference - default: - return font[chr]; - } - } catch(e) { - Processing.debug(e); - } - }; - - // Print some text to the Canvas - Drawing2D.prototype.text$line = function(str, x, y, z, align) { - var textWidth = 0, xOffset = 0; - // If the font is a standard Canvas font... - if (!curTextFont.glyph) { - if (str && ("fillText" in curContext)) { - if (isFillDirty) { - curContext.fillStyle = p.color.toString(currentFillColor); - isFillDirty = false; - } - - // horizontal offset/alignment - if(align === PConstants.RIGHT || align === PConstants.CENTER) { - textWidth = curTextFont.measureTextWidth(str); - - if(align === PConstants.RIGHT) { - xOffset = -textWidth; - } else { // if(align === PConstants.CENTER) - xOffset = -textWidth/2; - } - } - - curContext.fillText(str, x+xOffset, y); - } - } else { - // If the font is a Batik SVG font... - var font = p.glyphTable[curFontName]; - saveContext(); - curContext.translate(x, y + curTextSize); - - // horizontal offset/alignment - if(align === PConstants.RIGHT || align === PConstants.CENTER) { - textWidth = font.width(str); - - if(align === PConstants.RIGHT) { - xOffset = -textWidth; - } else { // if(align === PConstants.CENTER) - xOffset = -textWidth/2; - } - } - - var upem = font.units_per_em, - newScale = 1 / upem * curTextSize; - - curContext.scale(newScale, newScale); - - for (var i=0, len=str.length; i < len; i++) { - // Test character against glyph table - try { - p.glyphLook(font, str[i]).draw(); - } catch(e) { - Processing.debug(e); - } - } - restoreContext(); - } - }; - - Drawing3D.prototype.text$line = function(str, x, y, z, align) { - // handle case for 3d text - if (textcanvas === undef) { - textcanvas = document.createElement("canvas"); - } - var oldContext = curContext; - curContext = textcanvas.getContext("2d"); - curContext.font = curTextFont.css; - var textWidth = curTextFont.measureTextWidth(str); - textcanvas.width = textWidth; - textcanvas.height = curTextSize; - curContext = textcanvas.getContext("2d"); // refreshes curContext - curContext.font = curTextFont.css; - curContext.textBaseline="top"; - - // paint on 2D canvas - Drawing2D.prototype.text$line(str,0,0,0,PConstants.LEFT); - - // use it as a texture - var aspect = textcanvas.width/textcanvas.height; - curContext = oldContext; - - curContext.bindTexture(curContext.TEXTURE_2D, textTex); - curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, textcanvas); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); - // If we don't have a power of two texture, we can't mipmap it. - // curContext.generateMipmap(curContext.TEXTURE_2D); - - // horizontal offset/alignment - var xOffset = 0; - if (align === PConstants.RIGHT) { - xOffset = -textWidth; - } else if(align === PConstants.CENTER) { - xOffset = -textWidth/2; - } - var model = new PMatrix3D(); - var scalefactor = curTextSize * 0.5; - model.translate(x+xOffset-scalefactor/2, y-scalefactor, z); - model.scale(-aspect*scalefactor, -scalefactor, scalefactor); - model.translate(-1, -1, -1); - model.transpose(); - - var view = new PMatrix3D(); - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - - curContext.useProgram(programObject2D); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, textBuffer); - vertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord", 2, textureBuffer); - uniformi("uSampler2d", programObject2D, "uSampler", [0]); - - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", true); - - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", fillStyle); - curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); - curContext.drawElements(curContext.TRIANGLES, 6, curContext.UNSIGNED_SHORT, 0); - }; - - - /** - * unbounded text function (z is an optional argument) - */ - function text$4(str, x, y, z) { - var lines, linesCount; - if(str.indexOf('\n') < 0) { - lines = [str]; - linesCount = 1; - } else { - lines = str.split(/\r?\n/g); - linesCount = lines.length; - } - // handle text line-by-line - - var yOffset = 0; - if(verticalTextAlignment === PConstants.TOP) { - yOffset = curTextAscent + curTextDescent; - } else if(verticalTextAlignment === PConstants.CENTER) { - yOffset = curTextAscent/2 - (linesCount-1)*curTextLeading/2; - } else if(verticalTextAlignment === PConstants.BOTTOM) { - yOffset = -(curTextDescent + (linesCount-1)*curTextLeading); - } - - for(var i=0;i<linesCount;++i) { - var line = lines[i]; - drawing.text$line(line, x, y + yOffset, z, horizontalTextAlignment); - yOffset += curTextLeading; - } - } - - - /** - * box-bounded text function (z is an optional argument) - */ - function text$6(str, x, y, width, height, z) { - // 'fail' on 0-valued dimensions - if (str.length === 0 || width === 0 || height === 0) { - return; - } - // also 'fail' if the text height is larger than the bounding height - if(curTextSize > height) { - return; - } - - var spaceMark = -1; - var start = 0; - var lineWidth = 0; - var drawCommands = []; - - // run through text, character-by-character - for (var charPos=0, len=str.length; charPos < len; charPos++) - { - var currentChar = str[charPos]; - var spaceChar = (currentChar === " "); - var letterWidth = curTextFont.measureTextWidth(currentChar); - - // if we aren't looking at a newline, and the text still fits, keep processing - if (currentChar !== "\n" && (lineWidth + letterWidth <= width)) { - if (spaceChar) { spaceMark = charPos; } - lineWidth += letterWidth; - } - - // if we're looking at a newline, or the text no longer fits, push the section that fit into the drawcommand list - else - { - if (spaceMark + 1 === start) { - if(charPos>0) { - // Whole line without spaces so far. - spaceMark = charPos; - } else { - // 'fail', because the line can't even fit the first character - return; - } - } - - if (currentChar === "\n") { - drawCommands.push({text:str.substring(start, charPos), width: lineWidth}); - start = charPos + 1; - } else { - // current is not a newline, which means the line doesn't fit in box. push text. - // In Processing 1.5.1, the space is also pushed, so we push up to spaceMark+1, - // rather than up to spaceMark, as was the case for Processing 1.5 and earlier. - drawCommands.push({text:str.substring(start, spaceMark+1), width: lineWidth}); - start = spaceMark + 1; - } - - // newline + return - lineWidth = 0; - charPos = start - 1; - } - } - - // push the remaining text - if (start < len) { - drawCommands.push({text:str.substring(start), width: lineWidth}); - } - - // resolve horizontal alignment - var xOffset = 1, - yOffset = curTextAscent; - if (horizontalTextAlignment === PConstants.CENTER) { - xOffset = width/2; - } else if (horizontalTextAlignment === PConstants.RIGHT) { - xOffset = width; - } - - // resolve vertical alignment - var linesCount = drawCommands.length, - visibleLines = Math.min(linesCount, Math.floor(height/curTextLeading)); - if(verticalTextAlignment === PConstants.TOP) { - yOffset = curTextAscent + curTextDescent; - } else if(verticalTextAlignment === PConstants.CENTER) { - yOffset = (height/2) - curTextLeading * (visibleLines/2 - 1); - } else if(verticalTextAlignment === PConstants.BOTTOM) { - yOffset = curTextDescent + curTextLeading; - } - - var command, - drawCommand, - leading; - for (command = 0; command < linesCount; command++) { - leading = command * curTextLeading; - // stop if not enough space for one more line draw - if (yOffset + leading > height - curTextDescent) { - break; - } - drawCommand = drawCommands[command]; - drawing.text$line(drawCommand.text, x + xOffset, y + yOffset + leading, z, horizontalTextAlignment); - } - } - - /** - * text() Draws text to the screen. - * - * @param {String|char|int|float} data the alphanumeric symbols to be displayed - * @param {int|float} x x-coordinate of text - * @param {int|float} y y-coordinate of text - * @param {int|float} z optional z-coordinate of text - * @param {String} stringdata optional letters to be displayed - * @param {int|float} width optional width of text box - * @param {int|float} height optional height of text box - * - * @see #textAlign - * @see #textMode - * @see #loadFont - * @see #PFont - * @see #textFont - */ - p.text = function() { - if (textMode === PConstants.SHAPE) { - // TODO: requires beginRaw function - return; - } - if (arguments.length === 3) { // for text( str, x, y) - text$4(toP5String(arguments[0]), arguments[1], arguments[2], 0); - } else if (arguments.length === 4) { // for text( str, x, y, z) - text$4(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3]); - } else if (arguments.length === 5) { // for text( str, x, y , width, height) - text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], 0); - } else if (arguments.length === 6) { // for text( stringdata, x, y , width, height, z) - text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); - } - }; - - /** - * Sets the way text draws to the screen. In the default configuration (the MODEL mode), it's possible to rotate, - * scale, and place letters in two and three dimensional space. <br /><br /> Changing to SCREEN mode draws letters - * directly to the front of the window and greatly increases rendering quality and speed when used with the P2D and - * P3D renderers. textMode(SCREEN) with OPENGL and JAVA2D (the default) renderers will generally be slower, though - * pixel accurate with P2D and P3D. With textMode(SCREEN), the letters draw at the actual size of the font (in pixels) - * and therefore calls to <b>textSize()</b> will not affect the size of the letters. To create a font at the size you - * desire, use the "Create font..." option in the Tools menu, or use the createFont() function. When using textMode(SCREEN), - * any z-coordinate passed to a text() command will be ignored, because your computer screen is...flat! - * - * @param {int} MODE Either MODEL, SCREEN or SHAPE (not yet supported) - * - * @see loadFont - * @see PFont - * @see text - * @see textFont - * @see createFont - */ - p.textMode = function(mode){ - textMode = mode; - }; - - // Load Batik SVG Fonts and parse to pre-def objects for quick rendering - p.loadGlyphs = function(url) { - var x, y, cx, cy, nx, ny, d, a, lastCom, lenC, horiz_adv_x, getXY = '[0-9\\-]+', path; - - // Return arrays of SVG commands and coords - // get this to use p.matchAll() - will need to work around the lack of null return - var regex = function(needle, hay) { - var i = 0, - results = [], - latest, regexp = new RegExp(needle, "g"); - latest = results[i] = regexp.exec(hay); - while (latest) { - i++; - latest = results[i] = regexp.exec(hay); - } - return results; - }; - - var buildPath = function(d) { - var c = regex("[A-Za-z][0-9\\- ]+|Z", d); - var beforePathDraw = function() { - saveContext(); - return drawing.$ensureContext(); - }; - var afterPathDraw = function() { - executeContextFill(); - executeContextStroke(); - restoreContext(); - }; - - // Begin storing path object - path = "return {draw:function(){var curContext=beforePathDraw();curContext.beginPath();"; - - x = 0; - y = 0; - cx = 0; - cy = 0; - nx = 0; - ny = 0; - d = 0; - a = 0; - lastCom = ""; - lenC = c.length - 1; - - // Loop through SVG commands translating to canvas eqivs functions in path object - for (var j = 0; j < lenC; j++) { - var com = c[j][0], xy = regex(getXY, com); - - switch (com[0]) { - case "M": - //curContext.moveTo(x,-y); - x = parseFloat(xy[0][0]); - y = parseFloat(xy[1][0]); - path += "curContext.moveTo(" + x + "," + (-y) + ");"; - break; - - case "L": - //curContext.lineTo(x,-y); - x = parseFloat(xy[0][0]); - y = parseFloat(xy[1][0]); - path += "curContext.lineTo(" + x + "," + (-y) + ");"; - break; - - case "H": - //curContext.lineTo(x,-y) - x = parseFloat(xy[0][0]); - path += "curContext.lineTo(" + x + "," + (-y) + ");"; - break; - - case "V": - //curContext.lineTo(x,-y); - y = parseFloat(xy[0][0]); - path += "curContext.lineTo(" + x + "," + (-y) + ");"; - break; - - case "T": - //curContext.quadraticCurveTo(cx,-cy,nx,-ny); - nx = parseFloat(xy[0][0]); - ny = parseFloat(xy[1][0]); - - if (lastCom === "Q" || lastCom === "T") { - d = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(cy - y, 2)); - a = Math.PI + Math.atan2(cx - x, cy - y); - cx = x + (Math.sin(a) * (d)); - cy = y + (Math.cos(a) * (d)); - } else { - cx = x; - cy = y; - } - - path += "curContext.quadraticCurveTo(" + cx + "," + (-cy) + "," + nx + "," + (-ny) + ");"; - x = nx; - y = ny; - break; - - case "Q": - //curContext.quadraticCurveTo(cx,-cy,nx,-ny); - cx = parseFloat(xy[0][0]); - cy = parseFloat(xy[1][0]); - nx = parseFloat(xy[2][0]); - ny = parseFloat(xy[3][0]); - path += "curContext.quadraticCurveTo(" + cx + "," + (-cy) + "," + nx + "," + (-ny) + ");"; - x = nx; - y = ny; - break; - - case "Z": - //curContext.closePath(); - path += "curContext.closePath();"; - break; - } - lastCom = com[0]; - } - - path += "afterPathDraw();"; - path += "curContext.translate(" + horiz_adv_x + ",0);"; - path += "}}"; - - return ((new Function("beforePathDraw", "afterPathDraw", path))(beforePathDraw, afterPathDraw)); - }; - - // Parse SVG font-file into block of Canvas commands - var parseSVGFont = function(svg) { - // Store font attributes - var font = svg.getElementsByTagName("font"); - p.glyphTable[url].horiz_adv_x = font[0].getAttribute("horiz-adv-x"); - - var font_face = svg.getElementsByTagName("font-face")[0]; - p.glyphTable[url].units_per_em = parseFloat(font_face.getAttribute("units-per-em")); - p.glyphTable[url].ascent = parseFloat(font_face.getAttribute("ascent")); - p.glyphTable[url].descent = parseFloat(font_face.getAttribute("descent")); - - var glyph = svg.getElementsByTagName("glyph"), - len = glyph.length; - - // Loop through each glyph in the SVG - for (var i = 0; i < len; i++) { - // Store attributes for this glyph - var unicode = glyph[i].getAttribute("unicode"); - var name = glyph[i].getAttribute("glyph-name"); - horiz_adv_x = glyph[i].getAttribute("horiz-adv-x"); - if (horiz_adv_x === null) { - horiz_adv_x = p.glyphTable[url].horiz_adv_x; - } - d = glyph[i].getAttribute("d"); - // Split path commands in glpyh - if (d !== undef) { - path = buildPath(d); - // Store glyph data to table object - p.glyphTable[url][name] = { - name: name, - unicode: unicode, - horiz_adv_x: horiz_adv_x, - draw: path.draw - }; - } - } // finished adding glyphs to table - }; - - // Load and parse Batik SVG font as XML into a Processing Glyph object - var loadXML = function() { - var xmlDoc; - - try { - xmlDoc = document.implementation.createDocument("", "", null); - } - catch(e_fx_op) { - Processing.debug(e_fx_op.message); - return; - } - - try { - xmlDoc.async = false; - xmlDoc.load(url); - parseSVGFont(xmlDoc.getElementsByTagName("svg")[0]); - } - catch(e_sf_ch) { - // Google Chrome, Safari etc. - Processing.debug(e_sf_ch); - try { - var xmlhttp = new window.XMLHttpRequest(); - xmlhttp.open("GET", url, false); - xmlhttp.send(null); - parseSVGFont(xmlhttp.responseXML.documentElement); - } - catch(e) { - Processing.debug(e_sf_ch); - } - } - }; - - // Create a new object in glyphTable to store this font - p.glyphTable[url] = {}; - - // Begin loading the Batik SVG font... - loadXML(url); - - // Return the loaded font for attribute grabbing - return p.glyphTable[url]; - }; - - /** - * Gets the sketch parameter value. The parameter can be defined as the canvas attribute with - * the "data-processing-" prefix or provided in the pjs directive (e.g. param-test="52"). - * The function tries the canvas attributes, then the pjs directive content. - * - * @param {String} name The name of the param to read. - * - * @returns {String} The parameter value, or null if parameter is not defined. - */ - p.param = function(name) { - // trying attribute that was specified in CANVAS - var attributeName = "data-processing-" + name; - if (curElement.hasAttribute(attributeName)) { - return curElement.getAttribute(attributeName); - } - // trying child PARAM elements of the CANVAS - for (var i = 0, len = curElement.childNodes.length; i < len; ++i) { - var item = curElement.childNodes.item(i); - if (item.nodeType !== 1 || item.tagName.toLowerCase() !== "param") { - continue; - } - if (item.getAttribute("name") === name) { - return item.getAttribute("value"); - } - } - // fallback to default params - if (curSketch.params.hasOwnProperty(name)) { - return curSketch.params[name]; - } - return null; - }; - - //////////////////////////////////////////////////////////////////////////// - // 2D/3D methods wiring utils - //////////////////////////////////////////////////////////////////////////// - function wireDimensionalFunctions(mode) { - // Drawing2D/Drawing3D - if (mode === '3D') { - drawing = new Drawing3D(); - } else if (mode === '2D') { - drawing = new Drawing2D(); - } else { - drawing = new DrawingPre(); - } - - // Wire up functions (Use DrawingPre properties names) - for (var i in DrawingPre.prototype) { - if (DrawingPre.prototype.hasOwnProperty(i) && i.indexOf("$") < 0) { - p[i] = drawing[i]; - } - } - - // Run initialization - drawing.$init(); - } - - function createDrawingPreFunction(name) { - return function() { - wireDimensionalFunctions("2D"); - return drawing[name].apply(this, arguments); - }; - } - DrawingPre.prototype.translate = createDrawingPreFunction("translate"); - DrawingPre.prototype.transform = createDrawingPreFunction("transform"); - DrawingPre.prototype.scale = createDrawingPreFunction("scale"); - DrawingPre.prototype.pushMatrix = createDrawingPreFunction("pushMatrix"); - DrawingPre.prototype.popMatrix = createDrawingPreFunction("popMatrix"); - DrawingPre.prototype.resetMatrix = createDrawingPreFunction("resetMatrix"); - DrawingPre.prototype.applyMatrix = createDrawingPreFunction("applyMatrix"); - DrawingPre.prototype.rotate = createDrawingPreFunction("rotate"); - DrawingPre.prototype.rotateZ = createDrawingPreFunction("rotateZ"); - DrawingPre.prototype.shearX = createDrawingPreFunction("shearX"); - DrawingPre.prototype.shearY = createDrawingPreFunction("shearY"); - DrawingPre.prototype.redraw = createDrawingPreFunction("redraw"); - DrawingPre.prototype.toImageData = createDrawingPreFunction("toImageData"); - DrawingPre.prototype.ambientLight = createDrawingPreFunction("ambientLight"); - DrawingPre.prototype.directionalLight = createDrawingPreFunction("directionalLight"); - DrawingPre.prototype.lightFalloff = createDrawingPreFunction("lightFalloff"); - DrawingPre.prototype.lightSpecular = createDrawingPreFunction("lightSpecular"); - DrawingPre.prototype.pointLight = createDrawingPreFunction("pointLight"); - DrawingPre.prototype.noLights = createDrawingPreFunction("noLights"); - DrawingPre.prototype.spotLight = createDrawingPreFunction("spotLight"); - DrawingPre.prototype.beginCamera = createDrawingPreFunction("beginCamera"); - DrawingPre.prototype.endCamera = createDrawingPreFunction("endCamera"); - DrawingPre.prototype.frustum = createDrawingPreFunction("frustum"); - DrawingPre.prototype.box = createDrawingPreFunction("box"); - DrawingPre.prototype.sphere = createDrawingPreFunction("sphere"); - DrawingPre.prototype.ambient = createDrawingPreFunction("ambient"); - DrawingPre.prototype.emissive = createDrawingPreFunction("emissive"); - DrawingPre.prototype.shininess = createDrawingPreFunction("shininess"); - DrawingPre.prototype.specular = createDrawingPreFunction("specular"); - DrawingPre.prototype.fill = createDrawingPreFunction("fill"); - DrawingPre.prototype.stroke = createDrawingPreFunction("stroke"); - DrawingPre.prototype.strokeWeight = createDrawingPreFunction("strokeWeight"); - DrawingPre.prototype.smooth = createDrawingPreFunction("smooth"); - DrawingPre.prototype.noSmooth = createDrawingPreFunction("noSmooth"); - DrawingPre.prototype.point = createDrawingPreFunction("point"); - DrawingPre.prototype.vertex = createDrawingPreFunction("vertex"); - DrawingPre.prototype.endShape = createDrawingPreFunction("endShape"); - DrawingPre.prototype.bezierVertex = createDrawingPreFunction("bezierVertex"); - DrawingPre.prototype.curveVertex = createDrawingPreFunction("curveVertex"); - DrawingPre.prototype.curve = createDrawingPreFunction("curve"); - DrawingPre.prototype.line = createDrawingPreFunction("line"); - DrawingPre.prototype.bezier = createDrawingPreFunction("bezier"); - DrawingPre.prototype.rect = createDrawingPreFunction("rect"); - DrawingPre.prototype.ellipse = createDrawingPreFunction("ellipse"); - DrawingPre.prototype.background = createDrawingPreFunction("background"); - DrawingPre.prototype.image = createDrawingPreFunction("image"); - DrawingPre.prototype.textWidth = createDrawingPreFunction("textWidth"); - DrawingPre.prototype.text$line = createDrawingPreFunction("text$line"); - DrawingPre.prototype.$ensureContext = createDrawingPreFunction("$ensureContext"); - DrawingPre.prototype.$newPMatrix = createDrawingPreFunction("$newPMatrix"); - - DrawingPre.prototype.size = function(aWidth, aHeight, aMode) { - wireDimensionalFunctions(aMode === PConstants.WEBGL ? "3D" : "2D"); - p.size(aWidth, aHeight, aMode); - }; - - DrawingPre.prototype.$init = noop; - - Drawing2D.prototype.$init = function() { - // Setup default 2d canvas context. - // Moving this here removes the number of times we need to check the 3D variable - p.size(p.width, p.height); - - curContext.lineCap = 'round'; - - // Set default stroke and fill color - p.noSmooth(); - p.disableContextMenu(); - }; - Drawing3D.prototype.$init = function() { - // For ref/perf test compatibility until those are fixed - p.use3DContext = true; - p.disableContextMenu(); - }; - - DrawingShared.prototype.$ensureContext = function() { - return curContext; - }; - - ////////////////////////////////////////////////////////////////////////// - // Keyboard Events - ////////////////////////////////////////////////////////////////////////// - - // In order to catch key events in a canvas, it needs to be "specially focusable", - // by assigning it a tabindex. If no tabindex is specified on-page, set this to 0. - if (!curElement.getAttribute("tabindex")) { - curElement.setAttribute("tabindex", 0); - } - - function getKeyCode(e) { - var code = e.which || e.keyCode; - switch (code) { - case 13: // ENTER - return 10; - case 91: // META L (Saf/Mac) - case 93: // META R (Saf/Mac) - case 224: // META (FF/Mac) - return 157; - case 57392: // CONTROL (Op/Mac) - return 17; - case 46: // DELETE - return 127; - case 45: // INSERT - return 155; - } - return code; - } - - function getKeyChar(e) { - var c = e.which || e.keyCode; - var anyShiftPressed = e.shiftKey || e.ctrlKey || e.altKey || e.metaKey; - switch (c) { - case 13: - c = anyShiftPressed ? 13 : 10; // RETURN vs ENTER (Mac) - break; - case 8: - c = anyShiftPressed ? 127 : 8; // DELETE vs BACKSPACE (Mac) - break; - } - return new Char(c); - } - - function suppressKeyEvent(e) { - if (typeof e.preventDefault === "function") { - e.preventDefault(); - } else if (typeof e.stopPropagation === "function") { - e.stopPropagation(); - } - return false; - } - - function updateKeyPressed() { - var ch; - for (ch in pressedKeysMap) { - if (pressedKeysMap.hasOwnProperty(ch)) { - p.__keyPressed = true; - return; - } - } - p.__keyPressed = false; - } - - function resetKeyPressed() { - p.__keyPressed = false; - pressedKeysMap = []; - lastPressedKeyCode = null; - } - - function simulateKeyTyped(code, c) { - pressedKeysMap[code] = c; - lastPressedKeyCode = null; - p.key = c; - p.keyCode = code; - p.keyPressed(); - p.keyCode = 0; - p.keyTyped(); - updateKeyPressed(); - } - - function handleKeydown(e) { - var code = getKeyCode(e); - if (code === PConstants.DELETE) { - simulateKeyTyped(code, new Char(127)); - return; - } - if (codedKeys.indexOf(code) < 0) { - lastPressedKeyCode = code; - return; - } - var c = new Char(PConstants.CODED); - p.key = c; - p.keyCode = code; - pressedKeysMap[code] = c; - p.keyPressed(); - lastPressedKeyCode = null; - updateKeyPressed(); - return suppressKeyEvent(e); - } - - function handleKeypress(e) { - if (lastPressedKeyCode === null) { - return; // processed in handleKeydown - } - var code = lastPressedKeyCode, c = getKeyChar(e); - simulateKeyTyped(code, c); - return suppressKeyEvent(e); - } - - function handleKeyup(e) { - var code = getKeyCode(e), c = pressedKeysMap[code]; - if (c === undef) { - return; // no keyPressed event was generated. - } - p.key = c; - p.keyCode = code; - p.keyReleased(); - delete pressedKeysMap[code]; - updateKeyPressed(); - } - - // Send aCode Processing syntax to be converted to JavaScript - if (!pgraphicsMode) { - if (aCode instanceof Processing.Sketch) { - // Use sketch as is - curSketch = aCode; - } else if (typeof aCode === "function") { - // Wrap function with default sketch parameters - curSketch = new Processing.Sketch(aCode); - } else if (!aCode) { - // Empty sketch - curSketch = new Processing.Sketch(function (){}); - } else { - //#if PARSER - // Compile the code - curSketch = Processing.compile(aCode); - //#else - // throw "PJS compile is not supported"; - //#endif - } - - // Expose internal field for diagnostics and testing - p.externals.sketch = curSketch; - - wireDimensionalFunctions(); - - // the onfocus and onblur events are handled in two parts. - // 1) the p.focused property is handled per sketch - curElement.onfocus = function() { - p.focused = true; - }; - - curElement.onblur = function() { - p.focused = false; - if (!curSketch.options.globalKeyEvents) { - resetKeyPressed(); - } - }; - - // 2) looping status is handled per page, based on the pauseOnBlur @pjs directive - if (curSketch.options.pauseOnBlur) { - attachEventHandler(window, 'focus', function() { - if (doLoop) { - p.loop(); - } - }); - - attachEventHandler(window, 'blur', function() { - if (doLoop && loopStarted) { - p.noLoop(); - doLoop = true; // make sure to keep this true after the noLoop call - } - resetKeyPressed(); - }); - } - - // if keyboard events should be handled globally, the listeners should - // be bound to the document window, rather than to the current canvas - var keyTrigger = curSketch.options.globalKeyEvents ? window : curElement; - attachEventHandler(keyTrigger, "keydown", handleKeydown); - attachEventHandler(keyTrigger, "keypress", handleKeypress); - attachEventHandler(keyTrigger, "keyup", handleKeyup); - - // Step through the libraries that were attached at doc load... - for (var i in Processing.lib) { - if (Processing.lib.hasOwnProperty(i)) { - if(Processing.lib[i].hasOwnProperty("attach")) { - // use attach function if present - Processing.lib[i].attach(p); - } else if(Processing.lib[i] instanceof Function) { - // Init the libraries in the context of this p_instance (legacy) - Processing.lib[i].call(this); - } - } - } - - // sketch execute test interval, used to reschedule - // an execute when preloads have not yet finished. - var retryInterval = 100; - - var executeSketch = function(processing) { - // Don't start until all specified images and fonts in the cache are preloaded - if (!(curSketch.imageCache.pending || PFont.preloading.pending(retryInterval))) { - // the opera preload cache can only be cleared once we start - if (window.opera) { - var link, - element, - operaCache=curSketch.imageCache.operaCache; - for (link in operaCache) { - if(operaCache.hasOwnProperty(link)) { - element = operaCache[link]; - if (element !== null) { - document.body.removeChild(element); - } - delete(operaCache[link]); - } - } - } - - curSketch.attach(processing, defaultScope); - - // pass a reference to the p instance for this sketch. - curSketch.onLoad(processing); - - // Run void setup() - if (processing.setup) { - processing.setup(); - // if any transforms were performed in setup reset to identity matrix - // so draw loop is unpolluted - processing.resetMatrix(); - curSketch.onSetup(); - } - - // some pixels can be cached, flushing - resetContext(); - - if (processing.draw) { - if (!doLoop) { - processing.redraw(); - } else { - processing.loop(); - } - } - } else { - window.setTimeout(function() { executeSketch(processing); }, retryInterval); - } - }; - - // Only store an instance of non-createGraphics instances. - addInstance(this); - - // The parser adds custom methods to the processing context - // this renames p to processing so these methods will run - executeSketch(p); - } else { - // No executable sketch was specified - // or called via createGraphics - curSketch = new Processing.Sketch(); - - wireDimensionalFunctions(); - - // Hack to make PGraphics work again after splitting size() - p.size = function(w, h, render) { - if (render && render === PConstants.WEBGL) { - wireDimensionalFunctions('3D'); - } else { - wireDimensionalFunctions('2D'); - } - - p.size(w, h, render); - }; - } - }; - - // Place-holder for overridable debugging function - Processing.debug = (function() { - if ("console" in window) { - return function(msg) { - window.console.log('Processing.js: ' + msg); - }; - } - return noop; - }()); - - // bind prototype - Processing.prototype = defaultScope; - - /** - * instance store and lookup - */ - Processing.instances = processingInstances; - Processing.getInstanceById = function(name) { - return processingInstances[processingInstanceIds[name]]; - }; - - // Unsupported Processing File and I/O operations. - (function(Processing) { - var unsupportedP5 = ("open() createOutput() createInput() BufferedReader selectFolder() " + - "dataPath() createWriter() selectOutput() beginRecord() " + - "saveStream() endRecord() selectInput() saveBytes() createReader() " + - "beginRaw() endRaw() PrintWriter delay()").split(" "), - count = unsupportedP5.length, - prettyName, - p5Name; - - function createUnsupportedFunc(n) { - return function() { - throw "Processing.js does not support " + n + "."; - }; - } - - while (count--) { - prettyName = unsupportedP5[count]; - p5Name = prettyName.replace("()", ""); - Processing[p5Name] = createUnsupportedFunc(prettyName); - } - }(defaultScope)); - - // we're done. Return our object. - return Processing; -}; - -},{}],28:[function(require,module,exports){ -// Base source files -var source = { - virtEquals: require("./Helpers/virtEquals"), - virtHashCode: require("./Helpers/virtHashCode"), - ObjectIterator: require("./Helpers/ObjectIterator"), - PConstants: require("./Helpers/PConstants"), - ArrayList: require("./Objects/ArrayList"), - HashMap: require("./Objects/HashMap"), - PVector: require("./Objects/PVector"), - PFont: require("./Objects/PFont"), - Char: require("./Objects/Char"), - XMLAttribute: require("./Objects/XMLAttribute"), - XMLElement: require("./Objects/XMLElement"), - PMatrix2D: require("./Objects/PMatrix2D"), - PMatrix3D: require("./Objects/PMatrix3D"), - PShape: require("./Objects/PShape"), - colors: require("./Objects/webcolors"), - PShapeSVG: require("./Objects/PShapeSVG"), - CommonFunctions: require("./P5Functions/commonFunctions"), - defaultScope: require("./Helpers/defaultScope"), - Processing: require("./Processing"), - setupParser: require("./Parser/Parser"), - finalize: require("./Helpers/finalizeProcessing") -}; - -// Additional code that gets tacked onto "p" during -// instantiation of a Processing sketch. -source.extend = { - withMath: require("./P5Functions/Math.js"), - withProxyFunctions: require("./P5Functions/JavaProxyFunctions")(source.virtHashCode, source.virtEquals), - withTouch: require("./P5Functions/touchmouse"), - withCommonFunctions: source.CommonFunctions.withCommonFunctions -}; - -/** - * Processing.js building function - */ -module.exports = function buildProcessingJS(Browser, testHarness) { - var noop = function(){}, - virtEquals = source.virtEquals, - virtHashCode = source.virtHashCode, - PConstants = source.PConstants, - CommonFunctions = source.CommonFunctions, - ObjectIterator = source.ObjectIterator, - Char = source.Char, - XMLAttribute = source.XMLAttribute(), - - ArrayList = source.ArrayList({ - virtHashCode: virtHashCode, - virtEquals: virtEquals - }), - - HashMap = source.HashMap({ - virtHashCode: virtHashCode, - virtEquals: virtEquals - }), - - PVector = source.PVector({ - PConstants: PConstants - }), - - PFont = source.PFont({ - Browser: Browser, - noop: noop - }), - - XMLElement = source.XMLElement({ - Browser: Browser, - XMLAttribute: XMLAttribute - }), - - PMatrix2D = source.PMatrix2D({ - p:CommonFunctions - }), - - PMatrix3D = source.PMatrix3D({ - p:CommonFunctions - }), - - PShape = source.PShape({ - PConstants: PConstants, - PMatrix2D: PMatrix2D, - PMatrix3D: PMatrix3D - }), - - PShapeSVG = source.PShapeSVG({ - CommonFunctions: CommonFunctions, - PConstants: PConstants, - PShape: PShape, - XMLElement: XMLElement, - colors: source.colors - }), - - defaultScope = source.defaultScope({ - ArrayList: ArrayList, - HashMap: HashMap, - PVector: PVector, - PFont: PFont, - PShapeSVG: PShapeSVG, - ObjectIterator: ObjectIterator, - PConstants: PConstants, - Char: Char, - XMLElement: XMLElement, - XML: XMLElement - }), - - Processing = source.Processing({ - defaultScope: defaultScope, - Browser: Browser, - extend: source.extend, - noop: noop - }); - - // set up the Processing syntax parser - Processing = source.setupParser(Processing, { - Browser: Browser, - aFunctions: testHarness, - defaultScope: defaultScope - }); - - // finalise the Processing object - Processing = source.finalize(Processing, { - version: require('../package.json').version, - isDomPresent: false || Browser.isDomPresent, - window: Browser.window, - document: Browser.document, - noop: noop - }); - - // done. - return Processing; -}; - -},{"../package.json":2,"./Helpers/ObjectIterator":3,"./Helpers/PConstants":4,"./Helpers/defaultScope":6,"./Helpers/finalizeProcessing":7,"./Helpers/virtEquals":8,"./Helpers/virtHashCode":9,"./Objects/ArrayList":10,"./Objects/Char":11,"./Objects/HashMap":12,"./Objects/PFont":13,"./Objects/PMatrix2D":14,"./Objects/PMatrix3D":15,"./Objects/PShape":16,"./Objects/PShapeSVG":17,"./Objects/PVector":18,"./Objects/XMLAttribute":19,"./Objects/XMLElement":20,"./Objects/webcolors":21,"./P5Functions/JavaProxyFunctions":22,"./P5Functions/Math.js":23,"./P5Functions/commonFunctions":24,"./P5Functions/touchmouse":25,"./Parser/Parser":26,"./Processing":27}]},{},[1]); diff --git a/magnets.html b/magnets.html index 2fb7553..c8a99f7 100644 --- a/magnets.html +++ b/magnets.html @@ -1,7 +1,7 @@ <html> <head> <title>Magnets</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -11,7 +11,7 @@ <hr> <p>You can get the Android app for Magnets <a href="https://play.google.com/store/apps/details?id=org.neocities.autoart.magnets">here</a>.</p> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/magnets.js"></script> </body> </html> diff --git a/magnets_old_version.html b/magnets_old_version.html index ad12ce1..189d4ec 100644 --- a/magnets_old_version.html +++ b/magnets_old_version.html @@ -1,7 +1,7 @@ <html> <head> <title>Magnets</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -9,7 +9,7 @@ <div id="header_links_div"></div> <script src="js/header_links.js"></script> <hr> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/magnets_old_version.js"></script> </body> </html> diff --git a/mandelbrot.html b/mandelbrot.html index caab5a7..e5d7cf3 100644 --- a/mandelbrot.html +++ b/mandelbrot.html @@ -1,7 +1,7 @@ <html> <head> <title>The Mandelbrot Set</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> diff --git a/mandelbrot_explanation.html b/mandelbrot_explanation.html index 3a59639..961076c 100644 --- a/mandelbrot_explanation.html +++ b/mandelbrot_explanation.html @@ -1,7 +1,7 @@ <html> <head> <script src="js/latexit.js"></script> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <title>Mandelbrot Set Explanation</title> diff --git a/mathematical.html b/mathematical.html index 640d3ac..ca09c44 100644 --- a/mathematical.html +++ b/mathematical.html @@ -2,7 +2,7 @@ <head> <title>Mathematical Demonstrations</title> <meta charset="utf-8"> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> <link rel="shortcut icon" type="image/png" href="favicon.png"> </head> diff --git a/modularcircles.html b/modularcircles.html index 0267b03..6760130 100644 --- a/modularcircles.html +++ b/modularcircles.html @@ -1,9 +1,9 @@ <html>
<head>
<title>Modular circles</title>
-<link rel="stylesheet" href="css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
-<script src="js/p5.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script>
</head>
<body>
<h2>Modular circles</h2>
diff --git a/modularpascal.html b/modularpascal.html index 62c05bc..e744e67 100644 --- a/modularpascal.html +++ b/modularpascal.html @@ -1,10 +1,10 @@ <html>
<head>
<title>Modular pascal</title>
-<link rel="stylesheet" href="css/bootstrap.min.css">
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
-<script src="js/p5.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script>
</head>
<body>
diff --git a/shaperoller.html b/shaperoller.html index 3b8332c..476ef31 100644 --- a/shaperoller.html +++ b/shaperoller.html @@ -1,7 +1,7 @@ <html> <head> <title>Shape roller</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> @@ -14,7 +14,7 @@ Here's an animation of how it works (from Wikimedia):<br> <img width=100 height=100 src="https://upload.wikimedia.org/wikipedia/commons/d/d0/Cardiod_animation.gif" target="_blank"></p> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/shaperoller.js"></script> Speed: <input type="number" id="speed" value="0.5"><br> @@ -1,7 +1,7 @@ <html> <head> <title>Tree</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -9,7 +9,7 @@ <div id="header_links_div"></div> <script src="js/header_links.js"></script> <hr> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/tree.js"></script> </body> </html>
\ No newline at end of file diff --git a/treegenerator.html b/treegenerator.html index 8ef3a01..28e345b 100644 --- a/treegenerator.html +++ b/treegenerator.html @@ -1,7 +1,7 @@ <html> <head> <title>Tree Generator</title> -<link rel="stylesheet" href="css/bootstrap.min.css"> +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> @@ -19,7 +19,7 @@ Angle decay: Size: <input type="number" id="size" min="0" max="700" value="400"><br> <button onclick="saveTree();">Save image</button><br><br> -<script src="js/p5.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="js/treegenerator.js"></script> </body> </html>
\ No newline at end of file |