<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
<<importTiddlers>>
Finally got my Processing Wiki up and running.  Not... much here yet, and it's kind of scattered all over the place.  More I learn, the better it'll get.
I found two cool '~TiddlyProcessing' sites:
*http://tiddlyprocessing-simon.tiddlyspot.com/
*http://whatfettle.com/2008/05/TiddlyProcessing/
They come with the [[ProcessingjsPlugin]], which allows for Processing //in// the Tiddlywiki.  It's like a Processing \ Tiddlywiki mashup.  This is based on the work by [[Josh Resig|http://ejohn.org/]] on [[Processing.js|http://ejohn.org/blog/processingjs/]].  That plugin is now installed on //my// tiddlywiki, so I'll be able to actually post working examples.  Sweet.  

See an example below, pulled this directly from http://whatfettle.com/2008/05/TiddlyProcessing/, as a proof of concept test that the plugin works.

----

The angle of each segment is controlled with the mouseX and mouseY position. The transformations applied to the first segment are also applied to the second segment because they are inside the same pushMatrix() and popMatrix() group.
<<Processing 

float x = 50;
float y = 100;
float angle1 = 0.0;
float angle2 = 0.0;
float segLength = 50;

void setup() {
  size(200, 200);
  smooth(); 
  strokeWeight(20.0);
  stroke(0, 100);
}

void draw() {
  background(226);
  
  angle1 = (mouseX/float(width) - 0.5) * -PI;
  angle2 = (mouseY/float(height) - 0.5) * PI;
  
  pushMatrix();
  segment(x, y, angle1); 
  segment(segLength, 0, angle2);
  popMatrix();
}

void segment(float x, float y, float a) {
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
}

>>

Taken from [[basic/arm.html|http://ejohn.org/apps/processing.js/examples/basic/arm.html]]
Added the [[EXT REFERENCE]] (external reference) Category.  Will use it to collect other sites that have cool stuff.
Added the [[JAVA]] category.  Since Processing is based on Java, any Java language specific stuff I'll add here.
Added the [[OPENGL]] category.  I'm learning more about it... so might as well make a section.
On a bit of a hiatus.  Basically, I've been learning game authoring in [[Python|http://www.python.org/]] via [[PyGame|http://www.pygame.org]], and that has taken up most of my brainpower.  I'm sure I'll get back to Processing dev at some point.
Based on a 2d sketch, x0 & y0 are in the top left corner of the image, with +x (width) going 'right', and +y (height) going 'down'.

In a //3d// sketch (using OPENGL or ~P3D), depth is introduced.  X & Y remain the same, but depth, Z is added, also starting at the 'top left corner' with a value of 0.  By default, +z comes 'out' of the screen, while -z goes into the screen.

Honestly, this system seems //completely backwards// to me, coming from DCC software like Maya.  In that software, '0' would be the 'origin', with +x going 'left', +y going 'up', +z going 'forward' (thus the term 'z depth').  Perfectly visualized by holding up your right hand, with thumb going left, pointer going up (like making a backwards 'L'), and  middle finger going forward.

{{{width}}} and {{{height}}} are constants you can query in your sketch.  I often will make one called {{{depth}}} at the root of the sketch, and either update it there, or in the {{{setup()}}} function.
These are my online notes while I learn [[Processing|http://www.processing.org/]].  What //is// Processing?  From the site:
<<<
//Processing is an open source programming language and environment for people who want to program images, animation, and interactions. It is used by students, artists, designers, researchers, and hobbyists for learning, prototyping, and production. It is created to teach fundamentals of computer programming within a visual context and to serve as a software sketchbook and professional production tool. Processing is an alternative to proprietary software tools in the same domain.//
<<<
To add to that, Processing is a higher level wrapper around the programming language [[Java|http://java.sun.com/]], similar in the way [[PyGame|http://www.pygame.org]] wrappers [[Python|http://www.python.org/]].  The advantage is, while Processing gives you a lot of power, you can still directly access the underlying language as well.

''DISCLAIMER''
*I can't be blamed for anything misrepresented on this page! If it doesn't work, no finger-waving my direction.
*If you find something wrong, please tell me.  I //am// trying to correctly learn this stuff.
*Since I work on a Windows system, the majority of the command line stuff I call out to is Win-centric. If you're using Lunix\Unix\OSX etc, I can't comment on how well things will work.
Below are a list of //all// the subjects (tiddlers) in the wiki.  Note that there will be ones for site maintenance etc, that should be disregarded.
----
<<list all>>
ANDROID: Presuming you're holding the phone so the screen faces you in portrait mode:
*(0,0,0) is at the __bottom left__ corner of the screen.
*+X is to the right, -X is to the left.
*__+Y is up, -Y is down__.
*+Z is towards you, -Z is away from you.
And of COURSE this is different from Processing:
*(0,0,0) is at the __top left__ corner of the screen.
*+X is to the right, -X is to the left.
*__+Y is down, -Y is up__.
*+Z is towards you, -Z is away from you.
From the docs in [[android.hardware.SensorEvent|http://developer.android.com/reference/android/hardware/SensorEvent.html]]
{{{
 The coordinate space is defined relative to the screen of the phone 
 in its default orientation. The axes are not swapped when the device's
 screen orientation changes.

 The OpenGL ES coordinate system is used. The origin is in the
 lower-left corner  with respect to the screen, with the X axis horizontal
 and pointing  right, the Y axis vertical and pointing up and the Z axis
 pointing outside the front face of the screen. In this system, coordinates
 behind the screen have negative Z values.
 
 Note: This coordinate system is different from the one used in the
 Android 2D APIs where the origin is in the top-left corner. 

   x<0         x>0
                ^
                |
    +-----------+-->  y>0
    |           |
    |           |
    |           |
    |           |   / z<0
    |           |  /
    |           | /
    O-----------+/
    |[]  [ ]  []/
    +----------/+     y<0
              /
             /
           |/ z>0 (toward the sky)

    O: Origin (x=0,y=0,z=0)
}}}
This was sort of a scratchpad of code while I figured out how to access the sensors on the phone.  I have a blog post explaining it here: http://www.akeric.com/blog/?p=1313
----
''Irony:''
After I went through all this work to figure out the back end, I found this post here:
*http://codeanticode.wordpress.com/2010/10/10/3d-in-processing-for-android/
Which links to this lib here:
*http://processingandroid.org/Ketai/
*http://ketai.googlecode.com/svn/trunk/  (source)
Which does all the heavy lifting for you ;)

SDK:
*[[android.hardware.Sensor|http://developer.android.com/reference/android/hardware/Sensor.html]]  : __Class__ representing a sensor //type//.  Doesn't tell you much about what the sensor knows.
*[[android.hardware.SensorEvent|http://developer.android.com/reference/android/hardware/SensorEvent.html]]  :  This __class__ represents a sensor event and holds information such as the sensor type (eg: accelerometer, orientation, etc...), the time-stamp, accuracy and of course the sensor's data.
*[[android.hardware.SensorManager|http://developer.android.com/reference/android/hardware/SensorManager.html]]  :  __Class__ that lets you access the device's sensors.
**Specifically the {{{getOrientation}}} method.
*[[android.hardware.SensorEventListener|http://developer.android.com/reference/android/hardware/SensorEventListener.html]]  : __Interface__ used for receiving notifications from the {{{SensorManager}}} when sensor values have changed.
*--[[android.hardware.SensorListener|http://developer.android.com/reference/android/hardware/SensorListener.html]]--  :  Deprecated, use {{{SensorEventListener}}} instead.
Current:
*http://forum.processing.org/topic/reading-the-compass
*http://blog.androgames.net/135/android-orientation-tutorial/
*http://www.helloandroid.com/tutorials/using-android-phones-sensors
*http://www.netmite.com/android/mydroid/cupcake/development/samples/Compass/src/com/example/android/compass/CompassActivity.java
*http://efreedom.com/Question/1-2963705/Using-GetRotationMatrix-GetOrientation-Android-21
Outdated:
*http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.html
**Good example from the SDK, but uses deprecated {{{SensorListener}}} class.
*http://www.workingfromhere.com/blog/2009/03/30/orientation-sensor-tips-in-android/
*http://stackoverflow.com/questions/2974185/android-using-the-hardware-compass
*http://www.ibm.com/developerworks/opensource/library/os-android-sensor/index.html
*http://novoda.com/2009/05/02/motion-sensors-and-orientation-in-android/
*http://novoda.co.uk/wp-content/uploads/2009/05/sensoreventcheatsheet_v1.pdf
Reference:
*http://vmat.imgur.com/miscellaneous/ssz07


[[Processing Android Homepage|http://wiki.processing.org/w/Android]]
[[Forums|http://forum.processing.org/android-processing]]
''A bunch of below came from the homepage link above.  Adding here just so I can search easier.''
----
Processing Android source:
*http://code.google.com/p/processing/source/browse/trunk/processing#processing/android
The ~Android-Processing ~PApplet source:
*http://code.google.com/p/processing/source/browse/trunk/processing/android/core/src/processing/core/PApplet.java?r=7046
Some important stuff:
{{{
public class PApplet extends Activity implements PConstants, Runnable

    public PGraphics g;
    protected SurfaceView surfaceView;
}}}
----
Setup the screen to be the resolution of the phone. Use motionX and motionY variables:
{{{
float sw, sh;

void setup(){
  size(screenWidth, screenHeight, A2D);
  sw = screenWidth;
  sh = screenHeight;
}

void draw(){
  fill(255);
  rect(0,0, sw,sh);
  fill(0);
  ellipse(motionX, motionY, 128, 128);
}
}}}
----
Access the camera, sensors:
Check out the Ketai source for examples:
http://ketai.googlecode.com/svn/trunk/
----
''Text'':
Using [[createFont()|http://www.processing.org/reference/createFont_.html]] (instead of loadFont()) can help improve text quality, particularly with 2D rendering. Use [[PFont|http://www.processing.org/reference/PFont.html]].[[list()|http://www.processing.org/reference/PFont_list_.html]] to get a list of available fonts on the system, and select one of those, or include a .ttf or .otf file in the data directory of your sketch. 
----
Tracking Motion with new variables:
*{{{motionX}}} = {{{mouseX}}}
*{{{motionY}}} = {{{mouseY}}}
*{{{pmotionX}}} = {{{pmouseX}}}
*{{{pmotionY}}} = {{{pmotionY}}}
----
{{{size()}}}
Don't use it.  If not specified, then the sketch is opened and uses the entire display.
----
Renders:
*{{{A2D}}} = {{{P2D}}}, {{{JAVA2D}}}
*{{{A3D}}} = {{{P3D}}}, {{{OPENGL}}}
----
Orientation:
If you want to lock orientation to one direction, you can use one of the following commands inside {{{setup()}}}:
{{{
orientation(PORTRAIT);  // the hamburger way
orientation(LANDSCAPE);  // the hot dog way
}}}
----
''No Longer Available'':
*variables: (see [[Processing system variables]] for reference)
**[[mouseButton|http://processing.org/reference/mouseButton.html]] variable
**{{{keyEvent}}} variable
**{{{mouseEvent}}} variable
*constants: (see [[List of Processing Constants]])
**{{{ALT}}}
**{{{CONTROL}}}
**{{{SHIFT}}}
----
''Changes'':
*Using {{{createGraphics()}}} with {{{A3D}}}/{{{P3D}}}/{{{OPENGL}}} is only available on devices that support the FBO extension properly, which is mostly Android 2.2 and later devices.
*{{{screen.width}}}} and {{{screen.height}}} are replaced by {{{screenWidth}}} and {{{screenHeight}}}
*{{{PImage.image}}} is {{{PImage.bitmap}}}, to reflect that a different object type is there, in spite of its identical purpose
*{{{PFont.font}}} is {{{PFont.typeface}}}, similar as above. 
----
Override [[keyPressed|file:///C:/Program%20Files/processing-0191/reference/keyPressed.html]] to override the 'back' button on the phone:
{{{
  void keyPressed() {
    // doing other things here, and then:
    if (key == CODED && keyCode == KeyEvent.KEYCODE_BACK) {
      keyCode = 0;  // don't quit by default
    }
  }
}}}
----
Working with event objects:
{{{
  public boolean surfaceTouchEvent(MotionEvent event) {
    // your code here
 
    // if you want the variables for motionX/motionY, mouseX/mouseY etc.
    // to work properly, you'll need to call super.surfaceTouchEvent().
    return super.surfaceTouchEvent(event);
  }
}}}
You can use a handler like this to incorporate other libraries that support multitouch or fancier touch event handling than just the basics we currently provide. 

The key methods work in a similar fashion: 
{{{
  public boolean surfaceKeyDown(int code, KeyEvent event) {
    return super.surfaceKeyDown(code, event);
  }
 
  public boolean surfaceKeyUp(int code, KeyEvent event) {
    return super.surfaceKeyDown(code, event);
  }
}}}
----
Access the BACK and MENU keys:
{{{
  void keyPressed() {
    if (key == CODED) {
      if (keyCode == BACK) {
        // do something here for the back button behavior
        // you'll need to set keyCode to 0 if you want to prevent quitting (see above)
      } else if (keyCode == MENU) {
        // user hit the menu key, take action
      }
    }
  }
}}}
----
Docs for Android Key Events:
http://developer.android.com/reference/android/view/KeyEvent.html
To replace one of them:
{{{
  void keyPressed() {
    // doing other things here, and then:
    if (key == CODED && keyCode == KeyEvent.KEYCODE_HOME) {
      // override the home key here
    }
  }
}}}
----
Get screen density and pixel information via [[DisplayMetrics|http://developer.android.com/reference/android/util/DisplayMetrics.html]]:
{{{
  // Place this at the top of your sketch
  import android.util.DisplayMetrics; 
 
  // Place this inside your setup() method
  DisplayMetrics dm = new DisplayMetrics();
  getWindowManager().getDefaultDisplay().getMetrics(dm);
  float density = dm.density; 
  int densityDpi = dm.densityDpi;
  println("density is " + density); 
  println("densityDpi is " + densityDpi);
}}}
print something like:
{{{
density is 1.5
densityDpi is 240
}}}
Yes:
*[[Processing & Android: Mobile App Development Made (Very) Easy|http://blog.blprnt.com/blog/blprnt/processing-android-mobile-app-development-made-very-easy]]
*[[Getting Started with Processing for Android|http://createdigitalmotion.com/2010/09/getting-started-with-processing-for-android/]]
*[[3D in Processing for Android|http://codeanticode.wordpress.com/2010/10/10/3d-in-processing-for-android/]]
I don't have an "Arduino Wiki" (I did, but it... died), so a few notes here to keep me sane while working with it.
!!![[Pin Commands|http://arduino.cc/en/Reference/HomePage]]:
Based on a 5v board (like the Uno)
__Analog pins:__
*[[analogWrite(pin, value)|http://arduino.cc/en/Reference/AnalogWrite]] : {{{value}}} is a number between 0 -> 255.  Writes an analog value ([[PWM|http://arduino.cc/en/Tutorial/PWM]] wave) to a pin.  The PMW pulse is a 0v & 5v square wave.
*[[analogRead(pin)|http://arduino.cc/en/Reference/AnalogRead]] : Returns a number between 0 -> 1023, based on the voltage of the pin ranging from 0v -> 5v.  If the pin had 2.5v, it would return 512.  It takes about 100 microseconds (.1 milliseconds) to read an analog input.
__Digital pins:__
*[[pinMode(pin, mode)|http://arduino.cc/en/Reference/PinMode]] :  For use with //digital// pins, {{{mode}}} can either be {{{INPUT}}} or {{{OUTPUT}}}
*[[digitalRead(pin)|http://arduino.cc/en/Reference/DigitalRead]] :  Returns {{{HIGH}}}  if > 3v, or {{{LOW}}} if < 2v.
*[[digitalWrite(pin, value)|http://arduino.cc/en/Reference/DigitalWrite]] : 
**If pin has been configured to {{{OUTPUT}}} (via {{{pinMode}}}):  {{{value}}} is either {{{HIGH}}} (5v) or {{{LOW}}} (0v).
**If pin has been configured to {{{INPUT}}} (via {{{pinMode}}}):  Writing a {{{HIGH}}} value will enable an internal 20K pullup resistor. Writing {{{LOW}}} will disable the pullup. 
!!![[Constants|http://arduino.cc/en/Reference/Constants]]
*{{{HIGH}}} : 
**If {{{pinMode()}}} is {{{INPUT}}}, using {{{digitalRead()}}} the microcontroller will report {{{HIGH}}} if a voltage of 3 volts or more is present at the pin.
**A pin may also be configured as an {{{INPUT}}} with {{{pinMode}}}, and subsequently made {{{HIGH}}} with {{{digitalWrite}}}, this will set the internal 20K pullup resistors, which will steer the input pin to a {{{HIGH}}} reading unless it is pulled {{{LOW}}} by external circuitry.
**If {{{pinMode()}}} is {{{OUTPUT}}} and set to {{{HIGH}}} with {{{digitalWrite}}}, the pin is at 5 volts. In this state it can //source current//, e.g. light an LED that is connected through a series resistor to ground, or to another pin configured as an output, and set to LOW.
*{{{LOW}}} :
**If {{{pinMode()}}} is {{{INPUT}}}, and read with {{{digitalRead}}}, the microcontroller will report {{{LOW}}} if a voltage of 2 volts or less is present at the pin.
**If {{{pinMode()}}} is {{{OUTPUT}}} and set to {{{LOW}}} with {{{digitalWrite}}}, the pin is at 0 volts. In this state it can sink current, e.g. light an LED that is connected through a series resistor to, +5 volts, or to another pin configured as an output, and set to {{{HIGH}}}.
*{{{INPUT}}} :
**Arduino (Atmega) pins configured as {{{INPUT}}} with {{{pinMode()}}} are said to be in a high-impedance state. One way of explaining this is that pins configured as {{{INPUT}}} make extremely small demands on the circuit that they are sampling, say equivalent to a series resistor of 100 Megohms in front of the pin. This makes them useful for reading a sensor, but not powering an LED.
*{{{OUTPUT}}} :
**Pins configured as {{{OUTPUT}}} with {{{pinMode()}}} are said to be in a low-impedance state. This means that they can provide a substantial amount of current to other circuits. Atmega pins can source (provide positive current) or sink (provide negative current) up to 40 mA (milliamps) of current to other devices/circuits. This makes them useful for powering LED's but useless for reading sensors. Pins configured as outputs can also be damaged or destroyed if short circuited to either ground or 5 volt power rails. The amount of current provided by an Atmega pin is also not enough to power most relays or motors, and some interface circuitry will be required.
!!![[Hardware|http://arduino.cc/en/Main/ArduinoBoardUno]]
Using the Arduino Uno
*Operating Voltage : 5v
*Input Voltage (recommended)  7-12V
*Input Voltage (limits)  6-20V
**If supplied with less than 7V, the 5V pin may supply less than five volts and the board may be unstable. If using more than 12V, the voltage regulator may overheat and damage the board. The recommended range is 7 to 12 volts.
*DC Current per I/O Pin : 40 mA
*Giving power //to// the Arduino:
**USB : Delivers 5v standard. 500-900ma current max.
**Barrel jack : Can be used to connect any other power source based on the above specs.  2.1mm center-positive plug.
**{{{Vin}}} :  You can supply voltage to the Arduino via this pin (plus running the other lead to one of the {{{GND}}} pins).
*Getting Power //from// the Arduino (to power your project):
**{{{3v3}}} : Access a 3.3 volt supply generated by the on-board regulator. Maximum current draw is 50 mA.
**{{{5v}}} : Access the regulated power supply used to power the microcontroller and other components on the board. This can come either from VIN via an on-board regulator, or be supplied by USB or another regulated 5V supply.
**{{{Vin}}} : Access a direct path to the external power source, if an external power source is powering the Arduino (and not powering it through this pin, obviously).
*Other power-related pins.
**{{{Aref}}} : Ties to the function [[analogReference(type)|http://arduino.cc/en/Reference/PinMode]], where {{{type}}} has a variety of options based on the board.  How I see this being useful:  If you have (for example) 12v of external power coming into the board, you can also run a lead into the Aref pin from that external power:  Now, 0->12v will be used for {{{analogRead()}}}, rather than the internal 0-5v range.  You must set {{{type}}} to {{{EXTERNAL}}} before calling to the command though.
**{{{RESET}}} : Set this to {{{LOW}}} (0v) to reset the board.
**{{{GND}}} : Ground.
!!!Pins:
Pin spreadsheet:
| ''Pin'' | ''Features'' |
| | |
| D0 | RX : read TTL serial data |
| D1 | TX : transmit TTL serial data |
| D2 | External interrupt, see [[attachInterrupt()|http://arduino.cc/en/Reference/AttachInterrupt]] |
| D3 | PMW -- External interrupt, see [[attachInterrupt()|http://arduino.cc/en/Reference/AttachInterrupt]] |
| D4 |  |
| D5 | PMW |
| D6 | PMW |
| D7 |  |
| D8 |  |
| D9 | PMW |
| D10 | PMW -- [[SPI Communication|http://arduino.cc/en/Reference/SPI]] for {{{SS}}} |
| D11 | PMW -- [[SPI Communication|http://arduino.cc/en/Reference/SPI]] for {{{MOSI}}} |
| D12 | [[SPI Communication|http://arduino.cc/en/Reference/SPI]] for {{{MISO}}} |
| D13 | Built in LED -- [[SPI Communication|http://arduino.cc/en/Reference/SPI]] for {{{SCK}}} |
| | |
| A0 / D14 |  |
| A1 / D15 |  |
| A2 / D16 |  |
| A3 / D17 |  |
| A4 / D18 | TWI communication '{{{SDA}}}', see the [[Wire ibrary|http://arduino.cc/en/Reference/Wire]]  |
| A5 / D19 | TWI communication '{{{SCL}}}', see the [[Wire ibrary|http://arduino.cc/en/Reference/Wire]]  |
Pin Groupings:
*TTL Serial Communication: 
**D0 : read
**D1 : write
*External interrupt:
**D2, D3
*PWM:
**D3, D5, D6, D9, D10, D11
*SPI Communication:
**D10 : {{{SS}}}
**D11 : {{{MOSI}}}
**D12 : {{{MISO}}}
**D13 : {{{SCK}}}
*Onboard LED:
**D13
*TWI Communication
**A4 / D18 : {{{DSA}}}
**A5 / D19 : {{{SCL}}}
*Nothing Special:
**D4, D7, D8, A0 / D14, A1 / D15, A2 / D16, A3 / D17
*ICSP
**There are two spots on the board that have clusters of 6 pins (2x3).
**These can be used to burn the [[bootloader|http://www.arduino.cc/en/Hacking/Bootloader]] onto the Arduino.




*{{{.charAt}}}
*{{{.equals}}}
*{{{.indexOf}}}
*{{{.length}}}
*{{{.substring}}}
*{{{.toLowerCase}}}
*{{{.toUpperCase}}}
Also see:
*[[List of array functions]]
*[[List of string functions]]
The most common way of setting up your sketch is to have a {{{setup()}}} function, and then a {{{draw()}}} function.  {{{setup()}}} executes once, when the sketch starts.  {{{draw()}}} executes every frame.
{{{
// any global variables would be defined here  //

void setup(){
  // Some common settings:
  size(200, 200);
  background(51);
  noStroke();
  smooth();
}

void draw(){
  // do your stuff, will execute every frame.
}
}}}
<<gradient horiz #ffffff  #ddddff #8888ff >>
The Processing Wiki blog
*[[2009 09 09]] - On a break...
*[[2009 04 14]] - Added the [[JAVA]] & [[OPENGL]] Category.
*[[2009 01 12]] - Added [[EXT REFERENCE]] Category.
*[[2008 06 11]] - ~TiddlyProcessing!
*[[2008 06 10]] - Processing tiddlywiki is born!
Makes a bunch of balls bounce around the screen, and connects them by vibrating bezier curves.

Written while I was waiting on my computer to build the game I'm working on.  Nothing terribly special about this, other than to teach myself how to use classes, expand arrays, and create simple motion.  Good starting point for more complex stuff.
[img[http://bp3.blogger.com/_vouolqPGlUc/SHfoE0ffhvI/AAAAAAAABlg/Tg6rNad7yMc/s320/fuzzBall01.jpg]]
{{{
int ballCount = 10;
int c = 0;

Fball[] baller = {};

void setup(){
  size(256, 256);
  smooth(); 
  // baller[0] = new Fball();
  frameRate(30);
  background(0);
}

void draw(){
  fill(0,64);
  quad(0,0, width, 0, width, height, 0, height);

  while(c < ballCount){
    baller = (Fball[])expand(baller, c+1);  
    println(baller.length);
    baller[c] =  new Fball();
    c++;
  }

  for(int i=0; i<baller.length; i++){ 
    baller[i].moveBall();
    baller[i].drawLine();
    baller[i].drawBall();
  }
}

class Fball{
  // Properties

  private float drag = 1;
  private float xPos;
  private float yPos;
  private float diameter;
  private float xVelocity;
  private float yVelocity;
  private float xDir = 1;
  private float yDir = 1;

  // Constructors

  Fball(){
    diameter = random(8,64);
    xPos = random(0+diameter/2, width-diameter/2);
    yPos = random(0+diameter/2, height-diameter/2);
    xVelocity = random (1, 4);
    yVelocity = random (1, 4);    
  }

  // Methods

  float[] getPos(){
    float[] r = {
      xPos, yPos                };
    return r;
  }

  void drawBall(){
    stroke(0);
    strokeWeight(0);
    fill(255,128);
    ellipse(xPos, yPos, diameter, diameter);
  }

  void moveBall(){
    xPos = xPos + ( xVelocity * xDir );
    yPos = yPos + ( yVelocity * yDir );
    xVelocity *= drag;
    yVelocity *= drag; 
    // Test to see if the shape exceeds the boundaries of the screen
    // If it does, reverse its direction by multiplying by -1
    if (xPos > width-(diameter/2) || xPos < diameter/2) {
      xDir *= -1;
    }
    if (yPos > height-(diameter/2) || yPos < diameter/2) {
      yDir *= -1;
    }    
  }

  void drawLine(){
    for(int i =0; i<baller.length; i++){
      float[] targetPos = baller[i].getPos();
      strokeWeight(1);
      stroke(255);
      noFill();
      bezier(
        xPos, yPos, 
        random(xPos-30, xPos+30), random(yPos-30, yPos+30),  
        random(targetPos[0]-30, targetPos[0]+30), random(targetPos[1]-30, targetPos[1]+30),
        targetPos[0], targetPos[1]);
    } 
  }
}
}}}
{{{
sqrt(abs(
  pow(x2 - x1, 2) +
  pow(y2 - y1, 2)));
}}}
OR, you can just use {{{dist()}}} (don't know how I missed that one... )
http://www.processing.org/reference/dist_.html
When working in 3D Processing has the [[camera|http://processing.org/reference/camera_.html]] and [[perspective|http://processing.org/reference/perspective_.html]] commands.  But, it doesn't allow for querying of camera values (as far as I can tell).
----
I've also found these external libraries:
[[kaleidoscope|http://users.design.ucla.edu/~ptierney/kaleidoscope/index.html]]
''Update'':
As of Processing 0148 (maybe earlier) you can use the Processing {{{HashMap}}} object.  See the docs online [[here|http://www.processing.org/reference/HashMap.html]]
----
Old docs below:

Also known as associative arrays: Well, sort of, via Java.  I pulled this from [[this thread|http://processing.org/discourse/yabb_beta/YaBB.cgi?board=LibraryProblems;action=display;num=1189615216;start=1#1]]
{{{
import java.util.HashMap;
HashMap hm = new HashMap();

hm.put("mykey","myvalue");
println(hm.get("mykey"));

hm.put(new Integer(7),new Integer(10));  
println(hm.get(new Integer(7))); 
}}}
According to the Java docs, the ~HashMap only takes in [[objects|class]].  From the above example, {{{strings}}} pass in fine, since {{{strings}}} in processing //are// objects.  But to use something else, like an {{{int}}}, you need to make a {{{new Integer}}} object, and pass that in instead.
The problem I've found is that while per the example, you can print the return just fine, actually putting that retun into some kind of variable simply doesn't work.  There seems to be some incompatibility.
*//Java// Docs on ~HashMap [[here|http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html]]
''Update'':  Fixed code pasted below.  There was a slight formatting error when I transfered it to the wiki.
----
I authored this class to help with my "colorSearch" Sketch.  You can see images from that sketch [[here|http://www.flickr.com/photos/warpcat/2597180052/]].
*During creation, you pass into this class an array of color data/pixels (say, via a {{{PImage.pixels}}} color array), and the width of the image the pixels were captured from. 
*Then, via its method {{{get_colorPos}}}, you can pass in a color value.  The method will return back the XY position of //every color in the image that matches//, into a 2d int array.  Parse the array, and do stuff with the results.  
*The 2d array's first array is the length of all the x match values.  The second array holds only a single value, the matching y position.  So for example, if you found four matching positions, the array size would be {{{[4][2]}}} (four indices 'long', and two indices 'wide').
*Example usage at the bottom explaining how to parse it.
{{{
/*
Eric Pavey - 2008-06-20
*/

class ImageData{

  //------------------
  // PROPERTIES:

  // arrays to hold the xy pos for each pixel relative 
  // to the colors in pixies:
  color[] pixies;
  int[] xList;
  int[] yList;

  //------------------
  // CONSTRUCTOR:

  // Pass in a list of pixel values, 
  // and the width of the image they were captured from:
  ImageData(color[] pix, int xRes){
    pixies = pix;
    xList = new int[pixies.length];
    yList = new int[pixies.length];

    // fill our xList and yLists:
    int ix=0;
    int iy=0;
    for(int i=0; i<pixies.length; i++){
      xList[i] = ix;
      yList[i] = iy;

      ix++;
      if(ix > xRes-1){
        ix=0;
        iy++;
      }
    }
  }

  //------------------
  // METHODS:

  // Based on a passed in color, return back the x & y pos 
  // of every matching color in the image:
  // color col  :  the color we're trying to match

  int[][] get_colorPos(color col){
    int[][] returnPos;
    int[] foundX = new int[0];
    int[] foundY = new int[0];
    int counter=0;

    for(int i=0; i<pixies.length; i++){
      if(pixies[i] == col){
        foundX = expand(foundX, counter+1);
        foundY = expand(foundY, counter+1);
        foundX[counter] = xList[i];
        foundY[counter] = yList[i];
        counter++;
      }
    }

    // create our 2d array that will be returned
    returnPos = new int[foundX.length][2];

    // and fill the array with our found values:
    for(int i=0; i<foundX.length; i++){
      for(int j=0; j<2; j++){
        if(j==0){
          returnPos[i][j] = foundX[i];
        }
        else{
          returnPos[i][j] = foundY[i];          
        }
      }  
    }
    return returnPos;
  }
}
}}}
Example Usage:
{{{
// load our image:
PImage img = loadImage("myImage.jpg");
// Define some color to search for:
color searchCol = img.pixels[0];
// Create our ImageData object:
ImageData id = new ImageData(img.pixels, img.width);
// Find matching colors:
int[][] matchCols = id.get_colorPos(searchCol);

// do something with the colors:
for(int i=0;i<matchCols.length; i++){
  println("Matching color at x: " + matchCols[i][0] + " y: " + matchCols[i][1]);
} 
}}}
I often see classes in Processing that implement '{{{Comparable}}}':
{{{
class MyObj implements Comparable {
  // stuff...
}
}}}
Official notes on the Java object:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Comparable.html
Notes from the doc:
<<<
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). Objects that implement this interface can be used as keys in a sorted map or elements in a sorted set, without the need to specify a comparator.
<<<
Notes from Processing hacks:
http://processing.org/hacks/hacks:comparable
/***
|''Name:''|CryptoFunctionsPlugin|
|''Description:''|Support for cryptographic functions|
***/
//{{{
if(!version.extensions.CryptoFunctionsPlugin) {
version.extensions.CryptoFunctionsPlugin = {installed:true};

//--
//-- Crypto functions and associated conversion routines
//--

// Crypto "namespace"
function Crypto() {}

// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
	var be = Array();
	var len = Math.floor(str.length/4);
	var i, j;
	for(i=0, j=0; i<len; i++, j+=4) {
		be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
	}
	while (j<str.length) {
		be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
		j++;
	}
	return be;
};

// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
	var str = "";
	for(var i=0;i<be.length*32;i+=8)
		str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
	return str;
};

// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
	var hex = "0123456789ABCDEF";
	var str = "";
	for(var i=0;i<be.length*4;i++)
		str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
	return str;
};

// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
	return Crypto.be32sToHex(Crypto.sha1Str(str));
};

// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
	return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};

// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
	// Add 32-bit integers, wrapping at 32 bits
	add32 = function(a,b)
	{
		var lsw = (a&0xFFFF)+(b&0xFFFF);
		var msw = (a>>16)+(b>>16)+(lsw>>16);
		return (msw<<16)|(lsw&0xFFFF);
	};
	// Add five 32-bit integers, wrapping at 32 bits
	add32x5 = function(a,b,c,d,e)
	{
		var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
		var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
		return (msw<<16)|(lsw&0xFFFF);
	};
	// Bitwise rotate left a 32-bit integer by 1 bit
	rol32 = function(n)
	{
		return (n>>>31)|(n<<1);
	};

	var len = blen*8;
	// Append padding so length in bits is 448 mod 512
	x[len>>5] |= 0x80 << (24-len%32);
	// Append length
	x[((len+64>>9)<<4)+15] = len;
	var w = Array(80);

	var k1 = 0x5A827999;
	var k2 = 0x6ED9EBA1;
	var k3 = 0x8F1BBCDC;
	var k4 = 0xCA62C1D6;

	var h0 = 0x67452301;
	var h1 = 0xEFCDAB89;
	var h2 = 0x98BADCFE;
	var h3 = 0x10325476;
	var h4 = 0xC3D2E1F0;

	for(var i=0;i<x.length;i+=16) {
		var j,t;
		var a = h0;
		var b = h1;
		var c = h2;
		var d = h3;
		var e = h4;
		for(j = 0;j<16;j++) {
			w[j] = x[i+j];
			t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=16;j<20;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=20;j<40;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=40;j<60;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=60;j<80;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}

		h0 = add32(h0,a);
		h1 = add32(h1,b);
		h2 = add32(h2,c);
		h3 = add32(h3,d);
		h4 = add32(h4,e);
	}
	return Array(h0,h1,h2,h3,h4);
};


}
//}}}
Reference:
http://www.2dcurves.com/spiral/spiralaa.html
{{{
r = theta
}}}
Give it a second to get going....
<<Processing
float theta = 0;

void setup(){
  size(256,256); 
  smooth();
}

void draw(){
 translate(width/2, height/2);
 
 float x = sin(theta);
 float y = cos(theta);
 point(x*theta,y*theta);
 theta = theta + .01;
}
>>
Reference:
http://www.2dcurves.com/spiral/spirallo.html
The code I used to author this isn't exactly like listed, but gives a similar result.  Need to revisit to make correct
{{{
r = pow(e, a*theta)
}}}
Give it a second to get going....
<<Processing
float theta = 0;
float mult = 1;
void setup(){
  size(256,256); 
  smooth();
}

void draw(){
  translate(width/2, height/2);
  float x = sin(theta);
  float y = cos(theta);
  point(x*theta*mult,y*theta*mult);
  theta = theta + .01;
  mult = mult + .0025;
}
>>
{{{
y = x*x
}}}
<<Processing
int x = 0;
int y = 0;
void setup(){
  size(256,256);
}
void draw(){
  if(x<=width||y<=height){
    y = int(pow(x,2)*.004);
    point(x,y);
    x++;
  } 
}
>>
[[Welcome]]
/***
|''Name:''|DeprecatedFunctionsPlugin|
|''Description:''|Support for deprecated functions removed from core|
***/
//{{{
if(!version.extensions.DeprecatedFunctionsPlugin) {
version.extensions.DeprecatedFunctionsPlugin = {installed:true};

//--
//-- Deprecated code
//--

// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
	w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};

// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
	var lookaheadRegExp = new RegExp(this.lookahead,"mg");
	lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = lookaheadRegExp.exec(w.source);
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var text = lookaheadMatch[1];
		if(config.browser.isIE)
			text = text.replace(/\n/g,"\r");
		createTiddlyElement(w.output,"pre",null,null,text);
		w.nextMatch = lookaheadRegExp.lastIndex;
	}
};

// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
	createTiddlyElement(place,"br");
};

// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
	var i = this.indexOf(item);
	return i == -1 ? null : i;
};

// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
	return store.getLoader().internalizeTiddler(store,this,title,divRef);
};

// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
	return store.getSaver().externalizeTiddler(store,this);
};

// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
	return store.allTiddlersAsHtml();
}

// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
	refreshPageTemplate(title);
}

// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
	story.displayTiddlers(srcElement,titles,template,animate);
}

// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
	story.displayTiddler(srcElement,title,template,animate);
}

// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;

// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");

}
//}}}
Notes and whatnot...

http://screamyguy.net/DepthOfField/index.htm
http://screamyguy.net/dandelion/index.htm
Stuff below copied from over on the [[Android - Processing|http://wiki.processing.org/w/Android#Mouse.2C_Motion.2C_Keys.2C_and_Input]] wiki.  
Docs for [[android.view.KeyEvent|http://developer.android.com/reference/android/view/KeyEvent.html]]
{{{
  void keyPressed() {
    // doing other things here, and then:
    if (key == CODED && keyCode == KeyEvent.KEYCODE_HOME) {
      // override the home key here
    }
  }
}}}
{{{
  public boolean surfaceKeyDown(int code, KeyEvent event) {
    return super.surfaceKeyDown(code, event);
  }
 
  public boolean surfaceKeyUp(int code, KeyEvent event) {
    return super.surfaceKeyDown(code, event);
  }
}}}
{{{
  void keyPressed() {
    if (key == CODED) {
      if (keyCode == DPAD) {
        // user pressed the center button on the d-pad
      } else if (keyCode == UP) {
        // user triggered 'up' on the d-pad
      } else if (keyCode == DOWN) {
        // user triggered 'down' on the d-pad
      } else if (keyCode == LEFT) {
        // user triggered 'left' on the d-pad
      } else if (keyCode == RIGHT) {
        // user triggered 'right' on the d-pad
      }
    }
  }
}}}
{{{
  void keyPressed() {
    if (key == CODED) {
      if (keyCode == BACK) {
        // do something here for the back button behavior
        // you'll need to set keyCode to 0 if you want to prevent quitting (see above)
      } else if (keyCode == MENU) {
        // user hit the menu key, take action
      }
    }
  }
}}}
----
You can use this code to specifically override the Home button, or anytime the Sketch\Activity needs to exit:
{{{
public void onUserLeaveHint() { 
  super.onUserLeaveHint();
  // your code here
}
}}}
As of v1.0, Processing  has (to my knowledge) no native exception handling, but it can piggyback on top of what is in Java.
Processing uses the {{{try}}} \ {{{catch}}} method of exception handling:
{{{
try{
  doMyThing();
}
catch(SomeException e){
  println("Caught Exception: " + e.getMessage());
}
}}}
The exception being caught is what Processing spits out in red on the bottom of the IDE.  For example, one of my sketches recently tossed an {{{IndexOutOfBoundsException}}} when dealing with an {{{ArrayList}}}.   {{{Exception}}} is the parent of all exceptions, and will catch anything, but in general you should only catch the type of specific exception you're looking for.

Find tutorials on Java exception handling [[here|http://java.sun.com/docs/books/tutorial/essential/exceptions/]].  Covers more stuff like {{{throw}}} and {{{finally}}}.

See [[here|http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Exception.html]] for a list of Java exception types.  Many of these sub-classes of {{{Exception}}} have many subclasses of their own.
Ever since I got my [[Egg-Bot|http://egg-bot.com/]], I've been trying to figure out how to export svg data from Processing, to load into [[Inkscape|http://inkscape.org/]].

I found the [[proSVG|https://sites.google.com/site/kdlprosvg/]] library.  The examples run, but save fails:  Looks like it hasn't been updated since 2008, so is probably no longer compatible.

Processing comes included with it's own [[pdf library|http://www.processing.org/reference/libraries/pdf/index.html]], which I learned saves out as vector graphic data:  If these are imported into Inkscape, they're direclty converted to paths that will draw on the egg-bot.  Excellent!  A side effect however, is that the size of the pdf ends up being larger than the resolution defined in Processing, but it's an easy task to re-size it in Inkscape.
I have yet to do any fractal programming, but this sketch looks like a pretty good place to start:
http://www.cc.gatech.edu/~phlosoft/attractors/
An improvement on my [[BouncyBalls01]] [[QUICKSKETCH]].
Find video of this on [[Flickr|http://www.flickr.com/photos/warpcat/2666229237/?processed=1&cb=1216016281234]]
[img[http://farm4.static.flickr.com/3117/2667707781_f53e412dba.jpg?v=0]]
(They're based on a slightly older version that what is represented below.
{{{
/* 
 FuzzBall03.06
 Eric Pavey - 2008-07-13
 
 User can use the mouse to create balls by pressing the LMB.  
 Reset with MMB.
 Saves images with RMB.
 
 Balls draw bezier curves to other balls if they are in range which allow them to apply
 'pushing force' on one another.  Otherwise, draw "searcher" lines.  Balls push each 
 other around if they are in range, big balls have more force than small balls.
 If you push "m", will turn on "magnetic" mode:  Orange balls will attract, blue balls
 will repulse.
 
 Updates:
 3.01:  all balls now exert force on one another
 3.02:  LMB now creates new balls, much more interactive, and adds text 
 directions to splash screen.
 3.03:  Mouse motion now controls initial velocity and direction.
 Number of balls printed to screen 
 3.04:  Addition of 'checkState' method in Fball class:  Will allow for
 easier authoring of future behaviors.
 3.05:  MMB will now clear the screen, update splash screen
 3.06:  Adding ability for balls to push and pull.
 */

//----------------------------------------------------------
// user varaiable:
float minDiameter = 5;
float maxDiameter = 50;
int printBallNumber = 1;

//----------------------------------------------------------
// system vars, no touch
int c;
PFont fontA;
Fball[] baller = {};
float version = 3.06;
int magState = 0;

//----------------------------------------------------------

void setup(){
  size(640, 480);
  smooth(); 
  frameRate(30);
  background(0);
  c=0;
  fontA = createFont("Arial", 16, true);
}


//----------------------------------------------------------


void draw(){
  // setup our background:
  colorMode(HSB,100);
  fill(0,30);
  quad(0,0, width, 0, width, height, 0, height);

  // if no balls exist, draw our instructions:
  if(baller.length == 0){
    drawSplash();
  }

  // draw our balls
  for(int i=0; i<baller.length; i++){ 
    baller[i].moveBall();
    baller[i].checkState();
    baller[i].drawBall();
  }

  // print # of balls: 
  if(printBallNumber == 1){
    fill(0, 0, 100, 50);
    text(("Number of balls: " + baller.length), 30, height - 35);
    if(magState==1){
      text(("Magnetic State: ON"), 30, height - 60);      
    }
    else{
      text(("Magnetic State: OFF"), 30, height - 60);      
    }    
  }

  // mouse interaction:
  if(mousePressed){
    if(mouseButton == LEFT){
      baller = (Fball[])expand(baller, baller.length+1);  
      baller[baller.length-1] =  new Fball(minDiameter, maxDiameter);
    }
    if(mouseButton == CENTER){
      baller = (Fball[])expand(baller, 0); 
      fill(0,30);
      background(0); 
    }
    if(mouseButton == RIGHT){
      saveFrame("fuzzBall03-####.jpg");
      println("Saved a frame");
    }
  }
  if(keyPressed){
    if(key == 'm'){
       magState = abs(magState-1); 
    }
  }
}

void drawSplash(){
  textFont(fontA);
  fill(0, 0, 100);
  text("Press Left Mouse Button to create fuzzballs", 30, 60);
  text("*  Speed and direction of mouse effects fuzzball creation", 30, 90);
  text("Press Middle Mouse Button to clear the screen", 30, 150);
  text("Press Right Mouse Button to save an image", 30, 210);
  text("Press 'm' (very quickly!) to toggle 'Magnetic State':", 30, 270);
  text("*  Orange balls will attract, blue balls repulse", 30, 300);  
  text("Fuzzballs v" + version, 30, height-10); 
}

//----------------------------------------------------------


class Fball{
  // Properties

  float xPos;
  float yPos;
  float minDiameter;
  float maxDiameter;
  float diameter;
  float xVelocity;
  float yVelocity;
  float xCurVelocity;
  float yCurVelocity;
  color cirCol;
  float angle;
  float colVal;
  int attractOrPush;
  float forceScale;

  // Constructor

  Fball(float minDiameter, float maxDiameter){
    this.minDiameter = minDiameter;
    this.maxDiameter = maxDiameter;
    diameter = random(minDiameter,maxDiameter);
    xPos = mouseX + random(-5, 5);
    yPos = mouseY + random(-5, 5);

    xCurVelocity = (mouseX-pmouseX) * .1;
    yCurVelocity = (mouseY-pmouseY) * .1;
    float velocity = (abs(xCurVelocity) + abs(yCurVelocity))/2;
    if(velocity < 2){
      velocity = 2; 
    }
    xVelocity = velocity;
    yVelocity = velocity;  
    // for some reason, this wouldn't do anything when in the 
    // draw() or setup() functions...
    colorMode(HSB, 100);
    attractOrPush = int(random(0,2));
    // if we attract balls
    if(attractOrPush == 0){
      cirCol = color(random(0,10),  random(50,100), random(75,100));
      forceScale = -1;
    }
    else{
       cirCol = color(random(50,60),  random(50,100), random(75,100));    
       forceScale = 1; 
    }
    colVal = brightness(cirCol);
    angle = random(0, TWO_PI);
    
  }

  // Methods

  float[] getPos(){
    float[] r = {
      xPos, yPos    };
    return r;
  }

  float getDiameter(){
    return diameter;
  }

  void drawBall(){
    stroke(cirCol);
    strokeWeight(1);
    fill(cirCol,32);
    ellipse(xPos, yPos, diameter, diameter);
  }

  void applyForce(float forceX, float forceY, float force){
    float vecX = xPos - forceX;
    float vecY = yPos - forceY;
    float vecLength = mag(vecX, vecY);
    float normalX = vecX / vecLength;
    float normalY = vecY / vecLength;
    xCurVelocity = xCurVelocity + normalX * force * .01;
    yCurVelocity = yCurVelocity + normalY * force * .01;
  }

  void moveBall(){
    xPos = xPos + xCurVelocity;
    yPos = yPos + yCurVelocity;

    // Test to see if the shape exceeds the boundaries of the screen
    // If it does, reverse its direction by multiplying by -1
    if (xPos > width-(diameter/2)){
      xCurVelocity = -xVelocity;
      xPos = width-(diameter/2);
    }   
    if(xPos < diameter/2) {
      xCurVelocity = xVelocity;
      xPos = diameter/2;
    }

    if (yPos > height-(diameter/2)){
      yCurVelocity = -yVelocity;
      yPos = height-(diameter/2);
    }
    if (yPos < diameter/2) {
      yCurVelocity = yVelocity;
      yPos = diameter/2;
    }    
  }

  void checkState(){
    int foundCircle = 0;
    // search through all of our circles:
    for(int i=0; i<baller.length; i++){
      // don't draw a line to itself
      if(baller[i] != this){
        // get the distance between the current ball, and the ball being tested:
        float[] targetPos = baller[i].getPos();
        float distance = sqrt(abs(
        pow(targetPos[0]-xPos, 2) + 
          pow(targetPos[1]-yPos, 2)));

        // If a ball is in-range, what should happen?
        if(distance <= diameter*3){
          foundCircle = 1;
          drawLine(targetPos, baller[i]);
          if(magState == 1){
            baller[i].applyForce(xPos, yPos, (diameter*forceScale));
          }
          else{
            baller[i].applyForce(xPos, yPos, diameter);            
          }
          }
        }
      }
    // if nothing is in-range of our ball:  
    if(foundCircle == 0){
      drawSearcher();
    }
  }

  void drawLine(float[] targetPos, Fball baller){
    strokeWeight(2);
    stroke(cirCol,128);
    noFill();  

    // find the closest point on both of our circles, and draw a line
    // between those points:
    float sourceVecX = targetPos[0] - xPos;
    float sourceVecY = targetPos[1] - yPos;     
    float sourceAngle = atan2(sourceVecX, sourceVecY)  * -1 + HALF_PI;  

    float destVecX =  xPos - targetPos[0];
    float destVecY =  yPos - targetPos[1];      
    float destAngle = atan2(destVecX, destVecY) * -1 + HALF_PI;  

    float sourcePointX = xPos + cos(sourceAngle)*(diameter/2);
    float sourcePointY = yPos + sin(sourceAngle)*(diameter/2); 

    float destPointX = targetPos[0] + cos(destAngle)*(baller.getDiameter()/2);
    float destPointY = targetPos[1] + sin(destAngle)*(baller.getDiameter()/2); 

    ellipse(destPointX, destPointY, diameter/4, diameter/4);
    bezier(
    sourcePointX, sourcePointY, 
    random(sourcePointX-diameter, sourcePointX+diameter), random(sourcePointY-diameter, sourcePointY+diameter),  
    random(destPointX-diameter, destPointX+diameter), random(destPointY-diameter, destPointY+diameter),
    destPointX, destPointY);
  }

  void drawSearcher(){
    strokeWeight(2);
    stroke(cirCol,128);
    noFill();
    // plot a bezier between two points:  One on the edge of the circle,
    // and one some distance away:
    float eX = xPos + cos(angle)*(diameter/2);
    float eY = yPos + sin(angle)*(diameter/2);   
    float pX = xPos + cos(angle)*(diameter*1.5);
    float pY = yPos + sin(angle)*(diameter*1.5);  
    angle += 10/diameter;     

    bezier(
    eX, eY, 
    random(eX-diameter/2, eX+diameter/2), random(eY-diameter/2, eY+diameter/2),  
    random(pX-diameter/2, pX+diameter/2), random(pY-diameter/2, pY+diameter/2),
    pX, pY);    

    ellipse(pX, pY, diameter/4, diameter/4); 
  }
}
}}}
An improvement on my [[FuzzBalls03]] sketch.  ''Still wip.''
In a nutshell:
Pressing "p" (very quickly) will toggle between creating "push" or "pull" balls.  
Pressing "f" (very quickly) will toggle on "follow" balls.
Pressing "e" (very quickly) will toggle on\off 'energy usage'.

Put each of the below code segments in it's own sketch tab, with the given name:
{{{FuzzBall04}}}
{{{
/* 
 FuzzBall04.00
 Eric Pavey - 2008-07-13
 
 User can use the mouse to create balls by pressing the LMB.  
 Reset with MMB.
 Saves images with RMB.
 
 Balls draw bezier curves to other balls if they are in range which allow them to apply
 'pushing force' on one another.  Otherwise, draw "searcher" lines.  Balls push each 
 other around if they are in range, big balls have more force than small balls.
 If you push "m", will turn on "magnetic" mode:  Orange balls will attract, blue balls
 will repulse.
 
 Updates:
 
 */

//----------------------------------------------------------
// user varaiable:
float minDiameter = 5;
float maxDiameter = 50;
int printData = 1;

//----------------------------------------------------------
// system vars, no touch
float version = 4.00;
int c;
PFont fontA;

// should balls use energy, or not?
int useEnergy = 1;

// a list of ALL the balls in the scene:
Fball[] baller = {};

// just the PushPullBalls:
PushPullBall[] ppb = {};
int pushPullState =0;

// just the FollowBalls:
FollowBall[] fb = {};

// this defines the type of ball to create:
// 0 = push, 1 = pull, 2 = follow, 3 = ?
int creationState = 0;

//----------------------------------------------------------

void setup(){
  size(640, 480);
  smooth(); 
  frameRate(30);
  background(0);
  c=0;
  fontA = createFont("Arial", 16, true);
}


//----------------------------------------------------------


void draw(){

  // setup our background:
  colorMode(HSB,100);
  fill(0,32);
  quad(0,0, width, 0, width, height, 0, height);

  // if no balls exist, draw our instructions:
  if(baller.length == 0){
    drawSplash();
  }

  // draw our balls, for each different type:
  for(int i=0; i<ppb.length; i++){ 
    ppb[i].run();
  }
  for(int i=0; i<fb.length; i++){ 
    fb[i].run();
  }  

  // print # of balls: 
  if(printData == 1){
    drawData();
  }

  // mouse interaction:
  if(mousePressed){
    if(mouseButton == LEFT){
      if(creationState == 0){
        ppb = (PushPullBall[])expand(ppb, ppb.length+1);  
        ppb[ppb.length-1] =  new PushPullBall("push", minDiameter, maxDiameter);
        baller = (Fball[])expand(baller, baller.length+1);
        baller[baller.length-1] = ppb[ppb.length-1];
      }
      else if(creationState == 1){
        ppb = (PushPullBall[])expand(ppb, ppb.length+1);  
        ppb[ppb.length-1] =  new PushPullBall("pull", minDiameter, maxDiameter);
        baller = (Fball[])expand(baller, baller.length+1);
        baller[baller.length-1] = ppb[ppb.length-1];  

      } 
      else if(creationState == 2){
        fb = (FollowBall[])expand(fb, fb.length+1);  
        fb[fb.length-1] =  new FollowBall(minDiameter, maxDiameter);
        baller = (Fball[])expand(baller, baller.length+1);
        baller[baller.length-1] = fb[fb.length-1];        
      }        
    }
    if(mouseButton == CENTER){
      ppb = (PushPullBall[])expand(ppb, 0); 
      fb = (FollowBall[])expand(fb, 0);                   
      baller = (Fball[])expand(baller, 0);     

      fill(0,30);
      background(0); 
    }
    if(mouseButton == RIGHT){
      saveFrame("fuzzBall04-####.jpg");
      println("Saved a frame");
    }
  }

  // keyboard interaction:
  if(keyPressed){
    if(key == 'p'){
      pushPullState = abs(pushPullState-1); 
      creationState = pushPullState;

    }
    if(key == 'f'){

      creationState = 2;
      pushPullState = 0;  
    }    
    if(key == 'e'){
      useEnergy = abs(useEnergy-1); 
      if(useEnergy == 0){
        for(int i=0; i< baller.length; i++){
          baller[i].setEnergy(100); 
        }
      }
    }        
  }
}

void drawData(){
  fill(0, 0, 100, 50);
  text(("Number of balls: " + baller.length), width - 145, height - 30);

  if(useEnergy == 0){
    text(("Energy Usage: OFF"), 30, height - 60);      
  }
  else if(useEnergy == 1){
    text(("Energy Usage: ON"), 30, height - 60);           
  }

  if(creationState==0){
    text(("Creation State: Push"), 30, height - 30);      
  }
  else if(creationState == 1){
    text(("Creation State: Pull"), 30, height - 30);           
  }
  else if(creationState == 2){
    text(("Creation State: Follow"), 30, height - 30);           
  }    
}

void drawSplash(){
  textFont(fontA);
  fill(0, 0, 100);
  text("Fuzzballs v" + version, 30, 30); 
  text("Press Left Mouse Button to create fuzzballs", 30, 60);
  text("*  Speed and direction of mouse effects fuzzball creation", 30, 90);
  text("Press Middle Mouse Button to clear the screen", 30, 150);
  text("Press Right Mouse Button to save an image", 30, 210);
  //  text("Press 'm' (very quickly!) to toggle 'Magnetic State':", 30, 270);
  //  text("*  Orange balls will attract, blue balls repulse", 30, 300);  

}
}}}
{{{Fball}}}
{{{
// This is the master ball, that all other balls inherit from

class Fball{
  //---------------------------
  // PROPERTIES

  // current position:
  float xPos;
  float yPos;
  // min\max diamater
  float minDiameter;
  float maxDiameter;
  // derrived random diameter:
  float diameter;
  // creation velocity:
  float xVelocity;
  float yVelocity;
  // current velocity:
  float xCurVelocity;
  float yCurVelocity;
  // color
  color cirCol;
  // angle storage
  float angle;
  // name of ball
  String name;  
  // curent juice level:
  float energy;
  // define what type of ball this is;
  int cState;


  //---------------------------
  // CONSTRUCTOR

  Fball(float minDiameter, float maxDiameter){
    // setup our diameter:
    this.minDiameter = minDiameter;
    this.maxDiameter = maxDiameter;
    diameter = random(minDiameter,maxDiameter);

    // setup our initial position:
    xPos = mouseX + random(-5, 5);
    yPos = mouseY + random(-5, 5);

    // setup our velocity:
    xCurVelocity = (mouseX-pmouseX) * .1;
    yCurVelocity = (mouseY-pmouseY) * .1;
    float velocity = (abs(xCurVelocity) + abs(yCurVelocity))/2;
    if(velocity < 2){
      velocity = 2; 
    }
    xVelocity = velocity;
    yVelocity = velocity;  

    // for some reason, this wouldn't do anything when in the 
    // draw() or setup() functions...
    colorMode(HSB, 100); 

    // setup our initial angle:
    angle = random(0, TWO_PI);
    
    // setup initial energy
    energy = 100;
    
    // define the type of ball that just got made
    cState = creationState;
  }

  //---------------------------
  // METHODS

  void setEnergy(float energy){
    this.energy = energy;
  }

  //--------------------------- 
  // Get ball name 
  String getName(){
    return name;
  }  
  
  float getDistance(Fball ball){
    float[] targetPos = ball.getPos();
    float distance = sqrt(abs(
      pow(targetPos[0]-xPos, 2) + 
      pow(targetPos[1]-yPos, 2))); 
    return distance;
  }

  //---------------------------
  // Get bal position
  float[] getPos(){
    float[] r = {
      xPos, yPos            };
    return r;
  }

  //---------------------------
  // Get ball diameter
  float getDiameter(){
    return diameter;
  }

  //---------------------------
  // get the type of ball this is:
  int getCreationState(){
    return cState; 
  }

  //---------------------------
  // Can be used to apply positive, or negative forces
  // forceX and forceY and the positions the force is coming
  // from relative to this ball.  
  void applyForce(float forceX, float forceY, float force){
    float vecX = xPos - forceX;
    float vecY = yPos - forceY;
    float vecLength = mag(vecX, vecY);
    float normalX = vecX / vecLength;
    float normalY = vecY / vecLength;
    xCurVelocity = xCurVelocity + normalX * force * .01;
    yCurVelocity = yCurVelocity + normalY * force * .01;
  }


  //---------------------------
  // based on current position and velocity, move ball.
  // bounce off walls  
  void moveBall(){
    xPos = xPos + xCurVelocity;
    yPos = yPos + yCurVelocity;

    // Test to see if the shape exceeds the boundaries of the screen
    // If it does, reverse its direction by multiplying by -1
    if (xPos > width-(diameter/2)){
      xCurVelocity = -xVelocity;
      xPos = width-(diameter/2);
    }   
    if(xPos < diameter/2) {
      xCurVelocity = xVelocity;
      xPos = diameter/2;
    }

    if (yPos > height-(diameter/2)){
      yCurVelocity = -yVelocity;
      yPos = height-(diameter/2);
    }
    if (yPos < diameter/2) {
      yCurVelocity = yVelocity;
      yPos = diameter/2;
    }    
  }


  //---------------------------
  // Draws a jittering line between two balls.
  // baller is the name of the ball to draw a line to 
  void drawLine(Fball baller){
    float[] targetPos = baller.getPos();
    strokeWeight(2);
    stroke(cirCol,128);
    noFill();  

    // find the closest point on both of our circles, and draw a line
    // between those points:
    float sourceVecX = targetPos[0] - xPos;
    float sourceVecY = targetPos[1] - yPos;     
    float sourceAngle = atan2(sourceVecX, sourceVecY)  * -1 + HALF_PI;  

    float destVecX =  xPos - targetPos[0];
    float destVecY =  yPos - targetPos[1];      
    float destAngle = atan2(destVecX, destVecY) * -1 + HALF_PI;  

    float sourcePointX = xPos + cos(sourceAngle)*(diameter/2);
    float sourcePointY = yPos + sin(sourceAngle)*(diameter/2); 

    float destPointX = targetPos[0] + cos(destAngle)*(baller.getDiameter()/2);
    float destPointY = targetPos[1] + sin(destAngle)*(baller.getDiameter()/2); 

    ellipse(destPointX, destPointY, diameter/4, diameter/4);
    bezier(
    sourcePointX, sourcePointY, 
    random(sourcePointX-diameter, sourcePointX+diameter), random(sourcePointY-diameter, sourcePointY+diameter),  
    random(destPointX-diameter, destPointX+diameter), random(destPointY-diameter, destPointY+diameter),
    destPointX, destPointY);
  }

  //---------------------------
  // Searcher line to draw.  Usually drawn when nothing else is going on.
  void drawSearcher(){
    strokeWeight(2);
    stroke(cirCol,128);
    noFill();
    // plot a bezier between two points:  One on the edge of the circle,
    // and one some distance away:
    float eX = xPos + cos(angle)*(diameter/2);
    float eY = yPos + sin(angle)*(diameter/2);   
    float pX = xPos + cos(angle)*(diameter*1.5);
    float pY = yPos + sin(angle)*(diameter*1.5);  
    angle += 10/diameter;     

    bezier(
    eX, eY, 
    random(eX-diameter/2, eX+diameter/2), random(eY-diameter/2, eY+diameter/2),  
    random(pX-diameter/2, pX+diameter/2), random(pY-diameter/2, pY+diameter/2),
    pX, pY);    

    ellipse(pX, pY, diameter/4, diameter/4); 
  }
}
}}}
{{{FollowBall}}}
{{{

class FollowBall extends Fball{
  // what ball does this one follow?
  int followIndex=-1;

  FollowBall(float minDiameter, float maxDiameter){
    super(minDiameter, maxDiameter);
    name = ("FollowBall_" + fb.length); 

    cirCol = color(random(30,40),  random(50,100), random(75,100));  

    // what circle does this follow?
    followIndex = fb.length;    

  }

  //---------------------------
  void drawBall(){
    stroke(cirCol);
    strokeWeight(1);
    fill(cirCol,32);
    ellipse(xPos, yPos, diameter, diameter);
  }

  //---------------------------
  void behavior(){

    if(followIndex < fb.length && followIndex != -1){
      // if this follows someting, apply a force to push it to the parent:
      //int index = fb.length-1;
      int index = followIndex;
      float distance = getDistance(fb[index]);
      float scaler = distance / diameter;
      float[] lastPos = fb[index].getPos();    
      applyForce(lastPos[0], lastPos[1], -10*scaler);        
      //drawLine(fb[followIndex]);  
      drawLine(fb[index]);

    }
  }  

  //---------------------------
  void run(){
    super.moveBall();
    drawBall();   
    behavior();
  }

}
}}}
{{{PushPullBall}}}
{{{
// These balls push other balls around, or pull other balls to them.
// If energy usage is on, pushing and pulling costs energy.  When
// a balls energy hits zero, it goes into recharge mode, where it can't
// do any pushing or pulling until energy has recharged back to 100%.

class PushPullBall extends Fball{

  //-----------------------------
  // PROPERTIES:

  // 1 or -1, depending on if it pushes, or pulls
  float forceScale;
  // is this ball in recharge mode or not?
  int recharge = 0;

  //-----------------------------
  // CONSTRUCTOR:

  PushPullBall(String pushPull, float minDiameter, float maxDiameter){
    super(minDiameter, maxDiameter);
    // define name pushPull should be either 'push', or 'pull':
    name = (pushPull + "Ball_" + ppb.length); 

    // define color, and force:
    if(pushPull == "push"){
      cirCol = color(random(50,60),  random(50,100), random(75,100));    
      forceScale = 1;
    }
    if(pushPull == "pull"){
      cirCol = color(random(0,10),  random(50,100), random(75,100));   
      forceScale = -1; 
    } 
  }

  //-----------------------------
  // METHODS:

  //---------------------------
  void drawBall(){
    stroke(cirCol);
    strokeWeight(1);
    if(useEnergy == 1){
      fill(cirCol,energy);
    }
    else{
      fill(cirCol,32);    
    }
    ellipse(xPos, yPos, diameter, diameter);
    if(recharge == 1){
      fill(cirCol, 100-energy);
      stroke(cirCol, energy);
      ellipse(xPos, yPos, (diameter * (energy*.02)), (diameter * (energy*.02)));    
    }
  }  


  //---------------------------
  void behavior(){
    int foundCircle = 0;
    // search through all of our circles:
    for(int i=0; i<baller.length; i++){
      // don't interact with itself:
      if(baller[i] != this){
        // get the distance between the current ball, and the ball being tested:
        float[] targetPos = baller[i].getPos();
        float distance = getDistance(baller[i]);

        // If a ball is in-range, has enough energy; push or pull:
        if(distance <= diameter*3 && energy > 0 ){  

          // if we're *not* currently recharging our ball...
          if(recharge == 0){   
            float energyUsage=0;
            // if we're pulling balls, stop pulling when they get close:
            // also, don't pull other pull balls.
            if(distance > diameter && forceScale == -1 && baller[i].getCreationState() != 1){
              energyUsage = baller[i].getDiameter() / diameter * .5;
              foundCircle = 1;
              drawLine(baller[i]);
              // scaler is used to reduce the forceScale the closer the
              // target gets to our ball.
              float scaler = distance / diameter;
              baller[i].applyForce(xPos, yPos, (diameter*forceScale*scaler));
            }

            // if we're pushing balls, push them away no matter how close:
            if(distance > diameter && forceScale == 1){
              energyUsage = baller[i].getDiameter() / diameter;
              foundCircle = 1;
              drawLine(baller[i]);
              baller[i].applyForce(xPos, yPos, (diameter*forceScale));
            }

            // if we're using energy, and we found a ball to use it on:
            if(useEnergy==1 && foundCircle == 1){
              // figure new energy:
              if(energy > 0){
                energy = energy - energyUsage;
              }
              // if we hit 0 energy, start recharge cycle
              if(energy <= 0){
                recharge = 1;
                energy = 0;
              }
            }
          }
        }
      }
    }

    // if nothing is in-range of our ball:  
    if(foundCircle == 0){
      if(recharge == 0){
        drawSearcher();
      }
      // recharge energy:
      if(energy < 100){
        energy++; 
      }
      if(energy >= 100){
        energy = 100; 
        recharge = 0;
      }
    }
  }


  //---------------------------
  void run(){
    super.moveBall();
    drawBall();   
    behavior();
  }
}
}}}
http://users.design.ucla.edu/~acolubri/processing/glgraphics/home/
"GLGraphics is a library for the Processing programming language that integrates ~OpenGL textures and ~GPU-accelerated effects into the Processing API. "

Tread on bugs with Processing v1+:
http://processing.org/discourse/yabb2/YaBB.pl?num=1237493983
http://users.design.ucla.edu/~acolubri/processing/gsvideo/home/
"GSVideo is a library for the Processing programming language that offers video playback, capture and recording capabilities through the use of the ~GStreamer multimedia framework."
http://www.processing.org/reference/PFont.html
{{{
String[] fontList;

void setup(){
  fontList = PFont.list();
  println(fontList);  
}
}}}
Prints (for my Samsung Captivate, Android 2.1) :
{{{
[0] "Monospaced-Bold"
[1] "Monospaced"
[2] "SansSerif"
[3] "Serif-Italic"
[4] "SansSerif-Bold"
[5] "SansSerif-BoldItalic"
[6] "Serif-Bold"
[7] "SansSerif-Italic"
[8] "Monospaced-BoldItalic"
[9] "Monospaced-Italic"
[10] "Serif-BoldItalic"
[11] "Serif"
}}}
I'd originally done this work in Mel (can see notes over on my [[Mel Wiki|http://mayamel.tiddlyspot.com/#%5B%5BGiven%20a%20point%2C%20a%20vector%20from%20that%20point%2C%20and%20a%20distance%2C%20how%20can%20I%20figure%20out%20where%20the%20new%20point%20lives%3F%5D%5D]]), but with the advent of the [[PVector|http://www.processing.org/reference/PVector.html]] object in Processing 1.0 (yay!), here it is in Processing:

Multiply the unit-vector (normalized vector) by the distance, and add that to your original point:
{{{
// define our point in space:
PVector p = new PVector(0, 0, 0);
// define vector from that point:
PVector v = new PVector(1, 1, 0);
// define distance to travel along vector
float d = 3;

v.normalize();
PVector m = PVector.mult(v, d);
PVector result = PVector.add(m, p);
println(result.array());
}}}
prints:
{{{
[0] 2.1213202
[1] 2.1213202
[2] 0.0
}}}
All {{{PImage}}} objects have a {{{.pixels[]}}} array, holding all their color value.  If you an index in the array, how can you figure out what the xy value of that pixel is?

{{{
PImange img = loadImage("foo.jpg");

// The pixel in the array you want to find the xy val of.
// Remember, the array is zero based, so this is the 8th
// pixel.
int myPixel = 7; 

int x = myPixel % img.width;
int y = myPixel / img.width;

println("Pixel '" + myPixel + "' is at position x:" + x + " y:" +y);
Pixel '7' is at position x:3 y:1
// Presuming your image is w4 h4 (16 pixels total).
// Again, remember that the coordinates are zero-based.
}}}
Basically the equation goes:
{{{
x = i % w;
y = i / w; 
}}}
So you can use it for any kind of array, presuming you know the array's 'width'.  But images make the most sense.
With Perlin noise code taken from [[PerlinParticles02]], Make snowflakes fall in a 3D environment, pulsing to the beat of [[GrooveSalad|http://somafm.com/play/groovesalad]] on [[SomaFM.com.|http://somafm.com/]].  Uses the [[Minim|http://code.compartmental.net/tools/minim/]] audio library.
See extra notes (and imagery) on my [[Blog|http://warpcat.blogspot.com/2008/12/grooveflakes.html]].
The sketch is broken in to four separate tabs, listed below:
----
Tab ''GrooveFlakes01'':
{{{
/*
GrooveFlakes01
 Eric Pavey - 2008-12-28  
 
 Render a 3d scene with falling snowflakes.
 The flakes fall 'through' perlin noise, modulating
 their position.
 Soundtrack by GrooveSalad - somaFM.com
 */

//------------------------------
// Import in the Minim audio lib:
// Download here: http://code.compartmental.net/tools/minim/
import ddf.minim.*;
import ddf.minim.analysis.*;

//------------------------------
// User vars:

// What height to make the window?  Width is auto-set to
// be 1.5 that amount.
int winRes = 768;
// Scale the whole scene.  Mainly just effects the relative
// size of the flakes:
int terrainSize = 2;


// How much turbulance to the noise?
float noiseFreq = random(2,6);
// How much amplitude to the noise?
float noiseAmp = random(3,6);
// Gravity should be at least half the noiseAmp, if you
// want to keep the flakes falling down
float gravity =noiseAmp/2;

// How many total snowflakes?
int numFlakes = 3000;

// Audio related vars:
// How big should our differnt kind of flakes be?
float kickFlakeSize = 2.0;
float snareFlakeSize = 2.0;
float hatFlakeSize = 2.0;
float snowSize = 4.0;
// how much bigger should they scale when on the beat?
float beatScale = 4.0;

// Define colors:
color sky = color(0,0,0);
color snow = color(255,255,255);

color kickCol = color(255,0,0);
color snareCol = color(0,255,0);
color hatCol = color(255,255,0);

//------------------------------
// System vars, no touch!
int depth = winRes;
Flake[] flakes = new Flake[numFlakes];
PImage imageX; 
PImage imageY; 
PImage imageZ;
int res = winRes * terrainSize;
float center = res / 2;
float[] cEye = {
  center, center, center};

// Audio stuff:
Minim minim;
AudioPlayer song;
BeatDetect beat;
BeatListener bl;
float kickSize, snareSize, hatSize;

// Text stuff:
PFont fontA = createFont("Arial", 32, true);    

//------------------------------
void setup(){
  size(int(winRes*1.5),winRes, P3D);
  frameRate(30);
  smooth(); 

  imageX = createImage(winRes, winRes, ARGB);
  imageY = createImage(winRes, winRes, ARGB);
  imageZ = createImage(winRes, winRes, ARGB);  

  makePerlin(imageX, noiseFreq);
  makePerlin(imageY, noiseFreq);
  makePerlin(imageZ, noiseFreq);  

  for(int i=0; i<numFlakes; i++){
    flakes[i] = new Flake(imageX, imageY, imageZ, 
    snow, kickCol, snareCol, hatCol, 
    kickFlakeSize, snareFlakeSize, hatFlakeSize, snowSize,
    gravity, noiseAmp); 

  }

  // Start our audio playing:
  minim = new Minim(this);
  // Load up the GrooveSalad playlist (from www.somafm.com), 
  // and give the AudioPlayer buffers that are 2048 samples long
  song = minim.loadFile("http://160.79.128.242:8032", 2048);
  // play the file
  song.play();  
  // Setup our beat detection:
  beat = new BeatDetect(song.bufferSize(), song.sampleRate());
  // sensitivty in milliseconds
  beat.setSensitivity(10);  
  bl = new BeatListener(beat, song); 

  // Bug:  If for some reason we don't render a box
  // a weird rendering anomoly shows up:
  // It's like certain flakes render in camera-space...?  
  box(1, 1, 1);
}

//------------------------------
void draw(){
  // Audio detection:
  if ( beat.isKick() ) kickSize = kickFlakeSize*beatScale;
  if ( beat.isSnare() ) snareSize = snareFlakeSize*beatScale;
  if ( beat.isHat() ) hatSize = hatFlakeSize*beatScale;

  background(sky);
  // Flip the corrdinate system, so +y goes up (like Maya)
  // This helps my brain.
  rotateX(PI);
  translate(0, -height, 0);

  // setup the perspective camera lense (from Processing examples)
  float fov = PI/2.0;
  float cameraZ = (height/2.0) / tan(PI * fov / 360.0);
  perspective(fov, float(width)/float(height), cameraZ/10.0, cameraZ*10.0);

  // define our camera look at point:
  float rot = map(mouseX, 0, width, 0, TWO_PI);
  float pX = cEye[0] + cos(rot)*winRes;
  float pZ = cEye[2] + sin(rot)*winRes;  
  float pY = map(mouseY, 0, float(height), 0, float(height*2));

  camera(cEye[0], cEye[1], cEye[2], pX, pY, pZ, 0, -1, 0);

  // draw the center axis (debug)
/*
  stroke(255,0,0);
  strokeWeight(1);
  line(0,0,0, res,0,0);
  stroke(0,255,0);
  line(0,0,0, 0,res,0); 
  stroke(0,0,255);
  line(0,0,0, 0,0,res);  
  */


  // draw our background:
  stroke(128,128,128);
  line(0,0,0, res,0,0);
  line(0,0,0, 0,0,res);    
  line(res,0,res, res,0,0);
  line(res,0,res, 0,0,res); 

  line(0,res,0, res,res,0);
  line(0,res,0, 0,res,res);    
  line(res,res,res, res,res,0);
  line(res,res,res, 0,res,res);   


  // Render our showflakes
  for(int f=0; f<numFlakes; f++){
    flakes[f].run();  
  }

  displayText();
  // Now bring the beat size back down:
  kickSize = constrain(kickSize * 0.9, 1, beatScale);
  snareSize = constrain(snareSize * 0.9, 1, beatScale);
  hatSize = constrain(hatSize * 0.9, 1, beatScale);
}

//------------------------------
// Stop Minim when over:
void stop()
{
  // always close Minim audio classes when you are done with them
  song.close();
  minim.stop();
  super.stop();
}


//------------------------------
void displayText(){
  fill(255,128);
  String lineA = "GrooveFlakes";
  String lineB = "Powered by GrooveSalad";
  String lineC = "somaFM.com";
  textFont(fontA);
  
  pushMatrix();
  translate(center, center, center*1.5);
  rotateX(-PI);
  text(lineA,0,0,0);
  translate(0,20,0);
  scale(.50,.50,.50);
  text(lineB,0,0,0);
  translate(0,30,0);
  text(lineC,0,0,0);
  popMatrix();

}
}}}
Tab ''~BeatListener'':
{{{
// from the example file "Minim->BeatDetect->FrequencyEnergy"
class BeatListener implements AudioListener
{
  private BeatDetect beat;
  private AudioPlayer source;
  
  BeatListener(BeatDetect beat, AudioPlayer source)
  {
    this.source = source;
    this.source.addListener(this);
    this.beat = beat;
  }
  
  void samples(float[] samps)
  {
    beat.detect(source.mix);
  }
  
  void samples(float[] sampsL, float[] sampsR)
  {
    beat.detect(source.mix);
  }
}
}}}
Tab ''Flake'':
{{{
//------------------------------
class Flake{
  float x, y, z;
  float rx, ry, rz;
  float randX, randY, randZ;

  String[] types = {
    "kick", "snare", "hat","snow","snow","snow"  };
  String type = "";
  float dia;

  PImage imageX;
  PImage imageY;
  PImage imageZ;

  color snow;
  color kickCol;
  color snareCol;
  color hatCol;

  float kickFlakeSize;
  float snareFlakeSize;
  float hatFlakeSize;
  float snowSize;
  
  float gravity;
  float noiseAmp;

  Flake(PImage imageX, PImage imageY, PImage imageZ, 
  color snow, color kickCol, color snareCol, color hatCol, 
  float kickFlakeSize, float snareFlakeSize, float hatFlakeSize, float snowSize,
  float gravity, float noiseAmp){
    this.imageX = imageX;
    this.imageY = imageY;
    this.imageZ = imageZ;

    this.snow = snow;
    this.kickCol = kickCol;
    this.snareCol = snareCol;
    this.hatCol = hatCol;
    this.kickFlakeSize = kickFlakeSize;
    this.snareFlakeSize = snareFlakeSize;
    this.hatFlakeSize = hatFlakeSize;
    this.snowSize = snowSize;
    
    this.gravity = gravity;
    this.noiseAmp = noiseAmp;

    x = random(0, res);
    y = random(0, res); 
    z = random(0, res);
    rx = random(0, TWO_PI);
    ry = random(0, TWO_PI);
    rz = random(0, TWO_PI);    

    type = types[int(random(0,6))];
  }

  void render(){
    // define new random postion:
    x = x + randX;
    y = y + randY - gravity;
    z = z + randZ;

    // do flake rotation:
    rx = rx + TWO_PI/120;
    ry = ry + TWO_PI/120; 
    rz = rz + TWO_PI/120;

    pushMatrix();
      translate(x, y, z);      
      rotateX(rx);
      rotateY(ry);
      rotateZ(rz);
    
      // Render the flake mesh:
      flakeMesh();
    popMatrix();

    // if out of bounds, reset:
    if(y < 0){
      y=res;
    }
    else if(y>res){
      y = 0; 
    }
    if(x < 0){
      x = res;
    }   
    else if(x>res){
      x=0; 
    }
    if(z < 0){
      z=res;
    }  
    else if(z>res){
      z=0;
    }    
  }

  void rand(){
    float mx = map(x, 0, res, 0, winRes);
    float my = map(y, 0, res, 0, winRes);
    float mz = map(z, 0, res, 0, winRes);

    color xCol = imageX.get(int(mz), int(my));
    color yCol = imageY.get(int(mx), int(mz));
    color zCol = imageZ.get(int(mx), int(my)); 

    float xVal = map(brightness(xCol), 0.0, 255.0, -1.0, 1.0);
    float yVal = map(brightness(yCol), 0.0, 255.0, -1.0, 1.0);
    float zVal = map(brightness(zCol), 0.0, 255.0, -1.0, 1.0);  

    // scale up the speed if they're on the beat:
    float beatScale=1;
    if(type == "kick"){
      beatScale = kickSize;;
    }
    if(type == "snare"){
      beatScale = snareSize;    
    }    
    if(type == "hat"){
      beatScale = hatSize; 
    }      

    randX = (xVal *  noiseAmp*beatScale);
    randY = (yVal *  noiseAmp*beatScale);
    randZ = (zVal *  noiseAmp*beatScale);
  }

  void flakeMesh(){
    // make flakes fade to black as they opproach the boundary:
    float dFromC = dist(x,y,z, center, center,center)-center/2;
    float dClamp = constrain(dFromC, 0, center);
    float dMap = map(dClamp, 0, center, 0, 1);
    color black = color(0,0,0);
    
    stroke(lerpColor(snow, black, dMap));
    strokeWeight(1);
    dia = snowSize;
    
    if(type == "kick"){
      dia = kickFlakeSize*kickSize;
      color newCol = lerpColor(kickCol, color(0,0,0), dMap);
      stroke(newCol);
    }
    if(type == "snare"){
      dia = snareFlakeSize*snareSize;
      stroke(lerpColor(snareCol, color(0,0,0), dMap));
    }    
    if(type == "hat"){
      dia = hatFlakeSize*hatSize; 
      stroke(lerpColor(hatCol, color(0,0,0), dMap));
    }   

    float[] xes = {
      0, .75, 1, .75, 0, -.75, -1, -.75     };       
    float[] yes = {
      -1, -.75, 0, .75, 1, .75, 0, -.75     };

    pushMatrix();  
    scale(dia); 

    beginShape(LINES);
    for(int m=0; m<xes.length; m++){
      vertex(0, 0, 0);     
      vertex(xes[m], yes[m], 0);
    }
    endShape();
    popMatrix();
  }

  void run(){
    rand();
    render();
  }

}
}}}
Tab ''makePerlin'':
{{{
//-----------------------------
// Make a 'perlin noise image'.
// Fill the define image with noise.
// channel is 0-2, = r, g, or b

void makePerlin(PImage img, float noiseScale){
  noiseSeed(int(random(0,1000)));
  
  for(int x=0; x < res; x++) {
    for(int y=0; y < res; y++){
      // normalize the x & y positions between 0-1
      float normX = map(x, 0, res, 0, noiseScale);
      float normY = map(y, 0, res, 0, noiseScale);  
      // find the noise value for that x,y pos:    
      float val = noise(normX, normY);
      // map that value to a color:
      int cVal = int(map(val, 0, 1, 0, 255));

      color col = color(cVal);     
      img.set(x,y,col);     
    }
  }  
}
}}}
<<timeline>>
Say you have a custom class, and as you press the mouse, you create new instances of the class.  You need to store these new objects in an array, so you can in your {{{draw()}}} function, draw them.  Unless there is an obviously easier way I'm simply missed, this is the current method I use:

Define our class (possibly in some other tab):
{{{
class Foo{
  void run(){
    // do work...
  }
}
}}}
At the start of the sketch, define an empty array to hold the objects:
{{{
Foo[] fooie = {};
}}}
Then in the {{{draw()}}} function, update the array with new Foo objects if the mouse has been pressed (mouse press code omitted).  
First we expand the array by one, then we create a new Foo object, and add it to the array.  Since we're passing a custom object into the {{{expand}}} command, we first need to 'cast' the object array's data type //in front// of the {{{expand}}} command.  At this point, this is the only place in Processing I've seen this convention used.
{{{
fooie = (Foo[])expand(fooie, fooie.length+1);  
fooie[fooie.length-1] =  new Foo();
}}}
Finally, we could call to the '{{{Foo.run()}}}' method to draw all the objects inside of the {{{draw()}}} function:
{{{
for(int i=0; i<fooie.length; i++){ 
  fooie[i].run();
}  
}}}
As you can see, some syntactical hoop-jumping is required to update the array size, and add our object to it.  In fact, in the past the docs on [[expand|http://www.processing.org/reference/expand_.html]] seem to be wrong in some areas, which added to the confusion.  But as of Processing v0148, the docs seem to be more clear.

If later you wanted to remove all the objects from the sketch, you can just clear the array:
{{{
fooie = (Foo[])expand(fooie, 0);
}}}
----
Also see:
*[[How can I increase the size of an array?]]
With Processing 1.0, you can now use [[PVector.normalize()|http://www.processing.org/reference/PVector_normalize_.html]], but up until then, of if you want to see another method, see below:
----
A {{{unit vector}}} is a vector with the same direction of the source vector, but with lengh = 1.  Also called //normalizing// the vector.
{{{
float vecX = 2;
float vecY = 3;
float vecLength = mag(vecX, vecY);
float normalX = vecX / vecLength;
float normalY = vecY / vecLength;
println("Original vector xy: " + vecX + ", " + vecY);
println("Normalized vector xy: " + normalX + ", " + normalY);
}}}
{{{
Original vector x,y: 2.0, 3.0
Normalized vector x,y: 0.5547002, 0.8320503
}}}
{{{
void setup(){
  frame.setTitle("My awesome sketch! - www.AKEric.com");
}
}}}
{{{
PImage img = loadImage("foo.jpg");
int w = img.width;
int h = img.height;
color c = img.get( int(random(0,w)), int(random(0,h)) );
}}}
{{{
int rand = int(random(0,2));
println(rand);
}}}
It's important to have the {{{abs()}}} in there, or you could end up trying to calculate the {{{sqrt()}}} of some negative value (not so good).  Using the {{{Pythagorean theorem}}}:
{{{
float dis = sqrt(abs(
    pow(mouseX, 2) - pow(pmouseX, 2) + 
    pow(mouseY, 2) - pow(pmouseY, 2)));
}}}
Since I'm still learning trig... was trying to find a way to figure out what the angle was of a given vector.  The below example has two a point with the x and y values equidistant from the origin.  This would result in a line being drawn to it from the origin at a 45 deg angle:
{{{
float x1 = 5;
float y1 = 5;
float angle = atan2(x1, y1);
println(degrees(angle));
45
}}}
Check out ~JPGVideo:
http://www.ndrw.co.uk/
I've been using this simple little application to convert jpg sequences into avi files for upload to Flickr, and it works really well.  Not a lot of options, but... it's not like you need a lot of options...
You can override the parent Activity class's [[onUserLeaveHint|http://developer.android.com/reference/android/app/Activity.html#onUserLeaveHint()]] method:
{{{
public void onUserLeaveHint() { 
  super.onUserLeaveHint();
  // custom code here
}
}}}
Straight from the [[Processing Docs|http://processing.org/learning/basics/loadingimages.html]]
{{{
size(200, 200);
PImage img1;
img1 = loadImage("http://www.processing.org/img/processing_beta_cover.gif");
image(img1, 0, 45);
}}}
The {{{createGraphics()}}} function.
http://www.processing.org/learning/basics/creategraphics.html
http://www.processing.org/reference/createGraphics_.html
Please see my other example:
[[How can I match a point to the end of a line that has been rotated?]]
Processing has {{{sqrt}}}, but no 'cuberoot' command:
{{{
float num = 27.0;
float raise = 1.0 / 3.0;
println(pow(num, raise));
3.0;
}}}
{{{.length}}}
{{{.size()}}}
{{{.Size}}}
It depends on the variable type it seems.
You can access the fields of the [[PImage|http://www.processing.org/reference/PImage.html]] object:
{{{
PImage img = loadImage("foo.jpg");
int w = img.width;
int h = img.height;
}}}
Example found in Processing Hacks by 'antiplastik':
http://processing.org/hacks/doku.php?id=hacks:listing-files
Source:
{{{
/**
listing-files taken from http://processinghacks.com/hacks:listing-files
@author antiplastik
*/
 
// we'll have a look in the data folder
java.io.File folder = new java.io.File(dataPath(""));
 
// let's set a filter (which returns true if file's extension is .jpg)
java.io.FilenameFilter jpgFilter = new java.io.FilenameFilter() {
  boolean accept(File dir, String name) {
    return name.toLowerCase().endsWith(".jpg");
  }
};
 
// list the files in the data folder, passing the filter as parameter
String[] filenames = folder.list(jpgFilter);
 
// get and display the number of jpg files
println(filenames.length + " jpg files in specified directory");
 
// display the filenames
for (int i = 0; i < filenames.length; i++) println(filenames[i]);
}}}
When I press the "back" button on my phone, the sketch does appear to properly exit.  I can relaunch it consistently without issue.  However, if I press the home button, even though it looks like the sketch quits, it doesn't:  The process is still running in the background.  Pressing 'home' doesn't seem to kill the sketch.

Since Processing sketches launch from the parent Activity class's onResume() method (uh, right?), and quit from the onPause() method, I simply override onPause() with a call to Activity's finish() method:
{{{
void onPause(){
  super.onPause();
  // kill our sketch, for reals:
  super.finish();
}
}}}
Calling to finish() moves into the onDestroy() method, exiting the Activity.
http://developer.android.com/reference/android/app/Activity.html#finish()
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
This may have other unforeseen consequences however.  For example, if someone calls you in the middle of the sketch I have a feeling it'll just kill the sketch.  But maybe that's desirable?
While a sketch is running you can author a [[function]] around the {{{keyPressed}}} system variable, that queries which key is pressed, via the {{{key}}} system variable:
{{{
void keyPressed()
{
// Note the single quotes ('), not double quotes(")
  if(key == 'a') {
    // do something
  }
}
}}}
{{{expand()}}}
To use though, some examples:
{{{
// here we declare an empty array:
float[] foo = {};

println(foo.length); 
// prints 0

foo = expand(foo, 4);
println(foo.length); 
// prints 4
}}}
The 2nd arg is always the size to make it.  It's //not// "will add this much to the size".

However, this gets more complicated if you have an array of objects:
{{{
class Foo{
}
Foo[] data = {};

println(data.length);  
// Prints 0

data = (Foo[])expand(data, 2);
println(data.length);  
// Prints 2
}}}
As you can see, for some reason you need to call to your class in parenthesis {{{(Foo[])}}} //before// the {{{expand}}} command.  This doesn't appear to be documented... :-S
----
Also see:
*[[How can I add objects to an array over time?]]
{{{ArrayList}}}s are great for giving you a more flexible way of dealing with list\array data.  They also let you insert into them at a certain index if you want:
{{{
void setup(){
  noLoop(); 
}

void draw(){
 ArrayList foo = new ArrayList(); 
 
 String val0 = "0";
 String val1 = "1";
 String val2 = "2";
 foo.add(val1);
 foo.add(val2);
// here we insert our val0 at index 0, that 
// was  previously occupied with val1:
 foo.add(0, val0);
 
 for(int i=0; i<foo.size(); i++){
  String num = (String) foo.get(i);
  println(num);
 }     
}
}}}
prints:
{{{
0
1
2
}}}
Consider you have the hand of a clock spinning, and you want to position an item on the end of the hand, but not have that item rotate in space?  Two solutions are provided below.

Example 1 uses push and popMatrix, so the circle is at the orgin.  {{{lineLength}}} can also be considered the radius of the circle.  The main computation is this:
{{{
float newX = lineLength * cos(rot-HALF_PI);
float newY = lineLength * sin(rot-HALF_PI);
}}}
Example 2 //doesn't// use any matrix work, and because of that uses a slightly different formula.  {{{cirX}}} and {{{cirY}}} are the center of the defined circle:
{{{
float pX = cirX + cos(rot)*radius;
float pY = cirY + sin(rot)*radius;
}}}
----
Code: (for some reason, the [[ProcessingjsPlugin]] won't display this in the wiki)
Example 1:  Using push and popMatrix:
{{{
// Translate a point to match the end point of a rotated line.

float rot = 0;
int w = 200;
int h = 200;

void setup(){
  size(w, h);
  background(0);
  stroke(255);
  strokeWeight(2);
  smooth();
}
  
void draw(){
  // fill our background each loop:
  quad(0, 0, width, 0, width, height, 0, height);

  // move the frame so the origin is at the middle bottom
  // of the window:
  translate(width/2, height/2);

  //draw a circle to mark the origin point:
  ellipse(0,0, 10,10);

  // rotate our matrix, and draw a line:
  pushMatrix();
  rotate(rot);
  float lineLength = height/4;
  line(0, 0, 0, -lineLength);
  popMatrix();
  
  // create an ellipse at the location of the end of the  
  // line, but based on a different transformation matrix:
  float newX = lineLength * cos(rot-HALF_PI);
  float newY = lineLength * sin(rot-HALF_PI);

  fill(0);
  ellipse(newX, newY, 5, 15);

  rot = rot + .01;
}
}}}
Example 2:
{{{
float radius = 40;
float rot = 0;

void setup(){
  stroke(255);
  strokeWeight(2);
  smooth();
}

void draw(){
  // fill our background each loop:
  background(0);

  // determine the center of our circle:
  float cirX = width/2;
  float cirY = height/2;
  
  // draw our circle:
  fill(0,255);
  ellipse(cirX,cirY, radius*2,radius*2);

  //draw a circle to mark the center point:
  ellipse(cirX,cirY, 10,10);

  // determine the point on the circumference of our circle:
  float pX = cirX + cos(rot)*radius;
  float pY = cirY + sin(rot)*radius;

  // create an ellipse at the location of the end of the line:
  stroke(128);
  line(cirX, cirY, pX, pY);

  fill(255);
  ellipse(pX, pY, 5, 15);

  rot = rot + .01;
}
}}}
{{{pixels[]}}} is a global system variable that stores all the pixels from the sketch screen.  You load pixels into the array via the {{{loadPixels()}}} function.  If you make any changes to the pixels in the array, you can apply them back to the screen with the {{{updatePixles}}} function.
http://www.processing.org/reference/pixels.html
http://www.processing.org/reference/loadPixels_.html
http://www.processing.org/reference/updatePixels_.html
{{{
loadPixels();
int totalPix = width * height;
for(int i=0; i<totalPix; i++){
  // do work on pixels[$i];
}
updatePixels();
}}}
Use {{{java.lang.Thread}}}:
{{{
import java.lang.Thread;

void setup(){
  size(256, 256); 

  try{
    Thread.sleep(2000);
    println("paused!");
  }
  catch (InterruptedException e){
    println(e);
  }
}
}}}
{{{
iimport java.util.Map;

Map<String, String> env = System.getenv();
for (String envName : env.keySet()) {
  // Java Way:
  //System.out.format("%s=%s%n", envName, env.get(envName));
  // Processing Way:
  println(envName + "=" + env.get(envName) );
}
}}}
You can query via {{{g.}}} for certain values:
{{{
println(g.strokeWeight);
println(g.fill);

1.0
true
}}}
These are read only attributes.  Here is a list, maybe more?
{{{
strokeWeight
smooth
strokeJoin
noSmooth
ellipseMode
rectMode
strokeCap
}}}
Via the 'Shape | Attributes' section in the extended reference.
using Java's {{{Random}}} class.  Example is using an {{{int}}} array.  If you wanted to use a different type of data, check the docs on Random [[here|http://java.sun.com/j2se/1.4.2/docs/api/java/util/Random.html]].
{{{
Random rand = new Random();

int[] myArray = {1,2,3,4,5};
int pos, temp;

for (int i=1; i<myArray.length; i++){
  pos = rand.nextInt(i);
  temp = myArray[pos];
  myArray[pos] = myArray[i];
  myArray[i] = temp;
}

for(int i=0; i<myArray.length; i++){
  print(myArray[i] + " ");
}
3 1 4 5 2
}}}
Found from this post:
http://forum.java.sun.com/thread.jspa?threadID=731204&messageID=10009632
The easiest way is with [[loadStrings|http://www.processing.org/reference/loadStrings_.html]]
Modified version from the docs, read in a playlist file from the web:
{{{
String lines[] = loadStrings("http://somafm.com/groovesalad.pls");
for (int i=0; i < lines.length; i++) {
  println(lines[i]);
}
}}}
Prints:
{{{
[playlist]
numberofentries=4
File1=http://streamer-ntc-aa02.somafm.com:80/stream/1018
Title1=SomaFM: Groove Salad (#1 128k mp3): A nicely chilled plate of ambient beats and grooves.
Length1=-1
File2=http://streamer-mtc-aa04.somafm.com:80/stream/1018
Title2=SomaFM: Groove Salad (#2 128k mp3): A nicely chilled plate of ambient beats and grooves.
Length2=-1
File3=http://streamer-ntc-aa04.somafm.com:80/stream/1018
Title3=SomaFM: Groove Salad (#3 128k mp3): A nicely chilled plate of ambient beats and grooves.
Length3=-1
File4=http://ice.somafm.com/groovesalad
Title4=SomaFM: Groove Salad (Firewall-friendly 128k mp3) A nicely chilled plate of ambient beats and grooves.
Length4=-1
Version=2
}}}
{{{
// add extra # symbols for more padding:
saveFrame("myFile####.jpg);
}}}
You need to enable {{{WRITE_EXTERNAL_STORAGE}}} in your sketch permissions, then point it to an intelligent save dir like the SD card:
{{{
save("//sdcard//DCIM/Camera/myImage.png");
}}}
Need to use {{{PGraphics}}} and {{{createGraphics}}}.  See this blog posting [[here|http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1231879947;start=7#6]].
Mainly pulled from the book:
[[Processing: A Progamming Handbook for Visual Designers and Artists|http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=11251]]
Presuming you have an array of colors to pass in, it will return a new array of the colors sorted from darkest to lighest:
{{{
color[] palette_darkToLight(color[] colors){
  color[] sorted = new color[colors.length];
  int num = 0;
  for(int i =0; i<255; i++){
    for(int j=0; j<colors.length; j++){
      if(int(brightness(colors[j])) == i){
        sorted[num] = colors[j];
        num++;
      }
    }
  }
  return sorted;
}
}}}
I've seen some really cool renders done with [[SunFlow|http://sunflow.sourceforge.net/]] up on Flickr.  
----
~SunflowApiApi, is a newer alternative:
http://code.google.com/p/sunflowapiapi/
Blog about how to install\use:
http://amnonp5.wordpress.com/2010/09/28/sunflow-processing/
joons-renderer seems to be related:
http://code.google.com/p/joons-renderer/
----
Old way
http://hipstersinc.com/p5sunflow/
{{{
int winRes = 512;
int depth = winRes;

void setup(){
  size(winRes, winRes, P3D);
}

void draw(){
  background(128, 128);
  lights();
  
  // position to middle of screen
  translate(width/2, height/2, -depth/4);
  // have mouse control the rotation of the scene:
  rotateX(map(mouseY, height, 0, 0, TWO_PI));
  rotateY(map(mouseX, width, 0, 0, TWO_PI)) ;  

  box(128);
}
}}}
Check out this blog here:
http://www.local-guru.net/blog/2010/08/01/how-to-use-the-mousewheel-in-processing
And for archival purposes, from that blog:
{{{
void setup() {
  size(300,300);
  smooth();
  addMouseWheelListener(new java.awt.event.MouseWheelListener() { 
    public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) { 
      mouseWheel(evt.getWheelRotation());
  }}); 
}
}}}
{{{
void mouseWheel(int delta) {
}
}}}
Tutorial over on [[processing.com|http://processing.org/learning/tutorials/2darray/]]

Any variable can be made into an array, and any array can can also be made into a 2D array by simply adding two sets of brackets.  Like an array, the size of the 2d array needs to be defined during initialization:
{{{
int[][] foo = new int[5][2];
}}}
To iterate over a 2d array in a loop, you need to know the size of each array element.
To find the size of the __first array element__:
{{{
println(foo.length);
5
}}}
To find the size of the __second array element__, you need to specify a bracket[] after the variable name.  You must put a number in the bracket, but the number doesn't seem to matter.  I find this convention a bit odd:
{{{
println(foo[0].length);
2
}}}
To loop over a 2d array:
{{{
for(int i=0; i<foo.length; i++){
  for(int j=0; j<foo[0].length; j++){
    println("foo[" + i + "][" + j + "] = " + foo[i][j]);
 } 
}

foo[0][0] = 0
foo[0][1] = 0
foo[1][0] = 0
foo[1][1] = 0
etc...
}}}
Also see:
*[[Info on arrays]]
Any variable can be made into an array by adding square-brackets {{{[]}}} after its variable type.  Arrays don't have a default data type, but are declared with a data type like variables are.

First an array is //declared//.  Once declared, the type can't change:
{{{
// Array declaration:
float[] foo;
// foo will now be a float array, forever
}}}
After declaration, they are //initialized//.  Array's need to use the [[new|http://www.processing.org/reference/new.html]] command:
{{{
// Array initialization.
foo = new float[50];
}}}
However, once initialized, their size can't changed (they become immutable sequences) without the help of the [[expand|http://www.processing.org/reference/expand_.html]] command.

Declaration and initialization can be combined into one statement:
{{{
float[] foo = new float[100];
}}}
Declaration can also assign the values at the same time, since this also determines the size:
{{{
int[] foo = {1,2,3};
}}}
However, things get a bit funny if you first initialize, //then// try to define with values:
{{{
int[] foo;
// this *won't* work:
foo = {1,2,3};
// this will work:
foo = new int[]{1,2,3};
}}}
Any object based on a [[class]] can be stored in an array based on it's type:
{{{
// make an array of ten 'foo' objects.

// Declare array:
Foo[] fooie; 
// Initialize array size:
fooie = new Foo[10];

for(int i=0;i<10;i++){
  fooie[i] = new Foo;
}

class Foo{
  // stuff
}
}}}
''Arrays also have [[methods|Array and String methods]].''

Also see:
*[[Info on 2d Arrays]]
*[[What types of variables does Processing have?]]
*[[How can I randomize an array?]]
<<gradient horiz #ddddff  #ffffff  >>This is a [[TiddlyWiki|http://tiddlywiki.com/]].  To really get a grasp on how to navigate it, check out their [[homepage|http://tiddlywiki.com/]].  Quick directions below:
----
''SEARCHING FOR DATA:''
#Browse the "Tags" tab in the //right column// for Processing-ish key-words.
**Inside the Tags tab, major ''Categories'' are all in caps, like "[[FUNDAMENTALS]]". 
**When picking a 'Tag' with more than one link, you can either:
###'{{{Open all}}}' the topics in that Tag (meaning, fully expand all the topics listed in the middle of that pop-up menu).
###Open a single topic by picking its heading.
###Show all the headings in the Tag by picking: {{{Open tag 'tagname}}}'.
#Use your web browsers screen-search ability ('Ctrl+F' in both Firefox & Internet Explorer) to find key-words you're after (good if 'Tags' tab is open).
#Or start browsing from the ''Categories'' section in the //left column//.  This will open each of their major headings in a new tiddler.
If things get too crowded, use the "close all" from the //right column// to clean up the page.  Or, you can use "close others" from an individual tiddler (This block called "[[Instructions For Use]]" is a tiddler, for example).
----
''COPYING DATA FROM WIKI, TO PROCESSING:''
*The way the text has been entered into this wiki, copying code from the source-boxes should work:
{{{
source-code in a box; 
}}}
*Other times it's not in a box, but is still safe for copy:
{{{source-code not in a box, but still safe to copy;}}}
*If you copy any code outside of a box that's 'not safe', Processing //may// have a hard time with it's formatting and be angered. Weird>>
Dealing with the mouse is split up into two types of data:  'Special Processing functions', and special [[Processing system variables]] .  The 'special variables' are updated every frame, while the 'special functions' can contain any code you want, their names are reserved by Processing, and are called to based on their descriptions.
Here is a list:
----
''Special functions'':
*[[mousePressed()|http://www.processing.org/reference/mousePressed_.html]] - Executed whenever the user holds a mouse button down.
*[[mouseReleased()|http://www.processing.org/reference/mouseReleased_.html]] - Executed whenever the user releases a mouse button.
*[[mouseClicked()|http://www.processing.org/reference/mouseClicked_.html]] - Executed whenever a user presses, then releases the mouse button (not sure how this is different from {{{mouseReleased()}}}).
*[[mouseDragged()|http://www.processing.org/reference/mouseDragged_.html]] - Executed whenever a mouse button is pressed, and the mouse is moved.
''Special variables:''
*[[mouseButton|http://www.processing.org/reference/mouseButton.html]] - Tracks which mouse button was last pressed:  {{{LEFT}}}, {{{RIGHT}}}, {{{CENTER}}}.
*[[mousePressed|http://www.processing.org/reference/mousePressed.html]] - Tracks per frame if a mouse button is pressed or not. {{{true}}}/{{{false}}}.
*[[mouseX|http://www.processing.org/reference/mouseX.html]] - Contains the //current// horizontal coordinate of the mouse.
*[[mouseY|http://www.processing.org/reference/mouseY.html]] - Contains the //current// vertical coordinate of the mouse.
*[[pmouseX|http://www.processing.org/reference/pmouseX.html]] - Contains the horizontal position of the mouse in the frame //previous// to the current frame.
*[[pmouseY|http://www.processing.org/reference/pmouseY.html]] - Contains the vertical position of the mouse in the frame //previous// to the current frame.
----
Simple example to execute code whenever the mouse is pressed:
{{{
void mousePressed(){
  if(mouseButton == LEFT){
    # do something...
  }
  if(mouseButton == CENTER){
    # do something...
  }
  else if(mouseButton == RIGHT){
    # do something...
  }
}
}}}
----
Great post here:
http://www.creativeapplications.net/processing/kinect-physics-tutorial-for-processing/
Calls on these libs:
*http://code.google.com/p/simple-openni/
*http://hg.postspectacular.com/toxiclibs/downloads/
*http://www.v3ga.net/processing/BlobDetection/index-page-download.html
*https://github.com/shiffman/PBox2D
/***
|''Name:''|LegacyStrikeThroughPlugin|
|''Description:''|Support for legacy (pre 2.1) strike through formatting|
|''Version:''|1.0.2|
|''Date:''|Jul 21, 2006|
|''Source:''|http://www.tiddlywiki.com/#LegacyStrikeThroughPlugin|
|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''License:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.0|
***/

//{{{
// Ensure that the LegacyStrikeThrough Plugin is only installed once.
if(!version.extensions.LegacyStrikeThroughPlugin) {
version.extensions.LegacyStrikeThroughPlugin = {installed:true};

config.formatters.push(
{
	name: "legacyStrikeByChar",
	match: "==",
	termRegExp: /(==)/mg,
	element: "strike",
	handler: config.formatterHelpers.createElementAndWikify
});

} //# end of "install only once"
//}}}
Some comments below the sketch code...
{{{
/*
Eric Pavey
2008-07-12
 
Draws two circles.  Each circle has a line starting from its
border, pointing to the other circle based on the closest points
between the two circles.  
The circles are authored through OOP.  The line is drawn as a 
normal function, simply to split it out of the objects, so it's
easier to visually debug.

Shows examples of:
*  Calculating the closest point on the circumference of a 
circle relative to another circle.
*  Finding the point on the circumference of a circle based
on an angle.

Hold LMB to position c1,  RMB to position c2
*/
 
//---------------------------------------------
// create our two circle objects:
Circle c1 = new Circle();
Circle c2 = new Circle();


//---------------------------------------------
void setup(){
  size(512,512);
}


//---------------------------------------------
void draw(){
  background(128);
  c1.drawCircle();
  c2.drawCircle();
  drawLine();

  // mouse control:
  if(mousePressed){
    if(mouseButton == LEFT){
      c1.setPos(mouseX, mouseY);
    }
    if(mouseButton == RIGHT){
      c2.setPos(mouseX, mouseY);
    }
  }
}


//---------------------------------------------
// Define our circle class:

class Circle{
  float x;
  float y;
  float radius;
  color col;

  Circle(){
    this.radius = 32;
    this.col =  color(random(0,255), random(0,255), random(0,255));
  }

  void drawCircle(){
    fill(col);
    ellipse(x, y, radius*2, radius*2);
  }
  
  float[] getPos(){
    float pos[] = {
      x, y};
    return pos;
  }

  float getRadius(){
    return radius; 
  }

  void setPos(float x, float y){
    this.x = x;
    this.y = y; 
  }
}


//---------------------------------------------
// draw line between circles:

void drawLine(){
  
  // get the xy position of both circles:
  float[] c1Pos = c1.getPos();
  float[] c2Pos = c2.getPos();
  
  // get the vector from c1 to c2:
  float c1VecX = c2Pos[0] - c1Pos[0];
  float c1VecY = c2Pos[1] - c1Pos[1];
  
  // get the vector from c2 to c1:
  float c2VecX = c1Pos[0] - c2Pos[0];
  float c2VecY = c1Pos[1] - c2Pos[1];  
  
  // based on our vectors, generate the angle that points from
  // the center of one circle to the other:
  float c1Angle = (atan2(c1VecX, c1VecY) * -1) + HALF_PI;
  float c2Angle = (atan2(c2VecX, c2VecY) * -1) + HALF_PI;  
  
  // Create the line coordinates that draws from c1 to c2.   
  // The line starts at the radius of c1, and extends out to 
  // 2x the radius:
  float c1CirX = c1Pos[0] + cos(c1Angle)*c1.getRadius();
  float c1CirY = c1Pos[1] + sin(c1Angle)*c1.getRadius();   
  float c1OutX = c1Pos[0] + cos(c1Angle)*(c1.getRadius()*2);
  float c1OutY = c1Pos[1] + sin(c1Angle)*(c1.getRadius()*2);     

  // Create the line coordinates that draws from c1 to c2.   
  // The line starts at the radius of c1, and extends out to 
  // 2x the radius: 
  float c2CirX = c2Pos[0] + cos(c2Angle)*c2.getRadius();
  float c2CirY = c2Pos[1] + sin(c2Angle)*c2.getRadius();   
  float c2OutX = c2Pos[0] + cos(c2Angle)*(c2.getRadius()*2);
  float c2OutY = c2Pos[1] + sin(c2Angle)*(c2.getRadius()*2);    
  
  // finally draw the line:
  stroke(0);
  line(c1CirX, c1CirY, c1OutX, c1OutY);
  line(c2CirX, c2CirY, c2OutX, c2OutY);
}
}}}
When I was searching online on how to figure out the angle of a vector, I tracked down the {{{atan2}}} command.  However, running this example block:
{{{
float c1Angle = atan2(c1VecX, c1VecY) ;
}}}
provided very poor results:  The rotations were opposite, and off by 90 degrees.  Through trial and error, I figured out the final block I used:
{{{
float c1Angle = (atan2(c1VecX, c1VecY) * -1) + HALF_PI;
float c2Angle = (atan2(c2VecX, c2VecY) * -1) + HALF_PI;  
}}}
Which reverses the direction, and adds 90 degs to the angle.  I don't know enough about trig yet to understand if I'm making a mistake in an earlier part of my code, or I simply need to do this.  I'm just happy it works ;)

http://dev.processing.org/source/index.cgi/trunk/processing/core/src/processing/core/PConstants.java?view=markup
Also see:
*[[Processing system variables]]
[[shorten|http://www.processing.org/reference/shorten_.html]]
[[concat|http://www.processing.org/reference/concat_.html]]
[[subset|http://www.processing.org/reference/subset_.html]]
[[append|http://www.processing.org/reference/append_.html]]
[[sort|http://www.processing.org/reference/sort_.html]]
[[arraycopy|http://www.processing.org/reference/arraycopy_.html]]
[[reverse|http://www.processing.org/reference/reverse_.html]]
[[splice|http://www.processing.org/reference/splice_.html]]
[[expand|http://www.processing.org/reference/expand_.html]]
Also see:
*[[Array and String methods]]
[[split|http://www.processing.org/reference/split_.html]]
[[join|http://www.processing.org/reference/join_.html]]
[[splitTokens|http://www.processing.org/reference/splitTokens_.html]]
[[nf|http://www.processing.org/reference/nf_.html]]
[[match|http://www.processing.org/reference/match_.html]]
[[trim|http://www.processing.org/reference/trim_.html]]
[[nfc|http://www.processing.org/reference/nfc_.html]]
[[nfs|http://www.processing.org/reference/nfs_.html]]
[[nfp|http://www.processing.org/reference/nfp_.html]]
Also see:
*[[Array and String methods]]
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
  url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
Ran across a tutorial about building a MIDI 'game of life' sequencer in processing over at [[MAKE: Magazine Blog|http://blog.makezine.com/archive/2008/09/coding_a_game_of_life_seq.html?CMP=OTC-0D6B48984890]]:
*Video documentation:
**http://vimeo.com/1824904?pg=embed&sec=1824904
*Web Site:
**http://ruinwesen.com/support  -> Software -> Java -> ~RWMidi Processing
**http://ruinwesen.com/support-files/rwmidi/documentation/RWMidi.html
>Notes from their site:
>"~RWMidi is a class containing static methods to get a list of the available MIDI devices. You can ask ~RWMidi about available input and output devices. You can then use the methods on the returned objects to open an input or output midi port. ~RWMidi doesn't provide access to the available MIDI devices through an index number, but rather requires you to use the returned ~MidiDevice object. This is because the number of available devices can change between a call to the function listing the device and the call opening the device, which could potentially lead to an index mismatch."
"This is a library for solving real-time fluid dynamics simulations based on ~Navier-Stokes equations and Jos Stam's paper on ~Real-Time Fluid Dynamics for Games. While I wrote the library primarily for processing it has no dependency on processing libraries and the source can be used with any Java application. "
http://memo.tv/msafluid_for_processing
http://memo.tv/files/memotv/msafluid_for_processing/index.html
*[[Welcome]]
*[[About Processing Wiki]]
*[[Instructions for use]]
*[[Latest Updates|History]]
*[[Processing Links]]
*[[Blog]]
*[[About Author|WarpCat]]
----
''Subscribe:''
''[[RSS|http://processingwiki.tiddlyspot.com/index.xml]]'' [img[http://farm1.static.flickr.com/197/492915948_b4a9f3233e.jpg?v=0][http://processingwiki.tiddlyspot.com/index.xml]] 
----
[[All Subjects]]
----
''Categories:''
[[ANDROID]]
[[AUDIO]]
[[COMMUNICATION]]
[[ENVIRONMENT]]
[[EXT REFERENCE]]
[[FILESYSTEMS]]
[[FUNDAMENTALS]]
[[HARDWARE]]
[[INFO]]
[[INTERACTION]]
[[JAVA]]
[[MATH]]
[[I/O]]
[[OOP]]
[[OPENGL]]
[[PHYSICS]]
[[PIXELS]]
[[PLAYBACK]]
[[QUICKSKETCH]]
[[RENDERING]]
[[TRANSFORMATION]]
[[VARIABLES]]
[[UI]]
[[VIDEO]]
http://www.euclideanspace.com/index.html
For all kinds of math

[[Dave's Short Trig Course|http://www.clarku.edu/~djoyce/trig/]]
Recommended to me, for all your trig needs.

Vectors:
http://mathforum.org/~klotz/Vectors/vectors.html
Links:
*http://en.wikipedia.org/wiki/Matrix_%28mathematics%29
Check out stuff on {{{affine transform}}}
From the Processing docs, you can use ''Minim'' to get audio in Processing.
http://code.compartmental.net/tools/minim/

Here are my notes on the subject:
----
[[Quick-start Guide|http://code.compartmental.net/tools/minim/quickstart/]]
For Processing:
*http://ubaa.net/shared/processing/opencv/
Other Links:
*http://www.willowgarage.com/pages/software/opencv
*http://opencv.willowgarage.com/wiki/
Some notes....
----
Thread:
http://processing.org/discourse/yabb2/YaBB.pl?num=1210936403/6#6
From that thread by {{{sgsrules}}}:
{{{
import processing.opengl.*;  
import javax.media.opengl.*; // This is the jogl library you need

PGraphicsOpenGL pgl; // from processing.opengl.*
GL gl;  // from javax.media.opengl.*

void setup(){
  size(600,600,OPENGL);
  hint( ENABLE_OPENGL_4X_SMOOTH); // anti aliasing

  pgl = (PGraphicsOpenGL) g;
  gl = pgl.gl;
}

void draw(){
  background(0);
  // processing code goes here

  pgl.beginGL(); // place before you native gl code
  // gl code does here

  // this translates the different matrices and other stuff so that  
  // you can use gl commands note that most of the processing commands will
  // not work or will behave strangly so don't mix the two.  Gl geometry
  //  will only be lit with gl lights and normals.
  pgl.endGL(); //place after your native gl code, you can place more processing stuff here
}
}}}
Docs on {{{/PGraphicsOpenGL}}}
http://dev.processing.org/reference/everything/javadoc/processing/opengl/PGraphicsOpenGL.html
----
OpenGL blending
From ''Flight 404'':
http://www.flight404.com/blog/?p=71
http://www.flight404.com/blog/?p=72

Processing.org thread:
http://processing.org/discourse/yabb2/YaBB.pl?num=1207671111
Sample sketch:
http://boxofbooze.com/processing/glblend.html
{{{glBlendFunc}}}
http://pyopengl.sourceforge.net/documentation/manual/glBlendFunc.3G.html
----
More additive blending stuff:
http://processing.org/discourse/yabb2/YaBB.pl?num=1226360818
from {{{pelintra}}}
{{{
import processing.opengl.*;
import javax.media.opengl.GL;

PGraphicsOpenGL pgl;
GL gl;

void setup(){
//just put what you would normally put here
}

void draw(){
//here you just add this code:
pgl = (PGraphicsOpenGL)g;
gl = pgl.beginGL(); //getting the GL object used by processing
gl.glEnable(GL.GL_BLEND);  // enabling blend
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE); //defining additive blend
pgl.endGL();

//now everything you draw will be drawn using additive blend
//making glows more glowy! 
}
}}}
http://www.processing.org/reference/PImage.html	
{{{get()}}}  -   	Reads the color of any pixel or grabs a rectangle of pixels
{{{set()}}} 	  -   Writes a color to any pixel or writes an image into another
{{{copy()}}} 	  -   Copies the entire image
{{{mask()}}} 	  -   Masks part of the image from displaying
{{{blend()}}} 	  -   Copies a pixel or rectangle of pixels using different blending modes
{{{filter()}}}   -   	Converts the image to grayscale or black and white
{{{save()}}} 	  -   Saves the image to a TIFF, TARGA, PNG, or JPEG file

You can also access these //fields//:
{{{.width}}}  -  Width of the image
{{{.height}}} - Height of the image
{{{.pixels[]}}} - Array of all pixels in the image.
Source code can be found here below.  It exposes more methods than the Processing docs do.
http://code.google.com/p/processing/source/browse/trunk/processing/core/src/processing/core/PVector.java

Processing docs:
http://processing.org/reference/PVector.html
A Processing library for rendering the class of 3D shapes known as "bicubic patches". 
http://www.mrfeinberg.com/patchy/
http://code.google.com/p/patchy/
I wanted to understand better how {{{noise()}}} worked.  So I wrote this little sketch that will "zoom" in and out of the noise.
{{{
/*
Eric Pavey - 2008-12-20

Code to zoom in\out of Perlin noise based on
mouse Y position.
*/

float noiseScale;

void setup(){
  size(128, 128);
  background(0);
}

void draw() {
  noStroke();
  background(0);
  for(int x=0; x < width; x++) {
    for(int y=0; y<height; y++){
      // normalize the x & y positions between 0-1
      float normX = map(x, 0, width, 0, noiseScale);
      float normY = map(y, 0, height, 0, noiseScale);  
      // find the noise value for that x,y pos:    
      float val = noise(normX, normY);
      // map that value to a color:
      float col = map(val, 0, 1, 0, 255);
      // plot color:
      fill(col);
      ellipse(x,y,1,1); 
    }
  }
  noiseScale = map(mouseY, 0, height, 10, .1);
}
}}}
I was experimenting with particle systems and snowflakes (it is "winter" after all).  I was trying to add a bit of random motion into the flakes motion using the {{{noise()}}} function.  As it turned out, I had a lot of fun just messing with noise, and this was the result.

Find movies on Flickr [[HERE|http://www.flickr.com/photos/warpcat/sets/72157605688360509/]]
{{{
/*
Eric Pavey 2008-12-21
perlinParticle02
Made with Processing v1.01
 
Render particles to screen, with their position being effected by
Perlin noise.
 
Code generates four images each in an off-screen buffer.  They are used
for determining the movement of the particles.  The x position
is determined by 'imageX', the y position is determined by 'imageY',
and the "speed" of the particle is determined by 'imageZ'.  Finally,
those three images are combined to make a composite image, which
is the first image seen when the sketch starts.

Each time you re-start the sketch, it regenerates the random noise.

The background can be changed by clicking the mouse button:
The first BG image is the 'combined' version.
The second BG image is the x influence image.
The third BG image is the y influence image.
The fourth BG image is the 'speed' image.
The fifth is no BG at all (black)
 
For the x & y images:
Black values make partcies go in negative direction.  
White values make particles go in positive directions.
 
For the 'speed' image:
black values make particles slow down, white values make particles
speed up.

Increase the 'noiseFreq' to have a more chaotic effect.
Increase 'noiseAmp' to speed uo particle motion.

If a particle stops moving, or occupies the space of another
particle, it will re-spawn.
*/

//------------------------------
// User vars, feel free to change:

// resolution of the screen (square)
int screenRes = 512;
// number of particles:
int numPerls = 500;
// Frequency of noise:
float noiseFreq = 1.0;
// speed of particles:
float noiseAmp = 5.0;
// controls background transparency.
int fade = 64;

//------------------------------
// System vars, no touch!
PImage imageX; 
PImage imageY; 
PImage imageZ;
PImage bg;
Perl[] perls = new Perl[numPerls];
int drawImage = 0;

//------------------------------
void setup(){
  size(screenRes, screenRes);
  frameRate(30);

  imageX = createImage(width, height, ARGB);
  imageY = createImage(width, height, ARGB);
  imageZ = createImage(width, height, ARGB);
  bg = createImage(width, height, ARGB);

  makePerlin(imageX, noiseFreq);
  makePerlin(imageY, noiseFreq);
  makePerlin(imageZ, noiseFreq);
  makeBackground();

  smooth();
  for(int i=0; i<numPerls; i++){
    perls[i] = new Perl(); 
  }
}

//------------------------------
void draw(){
  if(drawImage == 0){
    image(bg,0,0);
  }
  if(drawImage == 1){
    image(imageX,0,0);
  }  
  if(drawImage == 2){
    image(imageY,0,0);
  }    
  if(drawImage == 3){
    image(imageZ,0,0);
  }   
  if(drawImage == 4){  
    fill(0,fade*.25);
    quad(0,0, width, 0, width, height, 0, height);  
  }
  
  // Run the particles:
  for(int i=0; i<numPerls; i++){
    perls[i].run();
  }  
}

//------------------------------
// make background image by combining our three other images
void makeBackground(){
  for(int x=0; x < width; x++) {
    for(int y=0; y < height; y++){
      color col = color(brightness(imageX.get(int(x), int(y))), 
        brightness(imageY.get(int(x), int(y))),
        brightness(imageZ.get(int(x), int(y))),
        fade);
      bg.set(x, y, col);
    }
  }
}

//-----------------------------
// cycle through our images
void mousePressed() {
  drawImage += 1;
  if(drawImage > 4) {
    drawImage = 0; 
  }
} 

//-----------------------------
// Fill the defined image with noise.

void makePerlin(PImage img, float noiseScale){
  noiseSeed(int(random(0,1000)));
  
  for(int x=0; x < width; x++) {
    for(int y=0; y < height; y++){
      // normalize the x & y positions between 0-1
      float normX = map(x, 0, width, 0, noiseScale);
      float normY = map(y, 0, height, 0, noiseScale);  
      // find the noise value for that x,y pos:    
      float val = noise(normX, normY);
      // map that value to a color:
      int cVal = int(map(val, 0, 1, 0, 255));

      color col = color(cVal,fade);     
      img.set(x,y,col);     
    }
  }  
}


//------------------------------
// Main particle class declaration:

class Perl{

  //------------------------------
  float x, y;
  float lastX, lastY;
  float randX, randY;
  float diameter;
  float c;

  //------------------------------
  Perl(){
    init();
  }

  //------------------------------
  void init(){
    x = random(0, width);
    y = random(0, height);
    lastX = x;
    lastY = y;
    diameter = random(2.0,8.0);
    c=0;
  }

  //------------------------------
  // move the particle through space
  void move(){
    lastY = y;
    lastX = x;   

    rand();

    x = x + randX;
    y = y + randY;
    
    if(y > height){
      y = 0;
      lastY = y;
    }
    else if (y < 0){
      y = height; 
      lastY = y;
    }
    if(x<0){
      x = width;
      lastX = x;
    }
    else if(x > width){
      x = 0; 
      lastX = x;
    }
  }

  //------------------------------
  // Calc the new position of the particle based on noise:
  void rand(){   

    color xCol = imageX.get(int(x), int(y));
    color yCol = imageY.get(int(x), int(y));
    color amtCol = imageZ.get(int(x), int(y)); 

    float xVal = map(brightness(xCol), 0.0, 255.0, -1.0, 1.0);
    float yVal = map(brightness(yCol), 0.0, 255.0, 1.0, -1.0);
    float amtVal = map(brightness(amtCol), 0.0, 255.0, 0, 1.0);  

    randX = (xVal * amtVal * noiseAmp);
    randY = (yVal * amtVal * noiseAmp);
  }

  //------------------------------
  // If a particle has stopped, reset it, or 
  // if this particles position is in the same location as another,
  // re-initialize
  void posCheck(){
    if(abs(x -lastX) < .01 && abs(y -lastY) < .01){
      init();     
    }
    else{
      for(int i=0; i<perls.length; i++){
        // don't interact with itself:
        if(perls[i] != this){   
          float[] otherPos = perls[i].getPos();
          if(abs(otherPos[0] - this.x) < 1 && abs(otherPos[1] - this.y) < 1){
            init(); 
          }
        }
      }
    }
  }

  //------------------------------
  // for external particle access
  float[] getPos(){
    float[] ret = {x, y};
    return ret; 
  }

  //------------------------------
  void render(){
    // increase our alpha over time:
    if (c < 255){
      c+=4; 
    }
    stroke(255, c);
    line(x, y, lastX, lastY);
    strokeWeight(diameter);
    strokeCap(ROUND);

  }

  //------------------------------
  // Put the particle in action
  void run(){
    posCheck();
    move();
    render();
  }

}
}}}
An update to [[PerlinParticles02]].  See notes below.
Movie here on [[Flickr|http://www.flickr.com/photos/warpcat/3129524639/in/set-72157605688360509/]].
{{{
/*
 Eric Pavey 2008-12-22
 perlinParticle03
 Made with Processing v1.01
 
 Render particles to screen, with their position being effected by
 Perlin noise
 
 Update from v2:  In v3, rather than saving three perlin noise images
 to off-screen buffers, this code calculates noise the fly, thus
 allowing the user to also animate time.  However, it runs exponentially 
 slower than v02
 
 Each time you re-start the sketch, it regenerates the random noise.
 
 Increase the 'noiseFreq' to have a more chaotic effect.
 Increase 'noiseAmp' to speed uo particle motion.
 
 If a particle stops moving, or occupies the space of another
 particle, it will re-spawn.
 */

//------------------------------
// User vars:
int screenRes = 512;
int numPerls = 1000;
float noiseFreq = 2;
float noiseAmp = 10;
float timeScale = 10;  
// controls background transparency.
int fade = 64;

//------------------------------
// System vars, no touch!
Pnoise noiseX; 
Pnoise noiseY; 
Pnoise noiseZ; 
Perl[] perls = new Perl[numPerls];

//------------------------------
void setup(){
  size(screenRes, screenRes);
  frameRate(30);
  background(0);
  noiseX = new Pnoise(int(random(0,10000)));
  noiseY = new Pnoise(int(random(0,10000)));
  noiseZ = new Pnoise(int(random(0,10000)));

  smooth();
  for(int i=0; i<numPerls; i++){
    perls[i] = new Perl(); 
  }
}

//------------------------------
void draw(){

  fill(0,fade*.25);
  quad(0,0, width, 0, width, height, 0, height);  

  for(int i=0; i<numPerls; i++){
    perls[i].run();
  }  
}

//------------------------------
class Perl{

  //------------------------------
  float x, y;
  float lastX, lastY;
  float randX, randY;
  float diameter;
  float c;

  //------------------------------
  Perl(){
    init();
  }

  //------------------------------
  void init(){
    x = random(0, width);
    y = random(0, height);
    lastX = x;
    lastY = y;
    diameter = random(2.0,8.0);
    c=0;
  }

  //------------------------------
  void move(){
    lastY = y;
    lastX = x;   

    rand();

    x = x + randX;
    y = y + randY;

    if(y > height){
      y = 0;
      lastY = y;
    }
    else if (y < 0){
      y = height; 
      lastY = y;
    }
    if(x<0){
      x = width;
      lastX = x;
    }
    else if(x > width){
      x = 0; 
      lastX = x;
    }
  }

  //------------------------------
  void rand(){   

    /*
    color xCol = imageX.get(int(x), int(y));
     color yCol = imageY.get(int(x), int(y));
     color amtCol = imageZ.get(int(x), int(y)); 
     
     float xVal = map(brightness(xCol), 0.0, 255.0, -1.0, 1.0);
     float yVal = map(brightness(yCol), 0.0, 255.0, 1.0, -1.0);
     float amtVal = map(brightness(amtCol), 0.0, 255.0, 0, 1.0);  
     */
    float xVal = map(noiseX.getNoise(int(x), int(y)), 0, 1, -1, 1);
    float yVal = map(noiseY.getNoise(int(x), int(y)), 0, 1, 1, -1);
    float amtVal = noiseZ.getNoise(int(x), int(y));

    randX = (xVal * amtVal * noiseAmp);
    randY = (yVal * amtVal * noiseAmp);
  }

  //------------------------------
  // if a particle has stopped, reset it, or 
  // if this particles position is in the same location as another,
  // re-initialize
  void posCheck(){
    if(abs(x -lastX) < .01 && abs(y -lastY) < .01){
      init();     
    }
    else{
      for(int i=0; i<perls.length; i++){
        // don't interact with itself:
        if(perls[i] != this){   
          float[] otherPos = perls[i].getPos();
          if(abs(otherPos[0] - this.x) < 1 && abs(otherPos[1] - this.y) < 1){
            init(); 
          }
        }
      }
    }
  }

  //------------------------------
  float[] getPos(){
    float[] ret = {this.x, this.y};
    return ret; 
  }

  //------------------------------
  void render(){
    // increase our alpha over time:
    if (c < 255){
      c+=4; 
    }
    stroke(255, c);
    line(x, y, lastX, lastY);
    strokeWeight(diameter);
    strokeCap(ROUND);

  }

  //------------------------------
  void run(){
    posCheck();
    move();
    render();
  }

}


//------------------------------
class Pnoise{
  int seed;

  Pnoise(int rSeed){
    seed = rSeed;
  }

  float getNoise(int x, int y){
    noiseSeed(seed);
    float normX = map(x, 0, width, 0, noiseFreq);
    float normY = map(y, 0, height, 0, noiseFreq);    
    float val = noise(normX, normY, frameCount * (timeScale*.001));
    return val;
  }

}
}}}
http://www.cs.princeton.edu/~traer/physics/
And here's an example of it being used for a cloth sim:
http://www.jrc313.com/processing/cloth/
----
code.google.com, "toxilibs":
http://code.google.com/p/toxiclibs/
----
~MSAFluid
http://memo.tv/msafluid_for_processing
http://memo.tv/files/memotv/msafluid_for_processing/index.html
----
~PPHys2D
http://pphys2d.jmcouillard.com/
----
Daniel Shiffman has been working on integrating Box2d into Processing:
http://www.box2d.org/
http://www.shiffman.net/teaching/nature/box2d-processing/
http://code.google.com/p/pbox2d/
----
"Diewald fluid"
https://github.com/diwi/diewald_fluid
http://codeanticode.wordpress.com/2011/08/19/fluid-library-for-processing/
http://prideout.net/blog/?p=58
{{{
/*
Eric Pavey - 2008-06-21
PixelPlot01

Based on the color values of an image, convert them
into x,y,z coordinates, and plot them in 3d space using
OpenGL.
Can use either RGB or HSB color space.
*/

import processing.opengl.*;

//---------------------------------

// USER VARS:
// Display window size:
int winRes = 512;
// color mode to use:  RGB or HSB
String colMode = "HSB";
// Image to sample:
String imgPath = "image05.jpg";
// for performance reasons, downsample the image.  This is
// the new X resolution of the image.  Recomended values
// less than 100:
int resampleResX = 50;

// SYSTEM VARS:
int depth = winRes;
ColorPoint[] points;
PImage srcImg;
PImage img;
int itter = 0;
int resampleResY;

//---------------------------------

void setup(){
  size(winRes, winRes, OPENGL);
  noStroke();
  perspective();
  loop();

  if(colMode == "RGB")
    colorMode(RGB, 100);
  else if(colMode == "HSB")
    colorMode(HSB, 100);  

  // load our image, and then downsample it:
  srcImg = loadImage(imgPath);
  float resRatio = float(resampleResX) / float(srcImg.width);
  resampleResY = int(float(srcImg.height) * resRatio);
  img = srcImg.get(0,0,resampleResX,resampleResY);
  img.copy(srcImg, 0, 0, srcImg.width, srcImg.height, 
                   0, 0, resampleResX, resampleResY);

  // load up our array of points to draw  
  points = new ColorPoint[img.pixels.length];
  for(int i=0;i<img.pixels.length; i++){
    points[i] = new ColorPoint(img.pixels[i]);
  }
}

//---------------------------------

void draw(){
  // show our downsized image in the upper left corner.  This won't
  // work using P3D, only OPENGL
  background(img);
  
  // position transformation matrix to middle of screen
  translate(width/2, height/2, -depth/4);
  
  // start spinning
  rotateY(frameCount*PI/200);
  rotateX(frameCount*PI/200);  
  
  // Start plotting pixels:
  for(int i=0; i<itter; i++)
    points[i].draw();

  if(itter < img.pixels.length)
    itter++;
  else
    println("Finished!");
}

//---------------------------------

class ColorPoint{

  // Properties:

  float xPos;
  float yPos;
  float zPos;  
  color pixCol;

  // Constructor:

  ColorPoint(color pix){
    pixCol = pix;
    // the '-100' is to help center it in the frame
    if(colMode == "RGB"){
      xPos = red(pix)-100;
      yPos = green(pix)-100;
      zPos = green(pix)-100;
    }
    else if(colMode == "HSB"){
      xPos = hue(pix)-100;
      yPos = saturation(pix)-100;
      zPos = brightness(pix)-100;
    }
  }

  // Method:

  void draw(){
    pushMatrix();
    translate(xPos, yPos, zPos);
    fill(pixCol,50);   
    box(winRes/100);
    popMatrix();
  }
}
}}}
''Official:''
*http://www.processing.org/
*http://wiki.processing.org/w/Main_Page
*[[Processing Extended Reference|http://www.processing.org/reference/index_ext.html]]
*[[dev.processing.org|http://dev.processing.org/]]
**[[Core Section|http://dev.processing.org/reference/core/]]
**[[Everything Section|http://dev.processing.org/reference/everything/]]
*[[Processing Forums|http://www.processing.org/discourse/yabb_beta/YaBB.cgi]]
*[[Processing Release Notes|http://www.processing.org/download/revisions.txt]]
----
''Java-specific:'' (Processing is built on Java)
Official:
*[[The Java Tutorials|http://java.sun.com/docs/books/tutorial/index.html]]
**[[Sun's Java page on OOP|http://java.sun.com/docs/books/tutorial/java/concepts/index.html]]
*[[New to Java Programming Center|http://java.sun.com/new2java/]]
*[[Java 2 Platform, Standard Edition, v 1.4.2 API Specification|http://java.sun.com/j2se/1.4.2/docs/api/index.html]] (Java classes for use in Processing)
Other:
*[[Beginning Java|http://www.joegrip.com/java-course.html]] : online tutorial recommended to me at joegrip.com.
----
''Inspiration:''
*[[Flickr|http://www.flickr.com/groups/processing/]] Group.
*[[Ben Fry|http://benfry.com/]]
*[[REAS.com|http://reas.com/]]
*[[Gallery of Computation|http://www.complexification.net/]]
*[[Flight404|http://www.flight404.com/blog/]]
*[[OpenProcessing|http://www.openprocessing.org/]]
*[[Escape Motions|http://www.escapemotions.com/experiments.html]]
*[[HasCanvas|http://hascanvas.com/]]
----
''External Code \ Libraries'':
*[[toxiclibs|http://code.google.com/p/toxiclibs/]]
*[[traer.physics|http://www.cs.princeton.edu/~traer/physics/]]
*[[colorlib|http://code.google.com/p/colorlib/]]
----
''IDE's:''
*[[Eclipse|http://www.eclipse.org/]] : See a tutorial for getting Processing working in Eclipse [[here|http://processing.org/learning/eclipse/]].
*[[Obsessing|http://obsessing.org/]] :  Author Processing in your browser.
*[[Lily Processing|http://blog.lilyapp.org/2008/05/processing_js_1.html]]  :  Visual programming in Processing.
----
''Informative:''
*[[Wikipedia|http://en.wikipedia.org/wiki/Processing_(programming_language)]]
*http://whatfettle.com/2008/05/TiddlyProcessing/ & http://tiddlyprocessing-simon.tiddlyspot.com/   
**Sites with the [[ProcessingjsPlugin]], allowing for Processing execution //in// tiddywiki's.
----
''Recomended Books:''
Processing Specific:
*[[Processing: A Progamming Handbook for Visual Designers and Artists|http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=11251]]
**Downloads for this book can be found [[here|http://www.processing.org/learning/books/]]
*[[Processing: Creative Coding and Computational Art|http://www.friendsofed.com/book.html?isbn=159059617X]]
**Can download the lessons and example chapters there too.
*[[Learning Processing|http://www.learningprocessing.com/]]
**Can download lessons and examples there too.
Java Specific:
*[[The Java Tutorials: A Short Course on the Basics|http://www.amazon.com/gp/product/0321334205/ref=ase_javasoftsunmicroA/]] 4th Edition : Based on the tutorials from [[Suns official site|http://java.sun.com/docs/books/tutorial/index.html]].
*[[Thinking in Java|http://www.amazon.com/exec/obidos/ASIN/0131872486/ref=nosim/bookie09-20]] Fourth edition.  I was recommended this.
**[[Thinking in Java|http://www.mindview.net/Books/TIJ/]] Third edition, free online book (but, published in 2002, so I'm not sure how current it is).
*[[Head First Java|http://www.amazon.com/Head-First-Java-Kathy-Sierra/dp/0596009208/ref=sr_1_1?ie=UTF8&s=books&qid=1242230271&sr=1-1]] 2nd Edition.  I was recommended this.
*[[On to Java|http://www.amazon.com/Java-3rd-Patrick-Henry-Winston/dp/0201725932]] 3rd Edition.  I was recommended this.
----
''Similar to Processing'':
*[[Processing.js|http://processingjs.org/]] :  This is the Processing API re-written in ~JavaScript.
*[[Paper.js|http://paperjs.org/]] : Another ~JavaScript-based graphical web scripting environment.
*[[Kaleido|http://kaleido.media.mit.edu/]] : Wrapper around Processing.
*[[HYPE|http://hype.joshuadavis.com/]] : Flash ([[ActionScript|http://www.actionscript.org/]])
*[[Field|http://openendedgroup.com/field/]] : [[Processing|http://processing.org/]] + [[Jython|http://www.jython.org/]] (Mac only)
*[[Context Free Art|http://www.contextfreeart.org/]]
*[[Structure Synth|http://structuresynth.sourceforge.net/]]
*[[OpenFrameworks|http://www.openframeworks.cc/]] : [[c++|http://en.wikipedia.org/wiki/C%2B%2B]]
*[[Cinder|http://libcinder.org/]] : [[c++|http://en.wikipedia.org/wiki/C%2B%2B]]
*[[pocode|http://www.pocode.org/]] : [[c++|http://en.wikipedia.org/wiki/C%2B%2B]]
*[[Impure|http://www.impure.com/]]
*[[Field|http://openendedgroup.com/field/]] : [[Processing|http://processing.org/]] + [[Jython|http://www.jython.org/]] (Mac only) 
*[[NodeBox|http://nodebox.net]] : Python based, Mac only.  Similar API to Processing.
**[[NodeBox2|http://beta.nodebox.net/]] Python based, Windows or Python.
**[[Nodebox for OpenGL|http://www.cityinabottle.org/nodebox/]]  Python \ pyglet based, API similar to Processing.
A list of system variables, or 'global variables' used in Processing.  There are a few items that aren't officially 'system variables', but they act similarly.

|{{{frameCount}}} | the number of frames displayed since the program started|
|{{{frameRate}}} | the approximate frame rate of the software as it executes|
|{{{focused}}} | Confirms if a Processing program is "focused", meaning that it is active and will accept input from mouse or keyboard|
|{{{height}}} |  the height of the window|
|{{{key}}} | contains the value of the most recent key on the keyboard that was used|
|{{{keyCode}}} | like key, but for non-ASCII keys|
|{{{keyPressed}}} | has a key been pressed?|
|{{{mouseX}}}  |  the current mouse X position|
|{{{mouseY}}}  |  the current mouse Y position|
|{{{pmouseX}}}  | the previous frame's X mouse position|
|{{{pmouseY}}}  |  the previous frame's Y mouse position|
|{{{mouseButton}}} | which mouse button is pressed|
|{{{mousePressed}}} |  	variable storing if a mouse button is pressed|
|{{{online}}} | Confirms if a Processing program is running inside a web browser|
|{{{pixels[]}}} | An array Array containing the values for all the pixels in the display window.  Must call the function {{{loadPixels()}}} first.|
|{{{PI}}} | 180 deg of a circle, or 1 radian.   {{{3.14159265358979323846}}}|
|{{{HALF_PI}}} | 90 deg of a circle, or .5 radians.  {{{1.57079632679489661923}}}|
|{{{TWO_PI}}} |  360 deg of a circle, or 2 radians.  {{{6.28318530717958647693}}}|
|{{{displayWidth}}}, {{{displayHeight}}} | The dimensions of the computer screen.|
|{{{width}}}  |  the width of the window|
Also see:
*[[List of Processing Constants]]
Maya //mel// code to open a commandPort:
{{{
commandPort -name "127.0.0.1:7777";
commandPort -name ":7777";
commandPort -name "7777";
}}}
If I don't run //all three// of those lines, Processing gives me this Exception:
{{{
java.net.ConnectException: Connection refused: connect
}}}
----
Processing code to create a locator in Maya whenever the left mouse button is pressed.  This uses the {{{Client}}} library:
http://processing.org/reference/libraries/net/Client.html
{{{
// Import the Client library:
import processing.net.*; 
Client mayaClient;

void setup(){
  mayaClient = new Client(this, "localhost", 7777); 
}

void draw(){
  // nothing...
}

void mousePressed(){
  if(mouseButton == LEFT){
    float x = mouseX;
    float y = mouseY * -1 + height; // convert to Maya coordinates
    String mel = ("spaceLocator -p "+x+" "+y+" 0;");
    mayaClient.write(mel);
    ellipse(mouseX, mouseY, 4,4);
  }
}
}}}
----
I got tipped off to this code from this blog post:  http://www.jfernsler.com/blog/?p=29
/***
|''Name:''|ProcessingPlugin|
|''Description:''|TiddlyWiki Bundle of John Ressig's processing.js|
|''Date:''|May 9, 2008|
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com)|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/PaulDowney/plugins/ProcessingPlugin.js|
|''Version:''|0.2|
|''License:''|[[MIT license]]|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.2|

With contributions from Simon Baird.

***/

//{{{
// Ensure Plugin is only installed once.
if(!version.extensions.Processingjs) {
version.extensions.Processingjs = {installed:true};

config.macros.Processing = {
	counter: 0,
	handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		var id = "processingcanvas"+this.counter;
		var canvas = createTiddlyElement(place,"canvas",id);

		// inlined code
		var code = paramString;

		// quick and dirty grab of code from a named tiddler
		if (store.tiddlerExists(params[0])) {
			code = store.getTiddlerText(params[0]);
		}

		// or with no params, grab code from this tiddler
		if (paramString.trim() == '') {
			code = tiddler.text;
		}

		createTiddlyElement(place,"br");
		var restartBtn = createTiddlyButton(place,"restart","restart",function() {
				story.refreshTiddler(tiddler.title,null,true);
				return false;
			},
			'processingRestart' // it's a class so you can style the button
		);

		Processing(canvas,code);
	}
};

// requires 2.4
merge(config.macros.view.views,{
	processing: function(value,place,params,wikifier,paramString,tiddler) {
		wikify("<<Processing\n"+value+"\n>>",place,highlightHack,tiddler);
	}
});

/*
 *  inlined copy of Processing.js
 *  latest code at: http://ejohn.org/blog/processingjs/
 */

/*
 * Processing.js - John Resig (http://ejohn.org/)
 * MIT Licensed
 * http://ejohn.org/blog/processingjs/
 *
 * This is a port of the Processing Visualization Language.
 * More information: http://processing.org/
 */

(function(){

this.Processing = function Processing( aElement, aCode )
{
  var p = buildProcessing( aElement );
  p.init( aCode );
  return p;
};

function log()
{
  try
  {
    console.log.apply( console, arguments );
  }
  catch(e)
  {
    try
    {
      opera.postError.apply( opera, arguments );
    }
    catch(e){}
  }
}

function parse( aCode, p )
{
  // Angels weep at this parsing code :-(

  // Remove end-of-line comments
  aCode = aCode.replace(/\/\/ .*\n/g, "\n");

  // Weird parsing errors with %
  aCode = aCode.replace(/([^\s])%([^\s])/g, "$1 % $2");
 
  // Simple convert a function-like thing to function
  aCode = aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function(all, type, name, args)
  {
    if ( name == "if" || name == "for" || name == "while" )
    {
      return all;
    }
    else
    {
      return "Processing." + name + " = function " + name + args;
    }
  });

  // Force .length() to be .length
  aCode = aCode.replace(/\.length\(\)/g, ".length");

  // foo( int foo, float bar )
  aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4");
  aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4");

  // float[] foo = new float[5];
  aCode = aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g, function(all, name, args)
  {
    return "new ArrayList(" + args.slice(1,-1).split("][").join(", ") + ")";
  });
  
  aCode = aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function(all)
  {
    return all.replace(/{/g, "[").replace(/}/g, "]");
  });

  // int|float foo;
  var intFloat = /(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;
  while ( intFloat.test(aCode) )
  {
    aCode = aCode.replace(new RegExp(intFloat), function(all, type, name, sep)
    {
      return type + " " + name + " = 0" + sep;
    });
  }

  // float foo = 5;
  aCode = aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function(all, type, arr, name, sep)
  {
    if ( type == "return" )
      return all;
    else
      return "var " + name + sep;
  });

  // Fix Array[] foo = {...} to [...]
  aCode = aCode.replace(/=\s*{((.|\s)*?)};/g, function(all,data)
  {
    return "= [" + data.replace(/{/g, "[").replace(/}/g, "]") + "]";
  });
  
  // static { ... } blocks
  aCode = aCode.replace(/static\s*{((.|\n)*?)}/g, function(all, init)
  {
    // Convert the static definitons to variable assignments
    //return init.replace(/\((.*?)\)/g, " = $1");
    return init;
  });

  // super() is a reserved word
  aCode = aCode.replace(/super\(/g, "superMethod(");

  var classes = ["int", "float", "boolean", "string"];

  function ClassReplace(all, name, extend, vars, last)
  {
    classes.push( name );

    var static = "";

    vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function(all,set)
    {
      static += " " + name + "." + set;
      return "";
    });

    // Move arguments up from constructor and wrap contents with
    // a with(this), and unwrap constructor
    return "function " + name + "() {with(this){\n  " +
      (extend ? "var __self=this;function superMethod(){extendClass(__self,arguments," + extend + ");}\n" : "") +
      // Replace var foo = 0; with this.foo = 0;
      // and force var foo; to become this.foo = null;
      vars
        .replace(/,\s?/g, ";\n  this.")
        .replace(/\b(var |final |public )+\s*/g, "this.")
        .replace(/this.(\w+);/g, "this.$1 = null;") + 
	(extend ? "extendClass(this, " + extend + ");\n" : "") +
        "<CLASS " + name + " " + static + ">" + (typeof last == "string" ? last : name + "(");
  }

  var matchClasses = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;
  var matchNoCon = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;
  
  aCode = aCode.replace(matchClasses, ClassReplace);
  aCode = aCode.replace(matchNoCon, ClassReplace);

  var matchClass = /<CLASS (\w+) (.*?)>/, m;
  
  while ( (m = aCode.match( matchClass )) )
  {
    var left = RegExp.leftContext,
      allRest = RegExp.rightContext,
      rest = nextBrace(allRest),
      className = m[1],
      staticVars = m[2] || "";
      
    allRest = allRest.slice( rest.length + 1 );

    rest = rest.replace(new RegExp("\\b" + className + "\\(([^\\)]*?)\\)\\s*{", "g"), function(all, args)
    {
      args = args.split(/,\s*?/);
      
      if ( args[0].match(/^\s*$/) )
        args.shift();
      
      var fn = "if ( arguments.length == " + args.length + " ) {\n";
        
      for ( var i = 0; i < args.length; i++ )
      {
        fn += "    var " + args[i] + " = arguments[" + i + "];\n";
      }
        
      return fn;
    });
    
    // Fix class method names
    // this.collide = function() { ... }
    // and add closing } for with(this) ...
    rest = rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function(all, name, args)
    {
      return "ADDMETHOD(this, '" + name + "', function(" + args + ")";
    });
    
    var matchMethod = /ADDMETHOD([\s\S]*?{)/, mc;
    var methods = "";
    
    while ( (mc = rest.match( matchMethod )) )
    {
      var prev = RegExp.leftContext,
        allNext = RegExp.rightContext,
        next = nextBrace(allNext);

      methods += "addMethod" + mc[1] + next + "});"
      
      rest = prev + allNext.slice( next.length + 1 );
      
    }

    rest = methods + rest;
    
    aCode = left + rest + "\n}}" + staticVars + allRest;
  }

  // Do some tidying up, where necessary
  aCode = aCode.replace(/Processing.\w+ = function addMethod/g, "addMethod");
  
  function nextBrace( right )
  {
    var rest = right;
    var position = 0;
    var leftCount = 1, rightCount = 0;
    
    while ( leftCount != rightCount )
    {
      var nextLeft = rest.indexOf("{");
      var nextRight = rest.indexOf("}");
      
      if ( nextLeft < nextRight && nextLeft != -1 )
      {
        leftCount++;
        rest = rest.slice( nextLeft + 1 );
        position += nextLeft + 1;
      }
      else
      {
        rightCount++;
        rest = rest.slice( nextRight + 1 );
        position += nextRight + 1;
      }
    }
    
    return right.slice(0, position - 1);
  }

  // Handle (int) Casting
  aCode = aCode.replace(/\(int\)/g, "0|");

  // Remove Casting
  aCode = aCode.replace(new RegExp("\\((" + classes.join("|") + ")(\\[\\])?\\)", "g"), "");
  
  // Convert 3.0f to just 3.0
  aCode = aCode.replace(/(\d+)f/g, "$1");

  // Force numbers to exist
  //aCode = aCode.replace(/([^.])(\w+)\s*\+=/g, "$1$2 = ($2||0) +");

  // Force characters-as-bytes to work
  aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)");

  // Convert #aaaaaa into color
  aCode = aCode.replace(/#([a-f0-9]{6})/ig, function(m, hex){
    var num = toNumbers(hex);
    return "color(" + num[0] + "," + num[1] + "," + num[2] + ")";
  });

  function toNumbers( str ){
    var ret = [];
     str.replace(/(..)/g, function(str){
      ret.push( parseInt( str, 16 ) );
    });
    return ret;
  }

//log(aCode);

  return aCode;
}

function buildProcessing( curElement ){

  var p = {};

  // init
  p.PI = Math.PI;
  p.TWO_PI = 2 * p.PI;
  p.HALF_PI = p.PI / 2;
  p.P3D = 3;
  p.CORNER = 0;
  p.CENTER = 1;
  p.CENTER_RADIUS = 2;
  p.RADIUS = 2;
  p.POLYGON = 1;
  p.TRIANGLES = 6;
  p.POINTS = 7;
  p.LINES = 8;
  p.TRIANGLE_STRIP = 9;
  p.CORNERS = 10;
  p.CLOSE = true;
  p.RGB = 1;
  p.HSB = 2;

  // "Private" variables used to maintain state
  var curContext = curElement.getContext("2d");
  var doFill = true;
  var doStroke = true;
  var loopStarted = false;
  var hasBackground = false;
  var doLoop = true;
  var curRectMode = p.CORNER;
  var curEllipseMode = p.CENTER;
  var inSetup = false;
  var inDraw = false;
  var curBackground = "rgba(204,204,204,1)";
  var curFrameRate = 1000;
  var curShape = p.POLYGON;
  var curShapeCount = 0;
  var opacityRange = 255;
  var redRange = 255;
  var greenRange = 255;
  var blueRange = 255;
  var pathOpen = false;
  var mousePressed = false;
  var keyPressed = false;
  var firstX, firstY, prevX, prevY;
  var curColorMode = p.RGB;
  var curTint = -1;
  var curTextSize = 12;
  var curTextFont = "Arial";
  var getLoaded = false;
  var start = (new Date).getTime();

  // Global vars for tracking mouse position
  p.pmouseX = 0;
  p.pmouseY = 0;
  p.mouseX = 0;
  p.mouseY = 0;

  // Will be replaced by the user, most likely
  p.mouseDragged = undefined;
  p.mouseMoved = undefined;
  p.mousePressed = undefined;
  p.mouseReleased = undefined;
  p.keyPressed = undefined;
  p.keyReleased = undefined;
  p.draw = undefined;
  p.setup = undefined;

  // The height/width of the canvas
  p.width = curElement.width - 0;
  p.height = curElement.height - 0;
  
  // In case I ever need to do HSV conversion:
  // http://srufaculty.sru.edu/david.dailey/javascript/js/5rml.js
  p.color = function color( aValue1, aValue2, aValue3, aValue4 )
  {
    var aColor = "";
    
    if ( arguments.length == 3 )
    {
      aColor = p.color( aValue1, aValue2, aValue3, opacityRange );
    }
    else if ( arguments.length == 4 )
    {
      var a = aValue4 / opacityRange;
      a = isNaN(a) ? 1 : a;

      if ( curColorMode == p.HSB )
      {
        var rgb = HSBtoRGB(aValue1, aValue2, aValue3);
        var r = rgb[0], g = rgb[1], b = rgb[2];
      }
      else
      {
        var r = getColor(aValue1, redRange);
        var g = getColor(aValue2, greenRange);
        var b = getColor(aValue3, blueRange);
      }

      aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
    }
    else if ( typeof aValue1 == "string" )
    {
      aColor = aValue1;

      if ( arguments.length == 2 )
      {
        var c = aColor.split(",");
	c[3] = (aValue2 / opacityRange) + ")";
	aColor = c.join(",");
      }
    }
    else if ( arguments.length == 2 )
    {
      aColor = p.color( aValue1, aValue1, aValue1, aValue2 );
    }
    else if ( typeof aValue1 == "number" )
    {
      aColor = p.color( aValue1, aValue1, aValue1, opacityRange );
    }
    else
    {
      aColor = p.color( redRange, greenRange, blueRange, opacityRange );
    }

    // HSB conversion function from Mootools, MIT Licensed
    function HSBtoRGB(h, s, b)
    {
      h = (h / redRange) * 100;
      s = (s / greenRange) * 100;
      b = (b / blueRange) * 100;
      if (s == 0){
        return [b, b, b];
      } else {
        var hue = h % 360;
        var f = hue % 60;
        var br = Math.round(b / 100 * 255);
        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 getColor( aValue, range )
    {
      return Math.round(255 * (aValue / range));
    }
    
    return aColor;
  }

  p.nf = function( num, pad )
  {
    var str = "" + num;
    while ( pad - str.length )
      str = "0" + str;
    return str;
  };

  p.AniSprite = function( prefix, frames )
  {
    this.images = [];
    this.pos = 0;

    for ( var i = 0; i < frames; i++ )
    {
      this.images.push( prefix + p.nf( i, ("" + frames).length ) + ".gif" );
    }

    this.display = function( x, y )
    {
      p.image( this.images[ this.pos ], x, y );

      if ( ++this.pos >= frames )
        this.pos = 0;
    };

    this.getWidth = function()
    {
      return getImage(this.images[0]).width;
    };

    this.getHeight = function()
    {
      return getImage(this.images[0]).height;
    };
  };

  function buildImageObject( obj )
  {
    var pixels = obj.data;
    var data = p.createImage( obj.width, obj.height );

    if ( data.__defineGetter__ && data.__lookupGetter__ && !data.__lookupGetter__("pixels") )
    {
      var pixelsDone;
      data.__defineGetter__("pixels", function()
      {
        if ( pixelsDone )
	  return pixelsDone;

	pixelsDone = [];

        for ( var i = 0; i < pixels.length; i += 4 )
        {
          pixelsDone.push( p.color(pixels[i], pixels[i+1], pixels[i+2], pixels[i+3]) );
        }

	return pixelsDone;
      });
    }
    else
    {
      data.pixels = [];

      for ( var i = 0; i < pixels.length; i += 4 )
      {
        data.pixels.push( p.color(pixels[i], pixels[i+1], pixels[i+2], pixels[i+3]) );
      }
    }

    return data;
  }

  p.createImage = function createImage( w, h, mode )
  {
    var data = {
      width: w,
      height: h,
      pixels: new Array( w * h ),
      get: function(x,y)
      {
        return this.pixels[w*y+x];
      },
      _mask: null,
      mask: function(img)
      {
        this._mask = img;
      },
      loadPixels: function()
      {
      },
      updatePixels: function()
      {
      }
    };

    return data;
  }

  p.createGraphics = function createGraphics( w, h )
  {
    var canvas = document.createElement("canvas");
    var ret = buildProcessing( canvas );
    ret.size( w, h );
    ret.canvas = canvas;
    return ret;
  }

  p.beginDraw = function beginDraw()
  {

  }

  p.endDraw = function endDraw()
  {

  }

  p.tint = function tint( rgb, a )
  {
    curTint = a;
  }

  function getImage( img ) {
    if ( typeof img == "string" )
    {
      return document.getElementById(img);
    }

    if ( img.img || img.canvas )
    {
      return img.img || img.canvas;
    }

    img.data = [];

    for ( var i = 0, l = img.pixels.length; i < l; i++ )
    {
      var c = (img.pixels[i] || "rgba(0,0,0,1)").slice(5,-1).split(",");
      img.data.push( parseInt(c[0]), parseInt(c[1]), parseInt(c[2]), parseFloat(c[3]) * 100 );
    }

    var canvas = document.createElement("canvas")
    canvas.width = img.width;
    canvas.height = img.height;
    var context = canvas.getContext("2d");
    context.putImageData( img, 0, 0 );

    img.canvas = canvas;

    return canvas;
  }

  p.image = function image( img, x, y, w, h )
  {
    x = x || 0;
    y = y || 0;

    var obj = getImage(img);

    if ( curTint >= 0 )
    {
      var oldAlpha = curContext.globalAlpha;
      curContext.globalAlpha = curTint / opacityRange;
    }

    if ( arguments.length == 3 )
    {
      curContext.drawImage( obj, x, y );
    }
    else
    {
      curContext.drawImage( obj, x, y, w, h );
    }

    if ( curTint >= 0 )
    {
      curContext.globalAlpha = oldAlpha;
    }

    if ( img._mask )
    {
      var oldComposite = curContext.globalCompositeOperation;
      curContext.globalCompositeOperation = "darker";
      p.image( img._mask, x, y );
      curContext.globalCompositeOperation = oldComposite;
    }
  }

  p.exit = function exit()
  {

  }

  p.save = function save( file )
  {

  }

  p.loadImage = function loadImage( file )
  {
    var img = document.getElementById(file);
    if ( !img )
      return;

    var h = img.height, w = img.width;

    var canvas = document.createElement("canvas");
    canvas.width = w;
    canvas.height = h;
    var context = canvas.getContext("2d");

    context.drawImage( img, 0, 0 );
    var data = buildImageObject( context.getImageData( 0, 0, w, h ) );
    data.img = img;
    return data;
  }

  p.loadFont = function loadFont( name )
  {
    return {
      name: name,
      width: function( str )
      {
        if ( curContext.mozMeasureText )
          return curContext.mozMeasureText( typeof str == "number" ?
            String.fromCharCode( str ) :
            str) / curTextSize;
	else
	  return 0;
      }
    };
  }

  p.textFont = function textFont( name, size )
  {
    curTextFont = name;
    p.textSize( size );
  }

  p.textSize = function textSize( size )
  {
    if ( size )
    {
      curTextSize = size;
    }
  }

  p.textAlign = function textAlign()
  {

  }

  p.text = function text( str, x, y )
  {
    if ( str && curContext.mozDrawText )
    {
      curContext.save();
      curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
      curContext.translate(x, y);
      curContext.mozDrawText( typeof str == "number" ?
        String.fromCharCode( str ) :
	str );
      curContext.restore();
    }
  }

  p.char = function char( key )
  {
    //return String.fromCharCode( key );
    return key;
  }

  p.println = function println()
  {

  }

  p.map = function map( value, istart, istop, ostart, ostop )
  {
    return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
  };

  String.prototype.replaceAll = function(re, replace)
  {
    return this.replace(new RegExp(re, "g"), replace);
  };

  p.Point = function Point( x, y )
  {
    this.x = x;
    this.y = y;
    this.copy = function()
    {
      return new Point( x, y );
    }
  }

  p.Random = function()
  {
    var haveNextNextGaussian = false;
    var nextNextGaussian;

    this.nextGaussian = function()
    {
      if (haveNextNextGaussian) {
        haveNextNextGaussian = false;

        return nextNextGaussian;
      } else {
        var v1, v2, s;
        do { 
          v1 = 2 * p.random(1) - 1;   // between -1.0 and 1.0
          v2 = 2 * p.random(1) - 1;   // between -1.0 and 1.0
          s = v1 * v1 + v2 * v2;
        } while (s >= 1 || s == 0);
        var multiplier = Math.sqrt(-2 * Math.log(s)/s);
        nextNextGaussian = v2 * multiplier;
        haveNextNextGaussian = true;

        return v1 * multiplier;
      }
    };
  }

  p.ArrayList = function ArrayList( size, size2, size3 )
  {
    var array = new Array( 0 | size );
    
    if ( size2 )
    {
      for ( var i = 0; i < size; i++ )
      {
        array[i] = [];

        for ( var j = 0; j < size2; j++ )
        {
	  var a = array[i][j] = size3 ? new Array( size3 ) : 0;
	  for ( var k = 0; k < size3; k++ )
	  {
	    a[k] = 0;
	  }
        }
      }
    }
    else
    {
      for ( var i = 0; i < size; i++ )
      {
        array[i] = 0;
      }
    }
    
    array.size = function()
    {
      return this.length;
    };
    array.get = function( i )
    {
      return this[ i ];
    };
    array.remove = function( i )
    {
      return this.splice( i, 1 );
    };
    array.add = function( item )
    {
      for ( var i = 0; this[ i ] != undefined; i++ ) {}
      this[ i ] = item;
    };
    array.clone = function()
    {
      var a = new ArrayList( size );
      for ( var i = 0; i < size; i++ )
      {
        a[ i ] = this[ i ];
      }
      return a;
    };
    array.isEmpty = function()
    {
      return !this.length;
    };
    array.clear = function()
    {
      this.length = 0;
    };
    
    return array;
  }
  
  p.colorMode = function colorMode( mode, range1, range2, range3, range4 )
  {
    curColorMode = mode;

    if ( arguments.length >= 4 )
    {
      redRange = range1;
      greenRange = range2;
      blueRange = range3;
    }

    if ( arguments.length == 5 )
    {
      opacityRange = range4;
    }

    if ( arguments.length == 2 )
    {
      p.colorMode( mode, range1, range1, range1, range1 );
    }
  }
  
  p.beginShape = function beginShape( type )
  {
    curShape = type;
    curShapeCount = 0; 
  }
  
  p.endShape = function endShape( close )
  {
    if ( curShapeCount != 0 )
    {
      curContext.lineTo( firstX, firstY );

      if ( doFill )
        curContext.fill();
        
      if ( doStroke )
        curContext.stroke();
    
      curContext.closePath();
      curShapeCount = 0;
      pathOpen = false;
    }

    if ( pathOpen )
    {
      curContext.closePath();
    }
  }
  
  p.vertex = function vertex( x, y, x2, y2, x3, y3 )
  {
    if ( curShapeCount == 0 && curShape != p.POINTS )
    {
      pathOpen = true;
      curContext.beginPath();
      curContext.moveTo( x, y );
    }
    else
    {
      if ( curShape == p.POINTS )
      {
        p.point( x, y );
      }
      else if ( arguments.length == 2 )
      {
        if ( curShape == p.TRIANGLE_STRIP && curShapeCount == 2 )
	{
          curContext.moveTo( prevX, prevY );
          curContext.lineTo( firstX, firstY );
	}

        curContext.lineTo( x, y );
      }
      else if ( arguments.length == 4 )
      {
        if ( curShapeCount > 1 )
        {
	  curContext.moveTo( prevX, prevY );
          curContext.quadraticCurveTo( firstX, firstY, x, y );
	  curShapeCount = 1;
        }
      }
      else if ( arguments.length == 6 )
      {
        curContext.bezierCurveTo( x, y, x2, y2, x3, y3 );
        curShapeCount = -1;
      }
    }

    prevX = firstX;
    prevY = firstY;
    firstX = x;
    firstY = y;

    
    curShapeCount++;
    
    if ( curShape == p.LINES && curShapeCount == 2 ||
         (curShape == p.TRIANGLES || curShape == p.TRIANGLE_STRIP) && curShapeCount == 3 )
    {
      p.endShape();
    }

    if ( curShape == p.TRIANGLE_STRIP && curShapeCount == 3 )
    {
      curShapeCount = 2;
    }
  }

  p.curveTightness = function()
  {

  }

  // Unimplmented - not really possible with the Canvas API
  p.curveVertex = function( x, y, x2, y2 )
  {
    p.vertex( x, y, x2, y2 );
  }

  p.bezierVertex = p.vertex
  
  p.rectMode = function rectMode( aRectMode )
  {
    curRectMode = aRectMode;
  }

  p.imageMode = function()
  {

  }
  
  p.ellipseMode = function ellipseMode( aEllipseMode )
  {
    curEllipseMode = aEllipseMode;
  }
  
  p.dist = function dist( x1, y1, x2, y2 )
  {
    return Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
  }

  p.year = function year()
  {
    return (new Date).getYear() + 1900;
  }

  p.month = function month()
  {
    return (new Date).getMonth();
  }

  p.day = function day()
  {
    return (new Date).getDay();
  }

  p.hour = function hour()
  {
    return (new Date).getHours();
  }

  p.minute = function minute()
  {
    return (new Date).getMinutes();
  }

  p.second = function second()
  {
    return (new Date).getSeconds();
  }

  p.millis = function millis()
  {
    return (new Date).getTime() - start;
  }
  
  p.ortho = function ortho()
  {
  
  }
  
  p.translate = function translate( x, y )
  {
    curContext.translate( x, y );
  }
  
  p.scale = function scale( x, y )
  {
    curContext.scale( x, y || x );
  }
  
  p.rotate = function rotate( aAngle )
  {
    curContext.rotate( aAngle );
  }
  
  p.pushMatrix = function pushMatrix()
  {
    curContext.save();
  }
  
  p.popMatrix = function popMatrix()
  {
    curContext.restore();
  }
  
  p.redraw = function redraw()
  {
    if ( hasBackground )
    {
      p.background();
    }
    
    inDraw = true;
    p.pushMatrix();
    p.draw();
    p.popMatrix();
    inDraw = false;
  }
  
  p.loop = function loop()
  {
    if ( loopStarted )
      return;
    
    var looping = setInterval(function()
    {
      try
      {
        p.redraw();
      }
      catch(e)
      {
        clearInterval( looping );
        throw e;
      }
    }, 1000 / curFrameRate );
    
    loopStarted = true;
  }
  
  p.frameRate = function frameRate( aRate )
  {
    curFrameRate = aRate;
  }
  
  p.background = function background( img )
  {
    if ( arguments.length )
    {
      if ( img && img.img )
      {
        curBackground = img;
      }
      else
      {
        curBackground = p.color.apply( this, arguments );
      }
    }
    

    if ( curBackground.img )
    {
      p.image( curBackground, 0, 0 );
    }
    else
    {
      var oldFill = curContext.fillStyle;
      curContext.fillStyle = curBackground + "";
      curContext.fillRect( 0, 0, p.width, p.height );
      curContext.fillStyle = oldFill;
    }
  }

  p.sq = function sq( aNumber )
  {
    return aNumber * aNumber;
  }

  p.sqrt = function sqrt( aNumber )
  {
    return Math.sqrt( aNumber );
  }
  
  p.int = function int( aNumber )
  {
    return Math.floor( aNumber );
  }

  p.min = function min( aNumber, aNumber2 )
  {
    return Math.min( aNumber, aNumber2 );
  }

  p.max = function max( aNumber, aNumber2 )
  {
    return Math.max( aNumber, aNumber2 );
  }

  p.ceil = function ceil( aNumber )
  {
    return Math.ceil( aNumber );
  }

  p.floor = function floor( aNumber )
  {
    return Math.floor( aNumber );
  }

  p.float = function float( aNumber )
  {
    return typeof aNumber == "string" ?
	p.float( aNumber.charCodeAt(0) ) :
        parseFloat( aNumber );
  }

  p.byte = function byte( aNumber )
  {
    return aNumber || 0;
  }
  
  p.random = function random( aMin, aMax )
  {
    return arguments.length == 2 ?
      aMin + (Math.random() * (aMax - aMin)) :
      Math.random() * aMin;
  }

  // From: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
  p.noise = function( x, y, z )
  {
    return arguments.length >= 2 ?
      PerlinNoise_2D( x, y ) :
      PerlinNoise_2D( x, x );
  }

  function Noise(x, y)
  {
    var n = x + y * 57;
    n = (n<<13) ^ n;
    return Math.abs(1.0 - (((n * ((n * n * 15731) + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0));
  }

  function SmoothedNoise(x, y)
  {
    var corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
    var sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8;
    var center  =  Noise(x, y) / 4;
    return corners + sides + center;
  }

  function InterpolatedNoise(x, y)
  {
    var integer_X    = Math.floor(x);
    var fractional_X = x - integer_X;

    var integer_Y    = Math.floor(y);
    var fractional_Y = y - integer_Y;

    var v1 = SmoothedNoise(integer_X,     integer_Y);
    var v2 = SmoothedNoise(integer_X + 1, integer_Y);
    var v3 = SmoothedNoise(integer_X,     integer_Y + 1);
    var v4 = SmoothedNoise(integer_X + 1, integer_Y + 1);

    var i1 = Interpolate(v1 , v2 , fractional_X);
    var i2 = Interpolate(v3 , v4 , fractional_X);

    return Interpolate(i1 , i2 , fractional_Y);
  }

  function PerlinNoise_2D(x, y)
  {
      var total = 0;
      var p = 0.25;
      var n = 3;

      for ( var i = 0; i <= n; i++ )
      {
          var frequency = Math.pow(2, i);
          var amplitude = Math.pow(p, i);

          total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
      }

      return total;
  }

  function Interpolate(a, b, x)
  {
    var ft = x * p.PI;
    var f = (1 - p.cos(ft)) * .5;
    return  a*(1-f) + b*f;
  }

  p.red = function( aColor )
  {
    return parseInt(aColor.slice(5));
  }

  p.green = function( aColor )
  {
    return parseInt(aColor.split(",")[1]);
  }

  p.blue = function( aColor )
  {
    return parseInt(aColor.split(",")[2]);
  }

  p.alpha = function( aColor )
  {
    return parseInt(aColor.split(",")[3]);
  }

  p.abs = function abs( aNumber )
  {
    return Math.abs( aNumber );
  }
  
  p.cos = function cos( aNumber )
  {
    return Math.cos( aNumber );
  }
  
  p.sin = function sin( aNumber )
  {
    return Math.sin( aNumber );
  }
  
  p.pow = function pow( aNumber, aExponent )
  {
    return Math.pow( aNumber, aExponent );
  }
  
  p.constrain = function constrain( aNumber, aMin, aMax )
  {
    return Math.min( Math.max( aNumber, aMin ), aMax );
  }
  
  p.sqrt = function sqrt( aNumber )
  {
  	return Math.sqrt( aNumber );
  }
  
  p.atan2 = function atan2( aNumber, aNumber2 )
  {
  	return Math.atan2( aNumber, aNumber2 );
  }
  
  p.radians = function radians( aAngle )
  {
    return ( aAngle / 180 ) * p.PI;
  }
  
  p.size = function size( aWidth, aHeight )
  {
    var fillStyle = curContext.fillStyle;
    var strokeStyle = curContext.strokeStyle;

    curElement.width = p.width = aWidth;
    curElement.height = p.height = aHeight;

    curContext.fillStyle = fillStyle;
    curContext.strokeStyle = strokeStyle;
  }
  
  p.noStroke = function noStroke()
  {
    doStroke = false;
  }
  
  p.noFill = function noFill()
  {
    doFill = false;
  }
  
  p.smooth = function smooth()
  {
  
  }
  
  p.noLoop = function noLoop()
  {
    doLoop = false;
  }
  
  p.fill = function fill()
  {
    doFill = true;
    curContext.fillStyle = p.color.apply( this, arguments );
  }
  
  p.stroke = function stroke()
  {
    doStroke = true;
    curContext.strokeStyle = p.color.apply( this, arguments );
  }

  p.strokeWeight = function strokeWeight( w )
  {
    curContext.lineWidth = w;
  }
  
  p.point = function point( x, y )
  {
    var oldFill = curContext.fillStyle;
    curContext.fillStyle = curContext.strokeStyle;
    curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
    curContext.fillStyle = oldFill;
  }

  p.get = function get( x, y )
  {
    if ( arguments.length == 0 )
    {
      var c = p.createGraphics( p.width, p.height );
      c.image( curContext, 0, 0 );
      return c;
    }

    if ( !getLoaded )
    {
      getLoaded = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) );
    }

    return getLoaded.get( x, y );
  }

  p.set = function set( x, y, color )
  {
    var oldFill = curContext.fillStyle;
    curContext.fillStyle = color;
    curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
    curContext.fillStyle = oldFill;
  }
  
  p.arc = function arc( x, y, width, height, start, stop )
  {
    if ( width <= 0 )
      return;

    if ( curEllipseMode == p.CORNER )
    {
      x += width / 2;
      y += height / 2;
    }

    curContext.beginPath();
  
    curContext.moveTo( x, y );
    curContext.arc( x, y, curEllipseMode == p.CENTER_RADIUS ? width : width/2, start, stop, false );
    
    if ( doFill )
      curContext.fill();
      
    if ( doStroke )
      curContext.stroke();
    
    curContext.closePath();
  }
  
  p.line = function line( x1, y1, x2, y2 )
  {
    curContext.lineCap = "round";
    curContext.beginPath();
  
    curContext.moveTo( x1 || 0, y1 || 0 );
    curContext.lineTo( x2 || 0, y2 || 0 );
    
    curContext.stroke();
    
    curContext.closePath();
  }

  p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 )
  {
    curContext.lineCap = "butt";
    curContext.beginPath();
  
    curContext.moveTo( x1, y1 );
    curContext.bezierCurveTo( x2, y2, x3, y3, x4, y4 );
    
    curContext.stroke();
    
    curContext.closePath();
  }

  p.triangle = function triangle( x1, y1, x2, y2, x3, y3 )
  {
    p.beginShape();
    p.vertex( x1, y1 );
    p.vertex( x2, y2 );
    p.vertex( x3, y3 );
    p.endShape();
  }

  p.quad = function quad( x1, y1, x2, y2, x3, y3, x4, y4 )
  {
    p.beginShape();
    p.vertex( x1, y1 );
    p.vertex( x2, y2 );
    p.vertex( x3, y3 );
    p.vertex( x4, y4 );
    p.endShape();
  }
  
  p.rect = function rect( x, y, width, height )
  {
    if ( width == 0 && height == 0 )
      return;

    curContext.beginPath();
    
    var offsetStart = 0;
    var offsetEnd = 0;

    if ( curRectMode == p.CORNERS )
    {
      width -= x;
      height -= y;
    }
    
    if ( curRectMode == p.RADIUS )
    {
      width *= 2;
      height *= 2;
    }
    
    if ( curRectMode == p.CENTER || curRectMode == p.RADIUS )
    {
      x -= width / 2;
      y -= height / 2;
    }
  
    curContext.rect(
      Math.round( x ) - offsetStart,
      Math.round( y ) - offsetStart,
      Math.round( width ) + offsetEnd,
      Math.round( height ) + offsetEnd
    );
      
    if ( doFill )
      curContext.fill();
      
    if ( doStroke )
      curContext.stroke();
    
    curContext.closePath();
  }
  
  p.ellipse = function ellipse( x, y, width, height )
  {
    x = x || 0;
    y = y || 0;

    if ( width <= 0 && height <= 0 )
      return;

    curContext.beginPath();
    
    if ( curEllipseMode == p.RADIUS )
    {
      width *= 2;
      height *= 2;
    }
    
    var offsetStart = 0;
    
    // Shortcut for drawing a circle
    if ( width == height )
      curContext.arc( x - offsetStart, y - offsetStart, width / 2, 0, Math.PI * 2, false );
  
    if ( doFill )
      curContext.fill();
      
    if ( doStroke )
      curContext.stroke();
    
    curContext.closePath();
  }

  p.link = function( href, target )
  {
    window.location = href;
  }

  p.loadPixels = function()
  {
    p.pixels = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ).pixels;
  }

  p.updatePixels = function()
  {
    var colors = /(\d+),(\d+),(\d+),(\d+)/;
    var pixels = {};
    var data = pixels.data = [];
    pixels.width = p.width;
    pixels.height = p.height;

    var pos = 0;

    for ( var i = 0, l = p.pixels.length; i < l; i++ ) {
      var c = (p.pixels[i] || "rgba(0,0,0,1)").match(colors);
      data[pos] = parseInt(c[1]);
      data[pos+1] = parseInt(c[2]);
      data[pos+2] = parseInt(c[3]);
      data[pos+3] = parseFloat(c[4]) * 100;
      pos += 4;
    }

    curContext.putImageData(pixels, 0, 0);
  }

  p.extendClass = function extendClass( obj, args, fn )
  {
    if ( arguments.length == 3 )
    {
      fn.apply( obj, args );
    }
    else
    {
      args.call( obj );
    }
  }

  p.addMethod = function addMethod( object, name, fn )
  {
    if ( object[ name ] )
    {
      var args = fn.length;
      
      var oldfn = object[ name ];
      object[ name ] = function()
      {
        if ( arguments.length == args )
          return fn.apply( this, arguments );
        else
          return oldfn.apply( this, arguments );
      };
    }
    else
    {
      object[ name ] = fn;
    }
  }

  p.init = function init(code){
    p.stroke( 0 );
    p.fill( 255 );
  
    // Canvas has trouble rendering single pixel stuff on whole-pixel
    // counts, so we slightly offset it (this is super lame).
    curContext.translate( 0.5, 0.5 );

    if ( code )
    {
      (function(Processing){with (p){
        eval(parse(code, p));
      }})(p);
    }
  
    if ( p.setup )
    {
      inSetup = true;
      p.setup();
    }
    
    inSetup = false;
    
    if ( p.draw )
    {
      if ( !doLoop )
      {
        p.redraw();
      }
      else
      {
        p.loop();
      }
    }
    
    attach( curElement, "mousemove", function(e)
    {
      p.pmouseX = p.mouseX;
      p.pmouseY = p.mouseY;
      p.mouseX = e.clientX - curElement.offsetLeft;
      p.mouseY = e.clientY - curElement.offsetTop;

      if ( p.mouseMoved )
      {
        p.mouseMoved();
      }      

      if ( mousePressed && p.mouseDragged )
      {
        p.mouseDragged();
      }      
    });
    
    attach( curElement, "mousedown", function(e)
    {
      mousePressed = true;

      if ( typeof p.mousePressed == "function" )
      {
        p.mousePressed();
      }
      else
      {
        p.mousePressed = true;
      }
    });
      
    attach( curElement, "mouseup", function(e)
    {
      mousePressed = false;

      if ( typeof p.mousePressed != "function" )
      {
        p.mousePressed = false;
      }

      if ( p.mouseReleased )
      {
        p.mouseReleased();
      }
    });

    attach( document, "keydown", function(e)
    {
      keyPressed = true;

      p.key = e.keyCode + 32;

      if ( e.shiftKey )
      {
        p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt(0);
      }

      if ( typeof p.keyPressed == "function" )
      {
        p.keyPressed();
      }
      else
      {
        p.keyPressed = true;
      }
    });

    attach( document, "keyup", function(e)
    {
      keyPressed = false;

      if ( typeof p.keyPressed != "function" )
      {
        p.keyPressed = false;
      }

      if ( p.keyReleased )
      {
        p.keyReleased();
      }
    });

    function attach(elem, type, fn)
    {
      if ( elem.addEventListener )
        elem.addEventListener( type, fn, false );
      else
        elem.attachEvent( "on" + type, fn );
    }
  };

  return p;
}


})();


} //# end of "install only once"
//}}}
{{{
import java.util.Calendar;
import java.text.SimpleDateFormat;

void setup(){
}

void run(){
  println("Java Time:       " + getJavaDateTime());
  println("Processing Time: " + getProcessingDateTime());
  noLoop();
}

String getJavaDateTime(){
  // Changing the number of repeated charcters will change
  // how many leading zeroes pad single digit numbers:
  String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
  Calendar cal = Calendar.getInstance();
  SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
  return sdf.format(cal.getTime());
}

String getProcessingDateTime(){
  return (year()+"-"+month()+"-"+day()+" "+hour()+":"+minute()+":"+second());
}
}}}
prints:
{{{
Java Time:       2011-08-03 09:53:30
Processing Time: 2011-8-3 9:53:30
}}}
As you can see from the Java method, you have a bit more control over padding the values with zeroes, if you want.

I got the Java code from this link:
http://www.rgagnon.com/javadetails/java-0106.html
I always seem to forget how to properly read more complex serial streams, so... note time:
http://processing.org/reference/libraries/serial/Serial_readStringUntil_.html
{{{
/* Original example by Tom Igoe
Modified by Eric Pavey 2011-08-08

In this example, the serial stream is broken up by
line-feed characters, so we can use Serial.readStringUtil
to capture the stream until one of those chars. Furthermore,
(inthis example) the resultant stream (as being sent from my
Arduino) is made up of two values separated by a space, so 
we further chop it up for printing purposes.
*/

import processing.serial.*;

int lf = 10;    // Linefeed in ASCII
String myString = null;
Serial myPort;  // The serial port

void setup() {
  // List all the available serial ports
  println(Serial.list());
  // I know that the first port in the serial list on my mac
  // is always my  Keyspan adaptor, so I open Serial.list()[0].
  // Open whatever port is the one you're using.
  myPort = new Serial(this, Serial.list()[0], 9600);
  myPort.clear();
  // Throw out the first reading, in case we started reading 
  // in the middle of a string from the sender.
  myString = myPort.readStringUntil(lf);
  myString = null;
}

void draw() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil(lf);
    if (myString != null) {
      // trim off the line-feed char, then split by spaces:
      String[] data = split(trim(myString), " ");
      println("Degrees: " + data[0] + " - Distance: " + data[1] + " cm");
    }
  }
}
}}}
prints out stuff like:
{{{
Degrees: 56 - Distance: 255 cm
Degrees: 57 - Distance: 255 cm
Degrees: 58 - Distance: 255 cm
Degrees: 59 - Distance: 255 cm
Degrees: 60 - Distance: 254 cm
}}}
http://www.2dcurves.com/
As of this post,  874 different curves are available, and the math behind them.

http://en.wikipedia.org/wiki/Bezier_curve
Lots of stuff on Bezier curves

Famous Curves Applet Index
http://www-history.mcs.st-and.ac.uk/Java/index.html
Some links!
http://blog.hvidtfeldts.net/index.php/2012/08/reaction-diffusion-systems/
http://wewanttolearn.wordpress.com/2012/09/30/reaction-diffusion-alan-turing/
http://mrob.com/pub/comp/xmorphia/
http://www.karlsims.com/rd.html
This is bult into the iPhone, but how to do on Android?  Not quite as easily ;)

If you're developing processing for Android, it means you've already got the [[Android SDK|http://developer.android.com/sdk/index.html]] installed.  On my Win XP machine, browse here:
{{{
C:\android-sdk-windows\tools\ddms.bat
}}}
This will launch the 'Dalvik Debug Monitor'.
*When it comes up, select your 'device' listed under the 'Name' field.
*Top Menu -> Device -> Screen Capture.
Blam, that's it.
<<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<tiddler TspotSidebar>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
<<tabs txtMainTab  Tags 'All tags' TabTags >>
<<tabs txtMainTab  Dummy Dummy TabDummy Timeline Timeline TabTimeline All 'All tiddlers' TabAll More 'More lists' TabMore>>
http://prideout.net/blog/?p=58
Found that blog post, does a really nice job of covering it.
notes on learning the language...
Processing Wiki
Notes and links on space-filling code

http://www.complexification.net/gallery/machines/boxFitting/
http://www.davebollinger.com/works/boxfit/ 
http://en.wikipedia.org/wiki/Space-filling_curve

keywords:
Peano / Hilbert / Sierpinski / etal curves
*http://conkerjo.wordpress.com/2009/06/13/spatial-hashing-implementation-for-fast-2d-collisions/
/***
|''Name:''|SparklinePlugin|
|''Description:''|Sparklines macro|
***/
//{{{
if(!version.extensions.SparklinePlugin) {
version.extensions.SparklinePlugin = {installed:true};

//--
//-- Sparklines
//--

config.macros.sparkline = {};
config.macros.sparkline.handler = function(place,macroName,params)
{
	var data = [];
	var min = 0;
	var max = 0;
	var v;
	for(var t=0; t<params.length; t++) {
		v = parseInt(params[t]);
		if(v < min)
			min = v;
		if(v > max)
			max = v;
		data.push(v);
	}
	if(data.length < 1)
		return;
	var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
	box.title = data.join(",");
	var w = box.offsetWidth;
	var h = box.offsetHeight;
	box.style.paddingRight = (data.length * 2 - w) + "px";
	box.style.position = "relative";
	for(var d=0; d<data.length; d++) {
		var tick = document.createElement("img");
		tick.border = 0;
		tick.className = "sparktick";
		tick.style.position = "absolute";
		tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
		tick.style.left = d*2 + "px";
		tick.style.width = "2px";
		v = Math.floor(((data[d] - min)/(max-min)) * h);
		tick.style.top = (h-v) + "px";
		tick.style.height = v + "px";
		box.appendChild(tick);
	}
};


}
//}}}
A few things I've picked up along the way...
----
[[PFont|http://www.processing.org/reference/PFont.html]] is the font Class for Processing.  For each different type of font you want loaded in your sketch, you'll need to make a unique {{{PFont}}}.  Personally, putting the type of font in the name makes some sense to me...
{{{
PFont fontArial;
}}}
To actually have text show up though, there are ''two different methods''.  Both appear to be based around bitmapped imagery:  Processing displays fonts using the {{{.vlw}}} font format, which uses images for each letter, rather than defining them through vector data.
----
In the ''first'' method, you can create the bitmapped fonts on the fly.  To do this, you need to use [[createFont|http://www.processing.org/reference/createFont_.html]].  There is an option arg called {{{charset}}} which isn't listed below, which you can specify specifically which characters should be created.  If blank, I can only presume it makes all of them (need to test theory...).
{{{
// Make font of type 'Arial', 32 points in size, and smoothed.
fontArial= createFont("Arial", 32, true); 
}}}
The ''second'' method is to have Processing pre-make the {{{.vlw}}} data.  This is done via the menu option {{{Tools -> Create Font}}}.  This pops up a UI letting you visually see what you're getting yourself into.  When you hit the "OK" button, it saves off the {{{.vlw}}} data in the sketches {{{\data}}} sub-folder, for later retrieval.  I guess the advantage of this is initially the sketch should load faster since the font data is pre-generated, but it may make it hard to package up and send to others, unless you include the font data as well.
Once the font has been saved to disk, you can load it using [[loadFont|http://www.processing.org/reference/loadFont_.html]]:
{{{
// using an example font name saved to disk from the UI...
fontArial= loadFont("ArialMT-32.vlw"); 
}}}
----
Once your fonts are defined, it's time to actually display them.
Since in theory you can have multiple font-types loaded in your sketch (say, 'fontArial', 'fontGeorgia', 'fontFoo', etc), you need to tell Processing //which// once is currently loaded, and active.  You do that with the [[textFont|http://www.processing.org/reference/textFont_.html]] command:
{{{
textFont(fontArial);
}}}
----
Finally, you can actually display the text using the [[text|http://www.processing.org/reference/text_.html]] command.  You can pass in a {{{String}}} to the command, or just enter the text directly:
{{{
text("This is my text!");
}}}
----
Notes on placing text in 3D:
The {{{text}}} command has arguments for placing it in 3D space, via x, y, & z positions.  You can also leave off the position args entirely.  I've found that in 3D, leaving off the args is a bad idea:  Either position the text by explicitly passing in the x, y, & z data, or use the {{{translate}}} command ahead of time.  But, if using {{{translate}}}, be sure to pass in '0, 0, 0' to {{{text}}} as its position.  Leaving those args off seems to make the text disappear.

/***
Contains the stuff you need to use Tiddlyspot
Note you must also have UploadPlugin installed
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'processingwiki';

// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too

// disable autosave in d3
if (window.location.protocol != "file:")
	config.options.chkGTDLazyAutoSave = false;

// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
	SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
	SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
	OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
	DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
	MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}

// create some shadow tiddler content
merge(config.shadowTiddlers,{

'WelcomeToTiddlyspot':[
 "This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
 "<<tiddler TspotControls>>",
 "See also GettingStarted.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),

'TspotControls':[
 "| tiddlyspot password:|<<option pasUploadPassword>>|",
 "| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
 "| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),

'TspotSidebar':[
 "<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n"),

'TspotOptions':[
 "tiddlyspot password:",
 "<<option pasUploadPassword>>",
 ""
].join("\n")

});
//}}}
*[[sketch|Basic Sketch layout]] :  A {{{.pde}}} file saved on disk, traditionally in a directory with the same name.
**[[statement]]
**[[function]] (executed)
**[[function]] (defined)
***[[argument]] (data passed in)
***[[return]] (data passed out)
***[[statement]]
***[[function]] (executed)
**[[class]]
***[[property|class]] (variables)
***[[method|class]] (defined, methods //are// functions)
***[[function]] (executed)
***[[class]] (inherited) 
***[[class]] (executed)
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 30/05/2012 08:26:07 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . |
| 17/09/2012 10:14:37 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . |
| 25/03/2013 16:38:48 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . |
| 13/11/2013 17:41:11 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . | ok |
| 13/11/2013 17:41:20 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . | ok |
| 13/11/2013 17:43:55 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . | ok |
| 13/11/2013 17:48:52 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . |
| 16/11/2013 18:45:30 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . |
| 08/07/2014 17:55:07 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . | failed |
| 08/07/2014 17:55:35 | WarpCat | [[/|http://processingwiki.tiddlyspot.com/]] | [[store.cgi|http://processingwiki.tiddlyspot.com/store.cgi]] | . | [[index.html | http://processingwiki.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");

merge(config.macros.option.types, {
	'pas': {
		elementType: "input",
		valueField: "value",
		eventName: "onkeyup",
		className: "pasOptionInput",
		typeValue: config.macros.option.passwordInputType,
		create: function(place,type,opt,className,desc) {
			// password field
			config.macros.option.genericCreate(place,'pas',opt,className,desc);
			// checkbox linked with this password "save this password on this computer"
			config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);			
			// text savePasswordCheckboxLabel
			place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
		},
		onChange: config.macros.option.genericOnChange
	}
});

merge(config.optionHandlers['chk'], {
	get: function(name) {
		// is there an option linked with this chk ?
		var opt = name.substr(3);
		if (config.options[opt]) 
			saveOptionCookie(opt);
		return config.options[name] ? "true" : "false";
	}
});

merge(config.optionHandlers, {
	'pas': {
 		get: function(name) {
			if (config.options["chk"+name]) {
				return encodeCookie(config.options[name].toString());
			} else {
				return "";
			}
		},
		set: function(name,value) {config.options[name] = decodeCookie(value);}
	}
});

// need to reload options to load passwordOptions
loadOptionsCookie();

/*
if (!config.options['pasPassword'])
	config.options['pasPassword'] = '';

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}

/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.0|
|''Date:''|May 5, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (#3125)|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 0,
	date: new Date("May 5, 2007"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (#3125)'
};

//
// Environment
//

if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false;	// true to activate both in Plugin and UploadService
	
//
// Upload Macro
//

config.macros.upload = {
// default values
	defaultBackupDir: '',	//no backup
	defaultStoreScript: "store.php",
	defaultToFilename: "index.html",
	defaultUploadDir: ".",
	authenticateUser: true	// UploadService Authenticate User
};
	
config.macros.upload.label = {
	promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
	promptParamMacro: "Save and Upload this TiddlyWiki in %0",
	saveLabel: "save to web", 
	saveToDisk: "save to disk",
	uploadLabel: "upload"	
};

config.macros.upload.messages = {
	noStoreUrl: "No store URL in parmeters or options",
	usernameOrPasswordMissing: "Username or password missing"
};

config.macros.upload.handler = function(place,macroName,params) {
	if (readOnly)
		return;
	var label;
	if (document.location.toString().substr(0,4) == "http") 
		label = this.label.saveLabel;
	else
		label = this.label.uploadLabel;
	var prompt;
	if (params[0]) {
		prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0], 
			(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
	} else {
		prompt = this.label.promptOption;
	}
	createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};

config.macros.upload.action = function(params)
{
		// for missing macro parameter set value from options
		var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
		var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
		var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
		var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
		var username = params[4] ? params[4] : config.options.txtUploadUserName;
		var password = config.options.pasUploadPassword; // for security reason no password as macro parameter	
		// for still missing parameter set default value
		if ((!storeUrl) && (document.location.toString().substr(0,4) == "http")) 
			storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
		if (storeUrl.substr(0,4) != "http")
			storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
		if (!toFilename)
			toFilename = bidix.basename(window.location.toString());
		if (!toFilename)
			toFilename = config.macros.upload.defaultToFilename;
		if (!uploadDir)
			uploadDir = config.macros.upload.defaultUploadDir;
		if (!backupDir)
			backupDir = config.macros.upload.defaultBackupDir;
		// report error if still missing
		if (!storeUrl) {
			alert(config.macros.upload.messages.noStoreUrl);
			clearMessage();
			return false;
		}
		if (config.macros.upload.authenticateUser && (!username || !password)) {
			alert(config.macros.upload.messages.usernameOrPasswordMissing);
			clearMessage();
			return false;
		}
		bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password); 
		return false; 
};

config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir) 
{
	if (!storeUrl)
		return null;
		var dest = bidix.dirname(storeUrl);
		if (uploadDir && uploadDir != '.')
			dest = dest + '/' + uploadDir;
		dest = dest + '/' + toFilename;
	return dest;
};

//
// uploadOptions Macro
//

config.macros.uploadOptions = {
	handler: function(place,macroName,params) {
		var wizard = new Wizard();
		wizard.createWizard(place,this.wizardTitle);
		wizard.addStep(this.step1Title,this.step1Html);
		var markList = wizard.getElement("markList");
		var listWrapper = document.createElement("div");
		markList.parentNode.insertBefore(listWrapper,markList);
		wizard.setValue("listWrapper",listWrapper);
		this.refreshOptions(listWrapper,false);
		var uploadCaption;
		if (document.location.toString().substr(0,4) == "http") 
			uploadCaption = config.macros.upload.label.saveLabel;
		else
			uploadCaption = config.macros.upload.label.uploadLabel;
		
		wizard.setButtons([
				{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption, 
					onClick: config.macros.upload.action},
				{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
				
			]);
	},
	refreshOptions: function(listWrapper) {
		var uploadOpts = [
			"txtUploadUserName",
			"pasUploadPassword",
			"txtUploadStoreUrl",
			"txtUploadDir",
			"txtUploadFilename",
			"txtUploadBackupDir",
			"chkUploadLog",
			"txtUploadLogMaxLine",
			]
		var opts = [];
		for(i=0; i<uploadOpts.length; i++) {
			var opt = {};
			opts.push()
			opt.option = "";
			n = uploadOpts[i];
			opt.name = n;
			opt.lowlight = !config.optionsDesc[n];
			opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
			opts.push(opt);
		}
		var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
		for(n=0; n<opts.length; n++) {
			var type = opts[n].name.substr(0,3);
			var h = config.macros.option.types[type];
			if (h && h.create) {
				h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
			}
		}
		
	},
	onCancel: function(e)
	{
		backstage.switchTab(null);
		return false;
	},
	
	wizardTitle: "Upload with options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Cancel",
	cancelButtonPrompt: "Cancel prompt",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
}

//
// upload functions
//

if (!bidix.upload) bidix.upload = {};

if (!bidix.upload.messages) bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to upload backup file",
	rssSaved: "RSS feed uploaded",
	rssFailed: "Failed to upload RSS feed file",
	emptySaved: "Empty template uploaded",
	emptyFailed: "Failed to upload empty template file",
	mainSaved: "Main TiddlyWiki file uploaded",
	mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
	//specific upload
	loadOriginalHttpPostError: "Can't get original file",
	aboutToSaveOnHttpPost: 'About to upload on %0 ...',
	storePhpNotFound: "The store script '%0' was not found."
};

bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
	var callback = function(status,uploadParams,original,url,xhr) {
		if (!status) {
			displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
			return;
		}
		if (bidix.debugMode) 
			alert(original.substr(0,500)+"\n...");
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.upload.uploadRss(uploadParams,original,posDiv);
	};
	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	// save on localdisk ?
	if (document.location.toString().substr(0,4) == "file") {
		var path = document.location.toString();
		var localPath = getLocalPath(path);
		saveChanges();
	}
	// get original
	var uploadParams = Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
	var originalPath = document.location.toString();
	// If url is a directory : add index.html
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + "index.html";
	var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
	var log = new bidix.UploadLog();
	log.startUpload(storeUrl, dest, uploadDir,  backupDir);
	displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
	if (bidix.debugMode) 
		alert("about to execute Http - GET on "+originalPath);
	var r = doHttp("GET",originalPath,null,null,null,null,callback,uploadParams,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

bidix.upload.uploadRss = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
			bidix.upload.uploadMain(params[0],params[1],params[2]);
		} else {
			displayMessage(bidix.upload.messages.rssFailed);			
		}
	};
	// do uploadRss
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
		var rssUploadParams = Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		bidix.upload.httpUpload(rssUploadParams,convertUnicodeToUTF8(generateRss()),callback,Array(uploadParams,original,posDiv));
	} else {
		bidix.upload.uploadMain(uploadParams,original,posDiv);
	}
};

bidix.upload.uploadMain = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		var log = new bidix.UploadLog();
		if(status) {
			// if backupDir specified
			if ((params[3]) && (responseText.indexOf("backupfile:") > -1))  {
				var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
				displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
			}
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
			store.setDirty(false);
			log.endUpload("ok");
		} else {
			alert(bidix.upload.messages.mainFailed);
			displayMessage(bidix.upload.messages.mainFailed);
			log.endUpload("failed");			
		}
	};
	// do uploadMain
	var revised = bidix.upload.updateOriginal(original,posDiv);
	bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};

bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
	var localCallback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (xhr.status == httpStatus.NotFound)
			alert(bidix.upload.messages.storePhpNotFound.format([url]));
		if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
			alert(responseText);
			if (responseText.indexOf("Debug mode") >= 0 )
				responseText = responseText.substring(responseText.indexOf("\n\n")+2);
		} else if (responseText.charAt(0) != '0') 
			alert(responseText);
		if (responseText.charAt(0) != '0')
			status = null;
		callback(status,params,responseText,url,xhr);
	};
	// do httpUpload
	var boundary = "---------------------------"+"AaB03x";	
	var uploadFormName = "UploadPlugin";
	// compose headers data
	var sheader = "";
	sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
	sheader += uploadFormName +"\"\r\n\r\n";
	sheader += "backupDir="+uploadParams[3] +
				";user=" + uploadParams[4] +
				";password=" + uploadParams[5] +
				";uploaddir=" + uploadParams[2];
	if (bidix.debugMode)
		sheader += ";debug=1";
	sheader += ";;\r\n"; 
	sheader += "\r\n" + "--" + boundary + "\r\n";
	sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
	sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
	sheader += "Content-Length: " + data.length + "\r\n\r\n";
	// compose trailer data
	var strailer = new String();
	strailer = "\r\n--" + boundary + "--\r\n";
	data = sheader + data + strailer;
	if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
	var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
	if (!posDiv)
		posDiv = locateStoreArea(original);
	if((posDiv[0] == -1) || (posDiv[1] == -1)) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				store.allTiddlersAsHtml() + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = getPageTitle().htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
};

//
// UploadLog
// 
// config.options.chkUploadLog :
//		false : no logging
//		true : logging
// config.options.txtUploadLogMaxLine :
//		-1 : no limit
//      0 :  no Log lines but UploadLog is still in place
//		n :  the last n lines are only kept
//		NaN : no limit (-1)

bidix.UploadLog = function() {
	if (!config.options.chkUploadLog) 
		return; // this.tiddler = null
	this.tiddler = store.getTiddler("UploadLog");
	if (!this.tiddler) {
		this.tiddler = new Tiddler();
		this.tiddler.title = "UploadLog";
		this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
		this.tiddler.created = new Date();
		this.tiddler.modifier = config.options.txtUserName;
		this.tiddler.modified = new Date();
		store.addTiddler(this.tiddler);
	}
	return this;
};

bidix.UploadLog.prototype.addText = function(text) {
	if (!this.tiddler)
		return;
	// retrieve maxLine when we need it
	var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
	if (isNaN(maxLine))
		maxLine = -1;
	// add text
	if (maxLine != 0) 
		this.tiddler.text = this.tiddler.text + text;
	// Trunck to maxLine
	if (maxLine >= 0) {
		var textArray = this.tiddler.text.split('\n');
		if (textArray.length > maxLine + 1)
			textArray.splice(1,textArray.length-1-maxLine);
			this.tiddler.text = textArray.join('\n');		
	}
	// update tiddler fields
	this.tiddler.modifier = config.options.txtUserName;
	this.tiddler.modified = new Date();
	store.addTiddler(this.tiddler);
	// refresh and notifiy for immediate update
	story.refreshTiddler(this.tiddler.title);
	store.notify(this.tiddler.title, true);
};

bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {
	if (!this.tiddler)
		return;
	var now = new Date();
	var text = "\n| ";
	var filename = bidix.basename(document.location.toString());
	if (!filename) filename = '/';
	text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
	text += config.options.txtUserName + " | ";
	text += "[["+filename+"|"+location + "]] |";
	text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
	text += uploadDir + " | ";
	text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
	text += backupDir + " |";
	this.addText(text);
};

bidix.UploadLog.prototype.endUpload = function(status) {
	if (!this.tiddler)
		return;
	this.addText(" "+status+" |");
};

//
// Utilities
// 

bidix.checkPlugin = function(plugin, major, minor, revision) {
	var ext = version.extensions[plugin];
	if (!
		(ext  && 
			((ext.major > major) || 
			((ext.major == major) && (ext.minor > minor))  ||
			((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
			// write error in PluginManager
			if (pluginInfo)
				pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
			eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
	}
};

bidix.dirname = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};

bidix.basename = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("#")) != -1) 
		filePath = filePath.substring(0, lastpos);
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(lastpos + 1);
	} else
		return filePath.substring(filePath.lastIndexOf("\\")+1);
};

bidix.initOption = function(name,value) {
	if (!config.options[name])
		config.options[name] = value;
};

//
// Initializations
//

// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);

// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");

//optionsDesc
merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
	txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
	txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
	txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
	txtUploadUserName: "Upload Username",
	pasUploadPassword: "Upload Password",
	chkUploadLog: "do Logging in UploadLog (default: true)",
	txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});

// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');


/* don't want this for tiddlyspot sites

// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");

*/


//}}}


In a sketch, variables declared outside of the {{{setup()}}} or {{{draw()}}} functions (or any other functions you define) are considered //global//.  Variables defined in a function are local only to that function.
{{{
String glob = "I'm a global variable!";

void setup(){
    String loc = "I'm a local variable!";
    // a local varable pulling in the name of the global one:
    String locGlob = glob;
}

void draw(){
    String glob = "I'm a local variable, because I'm in this function!";
    String loc = "I'm another local variable, different from the one in setup();
}
}}}
Verlet sim examples
http://shabbyduck.org/post.php?id=29
http://codepen.io/stuffit/pen/KrAwx -- javascript
<<gradient horiz #ffffff  #ddddff #8888ff>>
[img[warpcat|http://farm3.static.flickr.com/2017/2118148943_75636dd96c.jpg?v=0]] Yes, that is me playing [[Rock Band|http://www.rockband.com/]].
''Eric Pavey''
*Email:  -  warpcat {{{(at)}}} sbcglobal {{{(dot)}}} net  -
*[[Blog|http://www.akeric.com/blog/]] - [[LinkedIn|http://www.linkedin.com/in/pavey]] - [[Flickr|http://www.flickr.com/photos/8064698@N03/collections/]] - [[Youtube|http://www.youtube.com/profile?user=warpcat]] - [[MobyGames|http://www.mobygames.com/developer/sheet/view/developerId,76979/]] - [[RSWarrior|http://rswarrior.com/photos/Warpcat/default.aspx]]
>>
My other Tiddlywiki's:
*[[mel wiki|http://mayamel.tiddlyspot.com/]]
*[[Python wiki|http://pythonwiki.tiddlyspot.com/]]
*[[PyGame Wiki|http://pygamewiki.tiddlyspot.com/]]
*[[CG OpenSource wiki|http://cgoswiki.tiddlyspot.com/]]
Here's a blog post for a "Minority Report" style of interaction with your web cam:
http://www.local-guru.net/blog/articles/2008/10/10/touchless-multitouch-in-processing
<<gradient horiz #ffffff  #ddddff #8888ff >>
[[About Processing Wiki]] (go here first)
[[Instructions for use]] (go here second)
[[Check out the latest updates|History]] (go here third)

//Hit ''F5'' to refresh your cache to see latest stuff.//

<<gradient horiz #ddddff  #8888ff >>''Browse \ Search using:''
----
{{{<---}}} Major ''//Categories//'' (or 'All Subjects') in the Left column
Key-word ''//Tags//'' tab in the Right column {{{--->}}}
The ''//Search//'' box in the Right column (top) {{{--->}}}
----
>>>>
Best viewed in ''[[Firefox|http://www.mozilla.com]]''
Running [[tiddlywiki|http://www.tiddlywiki.com]] v<<version>>
If you find this wiki useful, let the [[author|WarpCat]] know!
http://java.sun.com/j2se/1.4.2/docs/api/index.html
Lists the Java API most applicable to processing.  These classes are available in Processing all the time, just not documented in the standard processing reference.  
Example usage of the Java {{{Point}}} class:
{{{
Point[] p  = new Point[2];
p[0] = new Point(2,3);
p[1] = new Point(56, 24);
println(p[0].x + " " + p[0].y);
2 3
}}}
Make your sketch loop:
{{{
loop()
}}}
Stop sketch from looping:
{{{
noLoop()
}}}
Control frame rate of the sketch:
{{{
frameRate()
}}}
Cause the {{{draw()}}} function to execute once.
{{{
redraw()
}}}
''Variables:''
*[[boolean|http://processing.org/reference/boolean.html]]  :  {{{true}}} or {{{false}}}.  {{{1}}} or {{{0}}}
*[[byte|http://processing.org/reference/byte.html]]  :  The byte representation of an {{{int}}}, or {{{char}}}, from -128 to 127.
*[[char|http://processing.org/reference/char.html]]  : A numeric representation for a single character
*[[float|http://processing.org/reference/float.html]]  :  A floating point value.
*[[double|http://processing.org/reference/double.html]] : A datatype for floating-point numbers larger than those that can be stored in a float.
*[[int|http://processing.org/reference/int.html]]  :  Number with no decimal.
*[[long|http://processing.org/reference/long.html]]  :  Datatype for large integers (bigger than {{{int}}} if you need it). 
*[[color|http://processing.org/reference/color_datatype.html]]  :  Datatype for storing color values.
More advanced variables, or [[class]]es that act like variables:
*[[String|http://processing.org/reference/String.html]]  :  A sequence of text.  It's //capitalized// (because it's a [[class]]), has associated [[methods|Array and String methods]].
*[[PFont|http://processing.org/reference/PFont.html]]  :  Font data type, filled by {{{loadFont}}}, and setup with {{{textFont}}}.  See my notes here: [[Text and fonts]]
*[[PImage|http://processing.org/reference/PImage.html]]  : Image data type, filled by {{{loadImage}}}, and setup with {{{image}}}.  Has [[methods|PImage methods]]
*[[PVector|http://processing.org/reference/PVector.html]]  :  New to Processing 1.0.
*[[Array|http://processing.org/reference/Array.html]]  :  Most variables can be made into an {{{array}}}, see [[Info on arrays]]
*[[ArrayList|http://processing.org/reference/ArrayList.html]]  :  A dynamically resizable {{{Array}}}
*[[HashMap|http://processing.org/reference/HashMap.html]]  :  Also known as 'dictionaries' in other languages, it stores a collection of objects, each referenced by a key.
* Any [[Object|http://processing.org/reference/Object.html]] made by a [[class]] has it's own variable type.
----
There are a few more obscure ones.  Check the [[Processing Extended Reference|http://processing.org/reference/index_ext.html]] under '''Data'''.
''Image Related:''
Load an image from disk, but don't display it:
{{{
PImage img = loadImage("foo.jpg");
}}}
Get the resolution of a loaded image:
{{{
int w = img.width;
int h = img.height;
}}}
Display an image once loaded to the display window (two different ways):
{{{
image(img, 0, 0);
set(0, 0, img);
}}}
Get a single pixel value from a //loaded image//:
{{{
// using the PImage.get() method:
color pix = img.get(x, y);

// Using the PImage.pixels[] array:
color pix = img.pixels[(x+y*img.width)];
}}}
Create a //new// image, based off of some pixel region of a //loaded image//:
{{{
PImage imgB = img.get(x, y, width, height); 
}}}
Create a //new// image, based off of some pixel region of the //display window//:
{{{
PImage imgC = get(x, y, width, height);
}}}
Create a //new// image of a certain resolution, but no defined pixel values:
{{{
PImage imgD = createImage(width, height, RGB); // or ARGB, or ALPHA
}}}
Create a //new// image of some resolution, based off of some pixel region of a //loaded image// of a different resolution, and have the image resize to fit:
{{{
// load the image we want to copy from:
PImage img = loadImage("foo.jpg");
// create our new image, with temp pixels, but the resolution we want:
PImage newImg = img.get(0, 0, newResX, newResY);
// copy our source image into the new image, making it fit:
newImg.copy(img, 0, 0, img.width, img.height, 0, 0, newResX, newResY);
}}}
Change the color of a single pixel, of a loaded image:
{{{
color col = color(0, 0, 0);

// using the PImage.set() method:
img.set(x, y, col);

// using the PImage.pixels[] array:
img.pixels[(x+y*img.width)] = col;
}}}
How can I draw to an off-screne render buffer?
*Check the docs on [[PGraphics|http://www.processing.org/reference/PGraphics.html]]
*Need to expand example here.
----
''Display Window Related'':
Load all the pixels of the //display window// into the {{{pixels[]}}} array (which is the {{{color}}} datatype):
{{{
loadPixels();
}}}
Update the //display window// with any changes made to the {{{pixels[]}}} array (which is the {{{color}}} datatype):
{{{
updatePixels();
}}}
Get a single pixel value from the //display window//.
{{{
// Using the get() function:
color pix = get(x, y);

// Accessing the pixels[] array (presuming it's been loaded first).
// I have read this is faster than the get() function.
color pix = pixels[x+y*width];
}}}
Change a single pixel in the //display window//:
{{{
color col = color(0, 0, 0);

// using set():
set(x, y, col);

// using the pixels[] array (presuming it's been loaded first):
pixels[x+y*width] = col;
updatePixels();
}}}
''Object Oriented Programming (OOP) in Processing.''
For another take on this, see similar notes on my [[Python Wiki|http://pythonwiki.tiddlyspot.com/#Class]].
Also see [[Sun's|http://java.sun.com/]] page on [[Java OOP|http://java.sun.com/docs/books/tutorial/java/concepts/index.html]]

''Simple Overview:''
*''Class'':  AKA, "The Blueprint".  A class is an //object// maker: it contains all the statements needed to create an //object//, it's //properties//, as well as the statements to describe the operations that the //object// will be able to perform, via its //methods//.  Think of it as an '//object// factory'.  To say it another way:  A //class// isn't an //object//, it's a design for one.  Consider a //class// as the blueprint for an //object//.
*''Instance'':  AKA, "The Process".  The process of creating //objects// from a //class// is called //instantiation//.  //Classes// make //instances// of themselves, which are //objects//.  You create an //instance// by calling to a //function// with the same name as the //class//.  This function is called the //constructor method// (see below).  You can actually have multiple constructors, allowing for different default arguments to be passed in during //instancing//.  This is called "overloading the constructor".
*''Object'':  AKA, "The Result".  An //object// is a framework to group values (properties) and operations on these values (methods).  It is an //instance// of a //class//.  When a //class// goes to work, an //object// is the result (via instantiation).
*''Method'':  AKA, "An Ability".  A //method// is a [[function]] defined for a //class//, specifying a behavior of the //class instances//.  Method definitions follow exactly the same pattern as standard [[function]] definitions.  A method gives an object the ability to do something.  Methods as referred to here are considered //instance methods//.  //Static methods// (also known as class methods) are discussed below.
*''Properties'':  AKA, "A Memory".  //Properties// are variables that live inside of an //object//, as defined by the //class//.  They can be filled with values when the //instance// is made, as defined by the //constructor function//.  Basically, //properties// let objects remember things, and act on them via their //methods//.  Properties as referred to here are considered //instance properties//.  //Static properties// (also known as class properties) are discussed below.
Simple data breakdown:  
*''Class''  -  Makes (via instancing):
**''Objects''  -  Instance of a class, which contain (based on the class definitions):
***''Methods''  -  (functions defined inside of the class)
***''Properties''  -  (variables defined inside of the class)
(also see info on '[[this|http://www.processing.org/reference/this.html]]', which is //similar// to Python's '[[self|http://pythonwiki.tiddlyspot.com/#%5B%5BWhat%20is%20up%20with%20'self'%3F%5D%5D]]')

Example Class (from Processing.org [[class|http://www.processing.org/reference/class.html]] example):
{{{
// define the class, note the Uppercase:
class HLine { 

// define properties:
  float ypos, speed; 

// constructor function.  Also think of as creation arguments\parameters
  HLine (float y, float s) {  
    ypos = y; 
    speed = s; 
  } 

// method:  Things you can call to via classname.method
  void update() { 
    ypos += speed; 
    if (ypos > width) { 
      ypos = 0; 
    } 
    line(0, ypos, width, ypos); 
  } 
}
}}}
The class in action:
{{{
// Declare and contruct two objects (h1, h2) from the class HLine 
HLine h1 = new HLine(20, 2.0); 
HLine h2 = new HLine(50, 2.5); 
 
void setup() 
{
  size(200, 200);
  frameRate(30);
}

void draw() { 
  background(204);
  h1.update(); 
  h2.update();  
} 
}}}
----
''More advanced class stuff'':
*Static properties & Constants:
**Any property can be made a 'static property' by putting the keyword {{{static}}} in front of it.  They are also considered //class properties//.  These properties are accessed via the class, not by an instanced object.  It also means that all instanced objects share these properties.  Furthermore, static properties seem to be required to me made into //constants//: Variables that don't change.  To do this, you add the keyword {{{final}}} in front of the name.  Traditionally, {{{constants}}} are all upper-case:
{{{
class Foo{
  static final float PROP = 0;
// continue...
}
// then to access:
float num = Foo.PROP;
}}}
**notice I called the class directly, and not an object?  Calling an object works too though.
*Static methods:
**Possible?
*Inheritance:
**If you have one class inherit from another, you first need to {{{extend}}} the parental class (known as the //super class//), then you can call to it with the {{{super}}} keyword:
{{{
class Foo{
  int var;
  Foo(int var){
    this.var = var;
  }
}
class Goo extends Foo{
  Goo(var){
    super(var);
  }
}
}}}
**When in the Goo {{{constructor}}}, the //very first thing// you need to call too is the {{{super}}} command, with the correct arguments to pass to the super class.
*Public and Private
**{{{public}}}, {{{private}}}
**This are public by default.  Tagging them as {{{private}}} though, doesn't seem to have any privatization effects?
*Abstract classes and methods...

Functions organize code into reusable blocks.  They can take arguments, and return values.  They must always be preceded by the type of [[variable|What types of variables does Processing have?]] they return.  If they return nothing, they are preceded by {{{void}}}.
{{{
void draw() {
  line(10, 100, 190, 100);
}
}}}
This is a modification of [[PerlinParticles02]].
Note, you //must// have an image in your sketch folder named {{{image.jpg}}} for this sketch to function.
I'd advise you keep the resolution of the image less that 1024x1024, since it controls the display resolution of the sketch.
Movie here on [[Flickr|http://www.flickr.com/photos/warpcat/3130487990/in/set-72157605688360509/]]
{{{
/*
 Eric Pavey 2008-12-22
 imageParticlePath01
 Made with Processing v1.01
 
 Render particles to screen, with their position being effected by
 the RGB of the source image.
 
 This code is an update of perlinParticle02.
 In perlinParticle02, it would generate three random images based on perlin noise.
 noise. This version, doesn't use perlin noise at all, but an image placed in
 the sketch folder.  
 
 The background can be changed by clicking the mouse button:
 The first BG image is the loaded image.
 The second BG image is the x (red) influence image.
 The third BG image is the y (green) influence image.
 The fourth BG image is the z\'speed' (blue) image.
 The fifth is no BG at all (black)
 
 For the x & y images:
 Black values make partcies go in negative direction.  
 White values make particles go in positive directions.
 
 For the 'speed' image:
 black values make particles slow down, white values make particles
 speed up.
 
 If a particle stops moving, or occupies the space of another
 particle, it will re-spawn.
 */

//------------------------------
// User vars:
int numPerls = 500;
float speed = 20;
// controls background transparency.
int fade = 32;

//------------------------------
// System vars, no touch!
PImage imageX; 
PImage imageY; 
PImage imageZ;
PImage imageBG;
PImage bg;
Perl[] perls = new Perl[numPerls];

//------------------------------
void setup(){
  bg = loadImage("image.jpg");
  int w = bg.width;
  int h = bg.height;

  size(w, h);
  frameRate(30);

  imageX = createImage(w, h, ARGB);
  imageY = createImage(w, h, ARGB);
  imageZ = createImage(w, h, ARGB);
  // make a new background image with alpha:
  imageBG = createImage(w, h, ARGB);

  makeImage(bg, imageX, 0);
  makeImage(bg, imageY, 1);
  makeImage(bg, imageZ, 2);
  makeImage(bg, imageBG, 3);

  smooth();
  for(int i=0; i<numPerls; i++){
    perls[i] = new Perl(); 
  }
}

//------------------------------
void draw(){
  if(drawImage == 0){
    image(imageBG,0,0);
  }
  if(drawImage == 1){
    image(imageX,0,0);
  }  
  if(drawImage == 2){
    image(imageY,0,0);
  }    
  if(drawImage == 3){
    image(imageZ,0,0);
  }   
  if(drawImage == 4){  
    fill(0,fade*.25);
    quad(0,0, width, 0, width, height, 0, height);  
  }
  for(int i=0; i<numPerls; i++){
    perls[i].run();
  }  
}

//-----------------------------
// cycle through our images
void mousePressed() {
  drawImage += 1;
  if(drawImage > 4) {
    drawImage = 0; 
  }
} 


//------------------------------

class Perl{

  //------------------------------
  float x, y;
  float lastX, lastY;
  float randX, randY;
  float diameter;
  float c;
  color col;

  //------------------------------
  Perl(){
    init();
  }

  //------------------------------
  void init(){
    x = random(0, width);
    y = random(0, height);
    lastX = x;
    lastY = y;
    diameter = random(2.0,10.0);
    c=0;
    col = color(bg.get(int(x),int(y)));
  }

  //------------------------------
  void move(){
    lastY = y;
    lastX = x;   

    rand();

    x = x + randX;
    y = y + randY;
    
    if(y > height){
      y = 0;
      lastY = y;
    }
    else if (y < 0){
      y = height; 
      lastY = y;
    }
    if(x<0){
      x = width;
      lastX = x;
    }
    else if(x > width){
      x = 0; 
      lastX = x;
    }
  }

  //------------------------------
  void rand(){   

    color xCol = imageX.get(int(x), int(y));
    color yCol = imageY.get(int(x), int(y));
    color amtCol = imageZ.get(int(x), int(y)); 

    float xVal = map(brightness(xCol), 0.0, 255.0, -1.0, 1.0);
    float yVal = map(brightness(yCol), 0.0, 255.0, 1.0, -1.0);
    float amtVal = map(brightness(amtCol), 0.0, 255.0, 0, 1.0);  

    randX = (xVal * amtVal * speed);
    randY = (yVal * amtVal * speed);
  }

  //------------------------------
  // if a particle has stopped, reset it, or 
  // if this particles position is in the same location as another,
  // re-initialize
  void posCheck(){
    if(abs(x -lastX) < .01 && abs(y -lastY) < .01){
      init();     
    }
    else{
      for(int i=0; i<perls.length; i++){
        // don't interact with itself:
        if(perls[i] != this){   
          float[] otherPos = perls[i].getPos();
          if(abs(otherPos[0] - this.x) < 1 && abs(otherPos[1] - this.y) < 1){
            init(); 
          }
        }
      }
    }
  }

  //------------------------------
  float[] getPos(){
    float[] ret = {this.x, this.y};
    return ret; 
  }

  //------------------------------
  void render(){
    // increase our alpha over time:
    if (c < 255){
      c+=4; 
    }
    stroke(col, c);
    line(x, y, lastX, lastY);
    strokeWeight(diameter);
    strokeCap(ROUND);

  }

  //------------------------------
  void run(){
    posCheck();
    move();
    render();
  }

}

//-----------------------------
// generate our red, green, blue and bg images
// channel 0-2 = r,g,b.  3 = a new bg image, with alpha

void makeImage(PImage srcImg, PImage destImg, int channel){

  for(int x=0; x < width; x++) {
    for(int y=0; y < height; y++){
      color orig = srcImg.get(x,y);
      color newCol = color(0,0,0);
      float r = red(orig);
      float g = green(orig);
      float b = blue(orig);
      
      if(channel == 0){
        newCol = color(r, fade);
      }
      if(channel == 1){
        newCol = color(g, fade);        
      }
      if(channel == 2){
        newCol = color(b, fade);        
      }      
      if(channel == 3){
        newCol = color(r,g,b, fade);        
      }            
      destImg.set(x,y,newCol); 
    }
  }  
}
}}}
Code to simply loop over the pixels of an image, and process them as it goes.
{{{
/*
itterImage01
Eric Pavey - 2008-06-18

Based on the pixels of a loaded image, process every 'step' number of them,
doing some work.  In the case of the example, it will draw a circle at
every 10th pixel, with the color of that pixel.
*/

PImage img;
int ix = 0;
int iy = 0;
int step = 10;

void setup(){
  img = loadImage("image.jpg");
  int w = img.width;
  int h = img.height;
  size(w, h);
  smooth();
}

void draw(){
  if(iy < height){  
    color pix = img.pixels[(ix+iy*img.width)];
    fill(pix);
    ellipse(ix, iy, step, step);
    ix = ix + step;
    if(ix > width){
      ix = 0;
      iy = iy + step;
    }
  }
}
}}}
Image below code...
{{{
/*
puffPaint01
Eric Pavey - 2008-06-18

Load an image, and "paint" on it with the mouse, creating faded circles.
Depending on speed of mouse, the opacity, size, and stroke-width of circles
will change.  Samples color of pixels below mouse.
Save your image as "image.jpg" in the sketch dir.
*/

PImage img;

void setup(){
  img = loadImage("image.jpg");
  int w = img.width;
  int h = img.height;
  size(w, h);
  image(img, 0, 0);
  smooth();
}

void draw(){
  // resAve is designed to change with the size of the loaded image,
  // giving similar results with the code despite resolution.
  float resAve = (img.width + img.height) / 2;
  
  // faster the mouse moves, more transparent the stroke gets:
  int strokeAlph = mouseMap(0, resAve/2, 128, 0);
  // faster the mouse moves, bigger the stroke gets:
  int strokeSize = mouseMap(0, resAve, 1, 16);
  // faster the mouse moves, more opaque the fill gets:
  int fillAlph = mouseMap(0, resAve, 0, 255);  
  // faster the mouse moves, bigger the circle gets:
  int drawSize = mouseMap(0, resAve/3, 1, 100);
  
  if(mousePressed){
    color pix = img.get(mouseX, mouseY);
    fill(pix, fillAlph);
    stroke(pix, int(strokeAlph));
    strokeWeight(strokeSize);
    ellipse(mouseX, mouseY, drawSize, drawSize);
  }
}

// calculate mouse distance traveled per frame:
int mouseMap(float low1, float high1, float low2, float high2){
  float dis = sqrt(abs(
    pow(mouseX, 2) - pow(pmouseX, 2) + 
    pow(mouseY, 2) - pow(pmouseY, 2)));
  return int(map(dis, low1, high1, low2, high2));
}
}}}
[img[http://farm4.static.flickr.com/3212/2590909484_7209ac6afc_o.jpg]]
Some links dealing with the code behind having sprites face a camera:
http://processing.org/discourse/yabb2/YaBB.pl?num=1212648257
http://nehe.gamedev.net/data/articles/article.asp?article=19
Example sketch online:
http://www.seltar.org/projects/particle3D/v2/