Вы находитесь на странице: 1из 189

/*** P R O C E S S I N G . J S - 1.4.1 a port of the Processing visualization language Processing.js is licensed under the MIT License, see LICENSE.

For a list of copyright holders, please refer to AUTHORS. http://processingjs.org ***/ (function(window, document, Math, undef) { var nop = function() {}; var debug = function() { if ("console" in window) return function(msg) { window.console.log("Processing.js: " + msg) }; return nop }(); var ajax = function(url) { var xhr = new XMLHttpRequest; xhr.open("GET", url, false); if (xhr.overrideMimeType) xhr.overrideMimeType("text/plain"); xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); xhr.send(null); if (xhr.status !== 200 && xhr.status !== 0) throw "XMLHttpRequest failed, st atus code " + xhr.status; return xhr.responseText }; var isDOMPresent = "document" in this && !("fake" in this.document); document.head = document.head || document.getElementsByTagName("head")[0]; function setupTypedArray(name, fallback) { if (name in window) return window[name]; if (typeof window[fallback] === "function") return window[fallback]; return function(obj) { if (obj instanceof Array) return obj; if (typeof obj === "number") { var arr = []; arr.length = obj; return arr } } } if (document.documentMode >= 9 && !document.doctype) throw "The doctype direct ive is missing. The recommended doctype in Internet Explorer is the HTML5 doctyp e: <!DOCTYPE html>"; var Float32Array = setupTypedArray("Float32Array", "WebGLFloatArray"), Int32Array = setupTypedArray("Int32Array", "WebGLIntArray"), Uint16Array = setupTypedArray("Uint16Array", "WebGLUnsignedShortArray"), Uint8Array = setupTypedArray("Uint8Array", "WebGLUnsignedByteArray"); var PConstants = { X: 0, Y: 1, Z: 2, R: 3, G: 4, B: 5, A: 6,

U: 7, V: 8, NX: 9, NY: 10, NZ: 11, EDGE: 12, SR: 13, SG: 14, SB: 15, SA: 16, SW: 17, TX: 18, TY: 19, TZ: 20, VX: 21, VY: 22, VZ: 23, VW: 24, AR: 25, AG: 26, AB: 27, DR: 3, DG: 4, DB: 5, DA: 6, SPR: 28, SPG: 29, SPB: 30, SHINE: 31, ER: 32, EG: 33, EB: 34, BEEN_LIT: 35, VERTEX_FIELD_COUNT: 36, P2D: 1, JAVA2D: 1, WEBGL: 2, P3D: 2, OPENGL: 2, PDF: 0, DXF: 0, OTHER: 0, WINDOWS: 1, MAXOSX: 2, LINUX: 3, EPSILON: 1.0E-4, MAX_FLOAT: 3.4028235E38, MIN_FLOAT: -3.4028235E38, MAX_INT: 2147483647, MIN_INT: -2147483648, PI: Math.PI, TWO_PI: 2 * Math.PI, HALF_PI: Math.PI / 2, THIRD_PI: Math.PI / 3, QUARTER_PI: Math.PI / 4, DEG_TO_RAD: Math.PI / 180, RAD_TO_DEG: 180 / Math.PI, WHITESPACE: " \t\n\r\u000c\u00a0", RGB: 1, ARGB: 2,

HSB: 3, ALPHA: 4, CMYK: 5, TIFF: 0, TARGA: 1, JPEG: 2, GIF: 3, BLUR: 11, GRAY: 12, INVERT: 13, OPAQUE: 14, POSTERIZE: 15, THRESHOLD: 16, ERODE: 17, DILATE: 18, REPLACE: 0, BLEND: 1 << 0, ADD: 1 << 1, SUBTRACT: 1 << 2, LIGHTEST: 1 << 3, DARKEST: 1 << 4, DIFFERENCE: 1 << 5, EXCLUSION: 1 << 6, MULTIPLY: 1 << 7, SCREEN: 1 << 8, OVERLAY: 1 << 9, HARD_LIGHT: 1 << 10, SOFT_LIGHT: 1 << 11, DODGE: 1 << 12, BURN: 1 << 13, ALPHA_MASK: 4278190080, RED_MASK: 16711680, GREEN_MASK: 65280, BLUE_MASK: 255, CUSTOM: 0, ORTHOGRAPHIC: 2, PERSPECTIVE: 3, POINT: 2, POINTS: 2, LINE: 4, LINES: 4, TRIANGLE: 8, TRIANGLES: 9, TRIANGLE_STRIP: 10, TRIANGLE_FAN: 11, QUAD: 16, QUADS: 16, QUAD_STRIP: 17, POLYGON: 20, PATH: 21, RECT: 30, ELLIPSE: 31, ARC: 32, SPHERE: 40, BOX: 41, GROUP: 0, PRIMITIVE: 1, GEOMETRY: 3, VERTEX: 0, BEZIER_VERTEX: 1,

CURVE_VERTEX: 2, BREAK: 3, CLOSESHAPE: 4, OPEN: 1, CLOSE: 2, CORNER: 0, CORNERS: 1, RADIUS: 2, CENTER_RADIUS: 2, CENTER: 3, DIAMETER: 3, CENTER_DIAMETER: 3, BASELINE: 0, TOP: 101, BOTTOM: 102, NORMAL: 1, NORMALIZED: 1, IMAGE: 2, MODEL: 4, SHAPE: 5, SQUARE: "butt", ROUND: "round", PROJECT: "square", MITER: "miter", BEVEL: "bevel", AMBIENT: 0, DIRECTIONAL: 1, SPOT: 3, BACKSPACE: 8, TAB: 9, ENTER: 10, RETURN: 13, ESC: 27, DELETE: 127, CODED: 65535, SHIFT: 16, CONTROL: 17, ALT: 18, CAPSLK: 20, PGUP: 33, PGDN: 34, END: 35, HOME: 36, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, NUMLK: 144,

META: 157, INSERT: 155, ARROW: "default", CROSS: "crosshair", HAND: "pointer", MOVE: "move", TEXT: "text", WAIT: "wait", NOCURSOR: "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALA AAAAABAAEAAAICRAEAOw=='), auto", DISABLE_OPENGL_2X_SMOOTH: 1, ENABLE_OPENGL_2X_SMOOTH: -1, ENABLE_OPENGL_4X_SMOOTH: 2, ENABLE_NATIVE_FONTS: 3, DISABLE_DEPTH_TEST: 4, ENABLE_DEPTH_TEST: -4, ENABLE_DEPTH_SORT: 5, DISABLE_DEPTH_SORT: -5, DISABLE_OPENGL_ERROR_REPORT: 6, ENABLE_OPENGL_ERROR_REPORT: -6, ENABLE_ACCURATE_TEXTURES: 7, DISABLE_ACCURATE_TEXTURES: -7, HINT_COUNT: 10, SINCOS_LENGTH: 720, PRECISIONB: 15, PRECISIONF: 1 << 15, PREC_MAXVAL: (1 << 15) - 1, PREC_ALPHA_SHIFT: 24 - 15, PREC_RED_SHIFT: 16 - 15, NORMAL_MODE_AUTO: 0, NORMAL_MODE_SHAPE: 1, NORMAL_MODE_VERTEX: 2, MAX_LIGHTS: 8 }; function virtHashCode(obj) { if (typeof obj === "string") { var hash = 0; for (var i = 0; i < obj.length; ++i) hash = hash * 31 + obj.charCodeAt(i) & 4294967295; return hash } if (typeof obj !== "object") return obj & 4294967295; if (obj.hashCode instanceof Function) return obj.hashCode(); if (obj.$id === undef) obj.$id = Math.floor(Math.random() * 65536) - 32768 < < 16 | Math.floor(Math.random() * 65536); return obj.$id } function virtEquals(obj, other) { if (obj === null || other === null) return obj === null && other === null; if (typeof obj === "string") return obj === other; if (typeof obj !== "object") return obj === other; if (obj.equals instanceof Function) return obj.equals(other); return obj === other } var ObjectIterator = function(obj) { if (obj.iterator instanceof Function) return obj.iterator(); if (obj instanceof Array) { var index = -1;

this.hasNext = function() { return ++index < obj.length }; this.next = function() { return obj[index] } } else throw "Unable to iterate: " + obj; }; var ArrayList = function() { function Iterator(array) { var index = 0; this.hasNext = function() { return index < array.length }; this.next = function() { return array[index++] }; this.remove = function() { array.splice(index, 1) } } function ArrayList(a) { var array; if (a instanceof ArrayList) array = a.toArray(); else { array = []; if (typeof a === "number") array.length = a > 0 ? a : 0 } this.get = function(i) { return array[i] }; this.contains = function(item) { return this.indexOf(item) > -1 }; this.indexOf = function(item) { for (var i = 0, len = array.length; i < len; ++i) if (virtEquals(item, a rray[i])) return i; return -1 }; this.lastIndexOf = function(item) { for (var i = array.length - 1; i >= 0; --i) if (virtEquals(item, array[i ])) return i; return -1 }; this.add = function() { if (arguments.length === 1) array.push(arguments[0]); else if (arguments.length === 2) { var arg0 = arguments[0]; if (typeof arg0 === "number") if (arg0 >= 0 && arg0 <= array.length) a rray.splice(arg0, 0, arguments[1]); else throw arg0 + " is not a valid index"; else throw typeof arg0 + " is not a number"; } else throw "Please use the proper number of parameters."; }; this.addAll = function(arg1, arg2) { var it; if (typeof arg1 === "number") { if (arg1 < 0 || arg1 > array.length) throw "Index out of bounds for ad dAll: " + arg1 + " greater or equal than " + array.length; it = new ObjectIterator(arg2);

while (it.hasNext()) array.splice(arg1++, 0, it.next()) } else { it = new ObjectIterator(arg1); while (it.hasNext()) array.push(it.next()) } }; this.set = function() { if (arguments.length === 2) { var arg0 = arguments[0]; if (typeof arg0 === "number") if (arg0 >= 0 && arg0 < array.length) ar ray.splice(arg0, 1, arguments[1]); else throw arg0 + " is not a valid index."; else throw typeof arg0 + " is not a number"; } else throw "Please use the proper number of parameters."; }; this.size = function() { return array.length }; this.clear = function() { array.length = 0 }; this.remove = function(item) { if (typeof item === "number") return array.splice(item, 1)[0]; item = this.indexOf(item); if (item > -1) { array.splice(item, 1); return true } return false }; this.removeAll = function(c) { var i, x, item, newList = new ArrayList; newList.addAll(this); this.clear(); for (i = 0, x = 0; i < newList.size(); i++) { item = newList.get(i); if (!c.contains(item)) this.add(x++, item) } if (this.size() < newList.size()) return true; return false }; this.isEmpty = function() { return !array.length }; this.clone = function() { return new ArrayList(this) }; this.toArray = function() { return array.slice(0) }; this.iterator = function() { return new Iterator(array) } } return ArrayList }(); var HashMap = function() { function HashMap() { if (arguments.length === 1 && arguments[0] instanceof HashMap) return argu ments[0].clone();

var initialCapacity = arguments.length > 0 ? arguments[0] : 16; var loadFactor = arguments.length > 1 ? arguments[1] : 0.75; var buckets = []; buckets.length = initialCapacity; var count = 0; var hashMap = this; function getBucketIndex(key) { var index = virtHashCode(key) % buckets.length; return index < 0 ? buckets.length + index : index } function ensureLoad() { if (count <= loadFactor * buckets.length) return; var allEntries = []; for (var i = 0; i < buckets.length; ++i) if (buckets[i] !== undef) allEn tries = allEntries.concat(buckets[i]); var newBucketsLength = buckets.length * 2; buckets = []; buckets.length = newBucketsLength; for (var j = 0; j < allEntries.length; ++j) { var index = getBucketIndex(allEntries[j].key); var bucket = buckets[index]; if (bucket === undef) buckets[index] = bucket = []; bucket.push(allEntries[j]) } } function Iterator(conversion, removeItem) { var bucketIndex = 0; var itemIndex = -1; var endOfBuckets = false; var currentItem; function findNext() { while (!endOfBuckets) { ++itemIndex; if (bucketIndex >= buckets.length) endOfBuckets = true; else if (buckets[bucketIndex] === undef || itemIndex >= buckets[buck etIndex].length) { itemIndex = -1; ++bucketIndex } else return } } this.hasNext = function() { return !endOfBuckets }; this.next = function() { currentItem = conversion(buckets[bucketIndex][itemIndex]); findNext(); return currentItem }; this.remove = function() { if (currentItem !== undef) { removeItem(currentItem); --itemIndex; findNext() } }; findNext() }

function Set(conversion, isIn, removeItem) { this.clear = function() { hashMap.clear() }; this.contains = function(o) { return isIn(o) }; this.containsAll = function(o) { var it = o.iterator(); while (it.hasNext()) if (!this.contains(it.next())) return false; return true }; this.isEmpty = function() { return hashMap.isEmpty() }; this.iterator = function() { return new Iterator(conversion, removeItem) }; this.remove = function(o) { if (this.contains(o)) { removeItem(o); return true } return false }; this.removeAll = function(c) { var it = c.iterator(); var changed = false; while (it.hasNext()) { var item = it.next(); if (this.contains(item)) { removeItem(item); changed = true } } return true }; this.retainAll = function(c) { var it = this.iterator(); var toRemove = []; while (it.hasNext()) { var entry = it.next(); if (!c.contains(entry)) toRemove.push(entry) } for (var i = 0; i < toRemove.length; ++i) removeItem(toRemove[i]); return toRemove.length > 0 }; this.size = function() { return hashMap.size() }; this.toArray = function() { var result = []; var it = this.iterator(); while (it.hasNext()) result.push(it.next()); return result } } function Entry(pair) { this._isIn = function(map) { return map === hashMap && pair.removed === undef

}; this.equals = function(o) { return virtEquals(pair.key, o.getKey()) }; this.getKey = function() { return pair.key }; this.getValue = function() { return pair.value }; this.hashCode = function(o) { return virtHashCode(pair.key) }; this.setValue = function(value) { var old = pair.value; pair.value = value; return old } } this.clear = function() { count = 0; buckets = []; buckets.length = initialCapacity }; this.clone = function() { var map = new HashMap; map.putAll(this); return map }; this.containsKey = function(key) { var index = getBucketIndex(key); var bucket = buckets[index]; if (bucket === undef) return false; for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, ke y)) return true; return false }; this.containsValue = function(value) { for (var i = 0; i < buckets.length; ++i) { var bucket = buckets[i]; if (bucket === undef) continue; for (var j = 0; j < bucket.length; ++j) if (virtEquals(bucket[j].value , value)) return true } return false }; this.entrySet = function() { return new Set(function(pair) { return new Entry(pair) }, function(pair) { return pair instanceof Entry && pair._isIn(hashMap) }, function(pair) { return hashMap.remove(pair.getKey()) })

}; this.get = function(key) { var index = getBucketIndex(key); var bucket = buckets[index]; if (bucket === undef) return null; for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, ke y)) return bucket[i].value; return null }; this.isEmpty = function() { return count === 0 }; this.keySet = function() { return new Set(function(pair) { return pair.key }, function(key) { return hashMap.containsKey(key) }, function(key) { return hashMap.remove(key) }) }; this.values = function() { return new Set(function(pair) { return pair.value }, function(value) { return hashMap.containsValue(value) }, function(value) { return hashMap.removeByValue(value) }) }; this.put = function(key, value) { var index = getBucketIndex(key); var bucket = buckets[index]; if (bucket === undef) { ++count; buckets[index] = [{ key: key, value: value }]; ensureLoad(); return null } for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, ke y)) { var previous = bucket[i].value; bucket[i].value = value; return previous }++count; bucket.push({

key: key, value: value }); ensureLoad(); return null }; this.putAll = function(m) { var it = m.entrySet().iterator(); while (it.hasNext()) { var entry = it.next(); this.put(entry.getKey(), entry.getValue()) } }; this.remove = function(key) { var index = getBucketIndex(key); var bucket = buckets[index]; if (bucket === undef) return null; for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, ke y)) { --count; var previous = bucket[i].value; bucket[i].removed = true; if (bucket.length > 1) bucket.splice(i, 1); else buckets[index] = undef; return previous } return null }; this.removeByValue = function(value) { var bucket, i, ilen, pair; for (bucket in buckets) if (buckets.hasOwnProperty(bucket)) for (i = 0, ilen = buckets[bucket].length; i < ilen; i++) { pair = buckets[bucket][i]; if (pair.value === value) { buckets[bucket].splice(i, 1); return true } } return false }; this.size = function() { return count } } return HashMap }(); var PVector = function() { function PVector(x, y, z) { this.x = x || 0; this.y = y || 0; this.z = z || 0 } PVector.dist = function(v1, v2) { return v1.dist(v2) }; PVector.dot = function(v1, v2) { return v1.dot(v2) }; PVector.cross = function(v1, v2) { return v1.cross(v2)

}; PVector.angleBetween = function(v1, v2) { return Math.acos(v1.dot(v2) / (v1.mag() * v2.mag())) }; PVector.prototype = { set: function(v, y, z) { if (arguments.length === 1) this.set(v.x || v[0] || 0, v.y || v[1] || 0, v.z || v[2] || 0); else { this.x = v; this.y = y; this.z = z } }, get: function() { return new PVector(this.x, this.y, this.z) }, mag: function() { var x = this.x, y = this.y, z = this.z; return Math.sqrt(x * x + y * y + z * z) }, add: function(v, y, z) { if (arguments.length === 1) { this.x += v.x; this.y += v.y; this.z += v.z } else { this.x += v; this.y += y; this.z += z } }, sub: function(v, y, z) { if (arguments.length === 1) { this.x -= v.x; this.y -= v.y; this.z -= v.z } else { this.x -= v; this.y -= y; this.z -= z } }, mult: function(v) { if (typeof v === "number") { this.x *= v; this.y *= v; this.z *= v } else { this.x *= v.x; this.y *= v.y; this.z *= v.z } }, div: function(v) { if (typeof v === "number") { this.x /= v; this.y /= v;

this.z } else { this.x this.y this.z }

/= v /= v.x; /= v.y; /= v.z

}, dist: function(v) { var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; return Math.sqrt(dx * dx + dy * dy + dz * dz) }, dot: function(v, y, z) { if (arguments.length === 1) return this.x * v.x + this.y * v.y + this.z * v.z; return this.x * v + this.y * y + this.z * z }, cross: function(v) { var x = this.x, y = this.y, z = this.z; return new PVector(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y) }, normalize: function() { var m = this.mag(); if (m > 0) this.div(m) }, limit: function(high) { if (this.mag() > high) { this.normalize(); this.mult(high) } }, heading2D: function() { return -Math.atan2(-this.y, this.x) }, toString: function() { return "[" + this.x + ", " + this.y + ", " + this.z + "]" }, array: function() { return [this.x, this.y, this.z] } }; function createPVectorMethod(method) { return function(v1, v2) { var v = v1.get(); v[method](v2); return v } } for (var method in PVector.prototype) if (PVector.prototype.hasOwnProperty(m ethod) && !PVector.hasOwnProperty(method)) PVector[method] = createPVectorMethod (method); return PVector }(); function DefaultScope() {}

DefaultScope.prototype = PConstants; var defaultScope = new DefaultScope; defaultScope.ArrayList = ArrayList; defaultScope.HashMap = HashMap; defaultScope.PVector = PVector; defaultScope.ObjectIterator = ObjectIterator; defaultScope.PConstants = PConstants; defaultScope.defineProperty = function(obj, name, desc) { if ("defineProperty" in Object) Object.defineProperty(obj, name, desc); else { if (desc.hasOwnProperty("get")) obj.__defineGetter__(name, desc.get); if (desc.hasOwnProperty("set")) obj.__defineSetter__(name, desc.set) } }; function overloadBaseClassFunction(object, name, basefn) { if (!object.hasOwnProperty(name) || typeof object[name] !== "function") { object[name] = basefn; return } var fn = object[name]; if ("$overloads" in fn) { fn.$defaultOverload = basefn; return } if (! ("$overloads" in basefn) && fn.length === basefn.length) return; var overloads, defaultOverload; if ("$overloads" in basefn) { overloads = basefn.$overloads.slice(0); overloads[fn.length] = fn; defaultOverload = basefn.$defaultOverload } else { overloads = []; overloads[basefn.length] = basefn; overloads[fn.length] = fn; defaultOverload = fn } var hubfn = function() { var fn = hubfn.$overloads[arguments.length] || ("$methodArgsIndex" in hubf n && arguments.length > hubfn.$methodArgsIndex ? hubfn.$overloads[hubfn.$methodA rgsIndex] : null) || hubfn.$defaultOverload; return fn.apply(this, arguments) }; hubfn.$overloads = overloads; if ("$methodArgsIndex" in basefn) hubfn.$methodArgsIndex = basefn.$methodArg sIndex; hubfn.$defaultOverload = defaultOverload; hubfn.name = name; object[name] = hubfn } function extendClass(subClass, baseClass) { function extendGetterSetter(propertyName) { defaultScope.defineProperty(subClass, propertyName, { get: function() { return baseClass[propertyName] }, set: function(v) { baseClass[propertyName] = v }, enumerable: true

}) } var properties = []; for (var propertyName in baseClass) if (typeof baseClass[propertyName] === " function") overloadBaseClassFunction(subClass, propertyName, baseClass[propertyN ame]); else if (propertyName.charAt(0) !== "$" && !(propertyName in subClass)) prop erties.push(propertyName); while (properties.length > 0) extendGetterSetter(properties.shift()); subClass.$super = baseClass } defaultScope.extendClassChain = function(base) { var path = [base]; for (var self = base.$upcast; self; self = self.$upcast) { extendClass(self, base); path.push(self); base = self } while (path.length > 0) path.pop().$self = base }; defaultScope.extendStaticMembers = function(derived, base) { extendClass(derived, base) }; defaultScope.extendInterfaceMembers = function(derived, base) { extendClass(derived, base) }; defaultScope.addMethod = function(object, name, fn, hasMethodArgs) { var existingfn = object[name]; if (existingfn || hasMethodArgs) { var args = fn.length; if ("$overloads" in existingfn) existingfn.$overloads[args] = fn; else { var hubfn = function() { var fn = hubfn.$overloads[arguments.length] || ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? hubfn.$overloads[hubfn.$met hodArgsIndex] : null) || hubfn.$defaultOverload; return fn.apply(this, arguments) }; var overloads = []; if (existingfn) overloads[existingfn.length] = existingfn; overloads[args] = fn; hubfn.$overloads = overloads; hubfn.$defaultOverload = existingfn || fn; if (hasMethodArgs) hubfn.$methodArgsIndex = args; hubfn.name = name; object[name] = hubfn } } else object[name] = fn }; function isNumericalJavaType(type) { if (typeof type !== "string") return false; return ["byte", "int", "char", "color", "float", "long", "double"].indexOf(t ype) !== -1 } defaultScope.createJavaArray = function(type, bounds) { var result = null, defaultValue = null; if (typeof type === "string") if (type === "boolean") defaultValue = false; else if (isNumericalJavaType(type)) defaultValue = 0;

if (typeof bounds[0] === "number") { var itemsCount = 0 | bounds[0]; if (bounds.length <= 1) { result = []; result.length = itemsCount; for (var i = 0; i < itemsCount; ++i) result[i] = defaultValue } else { result = []; var newBounds = bounds.slice(1); for (var j = 0; j < itemsCount; ++j) result.push(defaultScope.createJava Array(type, newBounds)) } } return result }; var colors = { aliceblue: "#f0f8ff", antiquewhite: "#faebd7", aqua: "#00ffff", aquamarine: "#7fffd4", azure: "#f0ffff", beige: "#f5f5dc", bisque: "#ffe4c4", black: "#000000", blanchedalmond: "#ffebcd", blue: "#0000ff", blueviolet: "#8a2be2", brown: "#a52a2a", burlywood: "#deb887", cadetblue: "#5f9ea0", chartreuse: "#7fff00", chocolate: "#d2691e", coral: "#ff7f50", cornflowerblue: "#6495ed", cornsilk: "#fff8dc", crimson: "#dc143c", cyan: "#00ffff", darkblue: "#00008b", darkcyan: "#008b8b", darkgoldenrod: "#b8860b", darkgray: "#a9a9a9", darkgreen: "#006400", darkkhaki: "#bdb76b", darkmagenta: "#8b008b", darkolivegreen: "#556b2f", darkorange: "#ff8c00", darkorchid: "#9932cc", darkred: "#8b0000", darksalmon: "#e9967a", darkseagreen: "#8fbc8f", darkslateblue: "#483d8b", darkslategray: "#2f4f4f", darkturquoise: "#00ced1", darkviolet: "#9400d3", deeppink: "#ff1493", deepskyblue: "#00bfff", dimgray: "#696969", dodgerblue: "#1e90ff", firebrick: "#b22222", floralwhite: "#fffaf0",

forestgreen: "#228b22", fuchsia: "#ff00ff", gainsboro: "#dcdcdc", ghostwhite: "#f8f8ff", gold: "#ffd700", goldenrod: "#daa520", gray: "#808080", green: "#008000", greenyellow: "#adff2f", honeydew: "#f0fff0", hotpink: "#ff69b4", indianred: "#cd5c5c", indigo: "#4b0082", ivory: "#fffff0", khaki: "#f0e68c", lavender: "#e6e6fa", lavenderblush: "#fff0f5", lawngreen: "#7cfc00", lemonchiffon: "#fffacd", lightblue: "#add8e6", lightcoral: "#f08080", lightcyan: "#e0ffff", lightgoldenrodyellow: "#fafad2", lightgrey: "#d3d3d3", lightgreen: "#90ee90", lightpink: "#ffb6c1", lightsalmon: "#ffa07a", lightseagreen: "#20b2aa", lightskyblue: "#87cefa", lightslategray: "#778899", lightsteelblue: "#b0c4de", lightyellow: "#ffffe0", lime: "#00ff00", limegreen: "#32cd32", linen: "#faf0e6", magenta: "#ff00ff", maroon: "#800000", mediumaquamarine: "#66cdaa", mediumblue: "#0000cd", mediumorchid: "#ba55d3", mediumpurple: "#9370d8", mediumseagreen: "#3cb371", mediumslateblue: "#7b68ee", mediumspringgreen: "#00fa9a", mediumturquoise: "#48d1cc", mediumvioletred: "#c71585", midnightblue: "#191970", mintcream: "#f5fffa", mistyrose: "#ffe4e1", moccasin: "#ffe4b5", navajowhite: "#ffdead", navy: "#000080", oldlace: "#fdf5e6", olive: "#808000", olivedrab: "#6b8e23", orange: "#ffa500", orangered: "#ff4500", orchid: "#da70d6", palegoldenrod: "#eee8aa", palegreen: "#98fb98",

paleturquoise: "#afeeee", palevioletred: "#d87093", papayawhip: "#ffefd5", peachpuff: "#ffdab9", peru: "#cd853f", pink: "#ffc0cb", plum: "#dda0dd", powderblue: "#b0e0e6", purple: "#800080", red: "#ff0000", rosybrown: "#bc8f8f", royalblue: "#4169e1", saddlebrown: "#8b4513", salmon: "#fa8072", sandybrown: "#f4a460", seagreen: "#2e8b57", seashell: "#fff5ee", sienna: "#a0522d", silver: "#c0c0c0", skyblue: "#87ceeb", slateblue: "#6a5acd", slategray: "#708090", snow: "#fffafa", springgreen: "#00ff7f", steelblue: "#4682b4", tan: "#d2b48c", teal: "#008080", thistle: "#d8bfd8", tomato: "#ff6347", turquoise: "#40e0d0", violet: "#ee82ee", wheat: "#f5deb3", white: "#ffffff", whitesmoke: "#f5f5f5", yellow: "#ffff00", yellowgreen: "#9acd32" }; (function(Processing) { var unsupportedP5 = ("open() createOutput() createInput() BufferedReader sel ectFolder() " + "dataPath() createWriter() selectOutput() beginRecord() " + "sav eStream() endRecord() selectInput() saveBytes() createReader() " + "beginRaw() e ndRaw() PrintWriter delay()").split(" "), count = unsupportedP5.length, prettyName, p5Name; function createUnsupportedFunc(n) { return function() { throw "Processing.js does not support " + n + "."; } } while (count--) { prettyName = unsupportedP5[count]; p5Name = prettyName.replace("()", ""); Processing[p5Name] = createUnsupportedFunc(prettyName) } })(defaultScope); defaultScope.defineProperty(defaultScope, "screenWidth", { get: function() { return window.innerWidth }

}); defaultScope.defineProperty(defaultScope, "screenHeight", { get: function() { return window.innerHeight } }); defaultScope.defineProperty(defaultScope, "online", { get: function() { return true } }); var processingInstances = []; var processingInstanceIds = {}; var removeInstance = function(id) { processingInstances.splice(processingInstanceIds[id], 1); delete processingInstanceIds[id] }; var addInstance = function(processing) { if (processing.externals.canvas.id === undef || !processing.externals.canvas .id.length) processing.externals.canvas.id = "__processing" + processingInstance s.length; processingInstanceIds[processing.externals.canvas.id] = processingInstances. length; processingInstances.push(processing) }; function computeFontMetrics(pfont) { var emQuad = 250, correctionFactor = pfont.size / emQuad, canvas = document.createElement("canvas"); canvas.width = 2 * emQuad; canvas.height = 2 * emQuad; canvas.style.opacity = 0; var cfmFont = pfont.getCSSDefinition(emQuad + "px", "normal"), ctx = canvas.getContext("2d"); ctx.font = cfmFont; var protrusions = "dbflkhyjqpg"; canvas.width = ctx.measureText(protrusions).width; ctx.font = cfmFont; var leadDiv = document.createElement("div"); leadDiv.style.position = "absolute"; leadDiv.style.opacity = 0; leadDiv.style.fontFamily = '"' + pfont.name + '"'; leadDiv.style.fontSize = emQuad + "px"; leadDiv.innerHTML = protrusions + "<br/>" + protrusions; document.body.appendChild(leadDiv); var w = canvas.width, h = canvas.height, baseline = h / 2; ctx.fillStyle = "white"; ctx.fillRect(0, 0, w, h); ctx.fillStyle = "black"; ctx.fillText(protrusions, 0, baseline); var pixelData = ctx.getImageData(0, 0, w, h).data; var i = 0, w4 = w * 4, len = pixelData.length; while (++i < len && pixelData[i] === 255) nop(); var ascent = Math.round(i / w4); i = len - 1;

while (--i > 0 && pixelData[i] === 255) nop(); var descent = Math.round(i / w4); pfont.ascent = correctionFactor * (baseline - ascent); pfont.descent = correctionFactor * (descent - baseline); if (document.defaultView.getComputedStyle) { var leadDivHeight = document.defaultView.getComputedStyle(leadDiv, null).g etPropertyValue("height"); leadDivHeight = correctionFactor * leadDivHeight.replace("px", ""); if (leadDivHeight >= pfont.size * 2) pfont.leading = Math.round(leadDivHei ght / 2) } document.body.removeChild(leadDiv); if (pfont.caching) return ctx } function PFont(name, size) { if (name === undef) name = ""; this.name = name; if (size === undef) size = 0; this.size = size; this.glyph = false; this.ascent = 0; this.descent = 0; this.leading = 1.2 * size; var illegalIndicator = name.indexOf(" Italic Bold"); if (illegalIndicator !== -1) name = name.substring(0, illegalIndicator); this.style = "normal"; var italicsIndicator = name.indexOf(" Italic"); if (italicsIndicator !== -1) { name = name.substring(0, italicsIndicator); this.style = "italic" } this.weight = "normal"; var boldIndicator = name.indexOf(" Bold"); if (boldIndicator !== -1) { name = name.substring(0, boldIndicator); this.weight = "bold" } this.family = "sans-serif"; if (name !== undef) switch (name) { case "sans-serif": case "serif": case "monospace": case "fantasy": case "cursive": this.family = name; break; default: this.family = '"' + name + '", sans-serif'; break } this.context2d = computeFontMetrics(this); this.css = this.getCSSDefinition(); if (this.context2d) this.context2d.font = this.css } PFont.prototype.caching = true; PFont.prototype.getCSSDefinition = function(fontSize, lineHeight) { if (fontSize === undef) fontSize = this.size + "px"; if (lineHeight === undef) lineHeight = this.leading + "px"; var components = [this.style, "normal", this.weight, fontSize + "/" + lineHe ight, this.family];

return components.join(" ") }; PFont.prototype.measureTextWidth = function(string) { return this.context2d.measureText(string).width }; PFont.prototype.measureTextWidthFallback = function(string) { var canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"); ctx.font = this.css; return ctx.measureText(string).width }; PFont.PFontCache = { length: 0 }; PFont.get = function(fontName, fontSize) { fontSize = (fontSize * 10 + 0.5 | 0) / 10; var cache = PFont.PFontCache, idx = fontName + "/" + fontSize; if (!cache[idx]) { cache[idx] = new PFont(fontName, fontSize); cache.length++; if (cache.length === 50) { PFont.prototype.measureTextWidth = PFont.prototype.measureTextWidthFallb ack; PFont.prototype.caching = false; var entry; for (entry in cache) if (entry !== "length") cache[entry].context2d = nu ll; return new PFont(fontName, fontSize) } if (cache.length === 400) { PFont.PFontCache = {}; PFont.get = PFont.getFallback; return new PFont(fontName, fontSize) } } return cache[idx] }; PFont.getFallback = function(fontName, fontSize) { return new PFont(fontName, fontSize) }; PFont.list = function() { return ["sans-serif", "serif", "monospace", "fantasy", "cursive"] }; PFont.preloading = { template: {}, initialized: false, initialize: function() { var generateTinyFont = function() { var encoded = "#E3KAI2wAgT1MvMg7Eo3VmNtYX7ABi3CxnbHlm" + "7Abw3kaGVhZ7AC s3OGhoZWE7A53CRobXR47AY3" + "AGbG9jYQ7G03Bm1heH7ABC3CBuYW1l7Ae3AgcG" + "9zd7AI3A E#B3AQ2kgTY18PPPUACwAg3ALSRoo3" + "#yld0xg32QAB77#E777773B#E3C#I#Q77773E#" + "Q7 777777772CMAIw7AB77732B#M#Q3wAB#g3B#" + "E#E2BB//82BB////w#B7#gAEg3E77x2B32B#E#" + "Q#MTcBAQ32gAe#M#QQJ#E32M#QQJ#I#g32Q77#"; var expand = function(input) { return "AAAAAAAA".substr(~~input ? 7 - input : 6) }; return encoded.replace(/[#237]/g, expand) }; var fontface = document.createElement("style");

fontface.setAttribute("type", "text/css"); fontface.innerHTML = "@font-face {\n" + ' font-family: "PjsEmptyFont";' + "\n" + " src: url('data:application/x-font-ttf;base64," + generateTinyFont() + "')\n" + " format('truetype');\n" + "}"; document.head.appendChild(fontface); var element = document.createElement("span"); element.style.cssText = 'position: absolute; top: 0; left: 0; opacity: 0; font-family: "PjsEmptyFont", fantasy;'; element.innerHTML = "AAAAAAAA"; document.body.appendChild(element); this.template = element; this.initialized = true }, getElementWidth: function(element) { return document.defaultView.getComputedStyle(element, "").getPropertyValue ("width") }, timeAttempted: 0, pending: function(intervallength) { if (!this.initialized) this.initialize(); var element, computedWidthFont, computedWidthRef = this.getElementWidth(th is.template); for (var i = 0; i < this.fontList.length; i++) { element = this.fontList[i]; computedWidthFont = this.getElementWidth(element); if (this.timeAttempted < 4E3 && computedWidthFont === computedWidthRef) { this.timeAttempted += intervallength; return true } else { document.body.removeChild(element); this.fontList.splice(i--, 1); this.timeAttempted = 0 } } if (this.fontList.length === 0) return false; return true }, fontList: [], addedList: {}, add: function(fontSrc) { if (!this.initialized) this.initialize(); var fontName = typeof fontSrc === "object" ? fontSrc.fontFace : fontSrc, fontUrl = typeof fontSrc === "object" ? fontSrc.url : fontSrc; if (this.addedList[fontName]) return; var style = document.createElement("style"); style.setAttribute("type", "text/css"); style.innerHTML = "@font-face{\n font-family: '" + fontName + "';\n src: url('" + fontUrl + "');\n}\n"; document.head.appendChild(style); this.addedList[fontName] = true; var element = document.createElement("span"); element.style.cssText = "position: absolute; top: 0; left: 0; opacity: 0;" ; element.style.fontFamily = '"' + fontName + '", "PjsEmptyFont", fantasy'; element.innerHTML = "AAAAAAAA"; document.body.appendChild(element); this.fontList.push(element) } };

defaultScope.PFont = PFont; var Processing = this.Processing = function(aCanvas, aCode) { if (! (this instanceof Processing)) throw "called Processing constructor as if it were a function: missing 'new'."; var curElement, pgraphicsMode = aCanvas === undef && aCode === undef; if (pgraphicsMode) curElement = document.createElement("canvas"); else curElement = typeof aCanvas === "string" ? document.getElementById(aCan vas) : aCanvas; if (! (curElement instanceof HTMLCanvasElement)) throw "called Processing co nstructor without passing canvas element reference or id."; function unimplemented(s) { Processing.debug("Unimplemented - " + s) } var p = this; p.externals = { canvas: curElement, context: undef, sketch: undef }; p.name = "Processing.js Instance"; p.use3DContext = false; p.focused = false; p.breakShape = false; p.glyphTable = {}; p.pmouseX = 0; p.pmouseY = 0; p.mouseX = 0; p.mouseY = 0; p.mouseButton = 0; p.mouseScroll = 0; p.mouseClicked = undef; p.mouseDragged = undef; p.mouseMoved = undef; p.mousePressed = undef; p.mouseReleased = undef; p.mouseScrolled = undef; p.mouseOver = undef; p.mouseOut = undef; p.touchStart = undef; p.touchEnd = undef; p.touchMove = undef; p.touchCancel = undef; p.key = undef; p.keyCode = undef; p.keyPressed = nop; p.keyReleased = nop; p.keyTyped = nop; p.draw = undef; p.setup = undef; p.__mousePressed = false; p.__keyPressed = false; p.__frameRate = 60; p.frameCount = 0; p.width = 100; p.height = 100; var curContext, curSketch, drawing, online = true, doFill = true, fillStyle = [1, 1, 1, 1],

currentFillColor = 4294967295, isFillDirty = true, doStroke = true, strokeStyle = [0, 0, 0, 1], currentStrokeColor = 4278190080, isStrokeDirty = true, lineWidth = 1, loopStarted = false, renderSmooth = false, doLoop = true, looping = 0, curRectMode = 0, curEllipseMode = 3, normalX = 0, normalY = 0, normalZ = 0, normalMode = 0, curFrameRate = 60, curMsPerFrame = 1E3 / curFrameRate, curCursor = 'default', oldCursor = curElement.style.cursor, curShape = 20, curShapeCount = 0, curvePoints = [], curTightness = 0, curveDet = 20, curveInited = false, backgroundObj = -3355444, bezDetail = 20, colorModeA = 255, colorModeX = 255, colorModeY = 255, colorModeZ = 255, pathOpen = false, mouseDragging = false, pmouseXLastFrame = 0, pmouseYLastFrame = 0, curColorMode = 1, curTint = null, curTint3d = null, getLoaded = false, start = Date.now(), timeSinceLastFPS = start, framesSinceLastFPS = 0, textcanvas, curveBasisMatrix, curveToBezierMatrix, curveDrawMatrix, bezier DrawMatrix, bezierBasisInverse, bezierBasisMatrix, curContextCache = { attributes: {}, locations: {} }, programObject3D, programObject2D, programObjectUnlitShape, boxBuffer, boxN ormBuffer, boxOutlineBuffer, rectBuffer, rectNormBuffer, sphereBuffer, lineBuffe r, fillBuffer, fillColorBuffer, strokeColorBuffer, pointBuffer, shapeTexVBO, can Tex, textTex, curTexture = { width: 0, height: 0 }, curTextureMode = 2, usingTexture = false, textBuffer, textureBuffer, indexBuffer, horizontalTextAlignment = 37, verticalTextAlignment = 0,

textMode = 4, curFontName = "Arial", curTextSize = 12, curTextAscent = 9, curTextDescent = 2, curTextLeading = 14, curTextFont = PFont.get(curFontName, curTextSize), originalContext, proxyContext = null, isContextReplaced = false, setPixelsCached, maxPixelsCached = 1E3, pressedKeysMap = [], lastPressedKeyCode = null, codedKeys = [16, 17, 18, 20, 33, 34, 35, 36, 37, 38, 39, 40, 144, 155, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 157]; var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop; if (document.defaultView && document.defaultView.getComputedStyle) { stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(curEleme nt, null)["paddingLeft"], 10) || 0; stylePaddingTop = parseInt(document.defaultView.getComputedStyle(curElemen t, null)["paddingTop"], 10) || 0; styleBorderLeft = parseInt(document.defaultView.getComputedStyle(curElemen t, null)["borderLeftWidth"], 10) || 0; styleBorderTop = parseInt(document.defaultView.getComputedStyle(curElement , null)["borderTopWidth"], 10) || 0 } var lightCount = 0; var sphereDetailV = 0, sphereDetailU = 0, sphereX = [], sphereY = [], sphereZ = [], sinLUT = new Float32Array(720), cosLUT = new Float32Array(720), sphereVerts, sphereNorms; var cam, cameraInv, modelView, modelViewInv, userMatrixStack, userReverseMat rixStack, inverseCopy, projection, manipulatingCamera = false, frustumMode = false, cameraFOV = 60 * (Math.PI / 180), cameraX = p.width / 2, cameraY = p.height / 2, cameraZ = cameraY / Math.tan(cameraFOV / 2), cameraNear = cameraZ / 10, cameraFar = cameraZ * 10, cameraAspect = p.width / p.height; var vertArray = [], curveVertArray = [], curveVertCount = 0, isCurve = false, isBezier = false, firstVert = true; var curShapeMode = 0; var styleArray = []; var boxVerts = new Float32Array([0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5 , -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0 .5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0 .5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,

-0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5]); var boxOutlineVerts = new Float32Array([0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5 , 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5]); var boxNorms = new Float32Array([0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0]); var rectVerts = new Float32Array([0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0]); var rectNorms = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); var vertexShaderSrcUnlitShape = "varying vec4 vFrontColor;" + "attribute vec 3 aVertex;" + "attribute vec4 aColor;" + "uniform mat4 uView;" + "uniform mat4 u Projection;" + "uniform float uPointSize;" + "void main(void) {" + " vFrontColo r = aColor;" + " gl_PointSize = uPointSize;" + " gl_Position = uProjection * u View * vec4(aVertex, 1.0);" + "}"; var fragmentShaderSrcUnlitShape = "#ifdef GL_ES\n" + "precision highp float; \n" + "#endif\n" + "varying vec4 vFrontColor;" + "uniform bool uSmooth;" + "void main(void){" + " if(uSmooth == true){" + " float dist = distance(gl_PointCo ord, vec2(0.5));" + " if(dist > 0.5){" + " discard;" + " }" + " }" + " gl_FragColor = vFrontColor;" + "}"; var vertexShaderSrc2D = "varying vec4 vFrontColor;" + "attribute vec3 aVerte x;" + "attribute vec2 aTextureCoord;" + "uniform vec4 uColor;" + "uniform mat4 u Model;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform float u PointSize;" + "varying vec2 vTextureCoord;" + "void main(void) {" + " gl_PointS ize = uPointSize;" + " vFrontColor = uColor;" + " gl_Position = uProjection * uView * uModel * vec4(aVertex, 1.0);" + " vTextureCoord = aTextureCoord;" + "}" ; var fragmentShaderSrc2D = "#ifdef GL_ES\n" + "precision highp float;\n" + "# endif\n" + "varying vec4 vFrontColor;" + "varying vec2 vTextureCoord;" + "unifor m sampler2D uSampler;" + "uniform int uIsDrawingText;" + "uniform bool uSmooth;" + "void main(void){" + " if(uSmooth == true){" + " float dist = distance(gl _PointCoord, vec2(0.5));" + " if(dist > 0.5){" + " discard;" + " }" + " }" + " if(uIsDrawingText == 1){" + " float alpha = texture2D(uSampler, v TextureCoord).a;" + " gl_FragColor = vec4(vFrontColor.rgb * alpha, alpha);" + " }" + " else{" + " gl_FragColor = vFrontColor;" + " }" + "}"; var webglMaxTempsWorkaround = /Windows/.test(navigator.userAgent); var vertexShaderSrc3D = "varying vec4 vFrontColor;" + "attribute vec3 aVerte x;" + "attribute vec3 aNormal;" + "attribute vec4 aColor;" + "attribute vec2 aTe xture;" + "varying vec2 vTexture;" + "uniform vec4 uColor;" + "uniform bool uU singMat;" + "uniform vec3 uSpecular;" + "uniform vec3 uMaterialEmissive;" + "uni form vec3 uMaterialAmbient;" + "uniform vec3 uMaterialSpecular;" + "uniform floa t uShininess;" + "uniform mat4 uModel;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform mat4 uNormalTransform;" + "uniform int uLightCount;" + "uniform vec3 uFalloff;" + "struct Light {" + " int type;" + " vec3 color;" + " vec3 position;" + " vec3 direction;" + " float angle;" + " vec3 halfVector ;" + " float concentration;" + "};" + "uniform Light uLights0;" + "uniform Ligh t uLights1;" + "uniform Light uLights2;" + "uniform Light uLights3;" + "uniform Light uLights4;" + "uniform Light uLights5;" + "uniform Light uLights6;" + "unif orm Light uLights7;" + "Light getLight(int index){" + " if(index == 0) return u Lights0;" + " if(index == 1) return uLights1;" + " if(index == 2) return uLigh ts2;" + " if(index == 3) return uLights3;" + " if(index == 4) return uLights4; " + " if(index == 5) return uLights5;" + " if(index == 6) return uLights6;" + " return uLights7;" + "}" + "void AmbientLight( inout vec3 totalAmbient, in vec 3 ecPos, in Light light ) {" + " float d = length( light.position - ecPos );" +

" float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2 ] * d * d ));" + " totalAmbient += light.color * attenuation;" + "}" + "void Di rectionalLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecP os, in Light light ) {" + " float powerFactor = 0.0;" + " float nDotVP = max(0 .0, dot( vertNormal, normalize(-light.position) ));" + " float nDotVH = max(0.0 , dot( vertNormal, normalize(-light.position-normalize(ecPos) )));" + " if( nDo tVP != 0.0 ){" + " powerFactor = pow( nDotVH, uShininess );" + " }" + " col += light.color * nDotVP;" + " spec += uSpecular * powerFactor;" + "}" + "void PointLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float powerFactor;" + " vec3 VP = light.position - ec Pos;" + " float d = length( VP ); " + " VP = normalize( VP );" + " float atte nuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + " float nDotVP = max( 0.0, dot( vertNormal, VP ));" + " vec3 halfVector = n ormalize( VP - normalize(ecPos) );" + " float nDotHV = max( 0.0, dot( vertNorma l, halfVector ));" + " if( nDotVP == 0.0 ) {" + " powerFactor = 0.0;" + " } " + " else {" + " powerFactor = pow( nDotHV, uShininess );" + " }" + " spe c += uSpecular * powerFactor * attenuation;" + " col += light.color * nDotVP * attenuation;" + "}" + "void SpotLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float spotAttenuation;" + " float powerFactor = 0.0;" + " vec3 VP = light.position - ecPos;" + " vec3 ldi r = normalize( -light.direction );" + " float d = length( VP );" + " VP = norm alize( VP );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ) );" + " float spotDot = dot( VP, ldir );" + (webglMa xTempsWorkaround ? " spotAttenuation = 1.0; " : " if( spotDot > cos( light.ang le ) ) {" + " spotAttenuation = pow( spotDot, light.concentration );" + " }" + " else{" + " spotAttenuation = 0.0;" + " }" + " attenuation *= spotAtte nuation;" + "") + " float nDotVP = max( 0.0, dot( vertNormal, VP ) );" + " vec 3 halfVector = normalize( VP - normalize(ecPos) );" + " float nDotHV = max( 0.0 , dot( vertNormal, halfVector ) );" + " if( nDotVP != 0.0 ) {" + " powerFact or = pow( nDotHV, uShininess );" + " }" + " spec += uSpecular * powerFactor * attenuation;" + " col += light.color * nDotVP * attenuation;" + "}" + "void mai n(void) {" + " vec3 finalAmbient = vec3( 0.0 );" + " vec3 finalDiffuse = vec3( 0.0 );" + " vec3 finalSpecular = vec3( 0.0 );" + " vec4 col = uColor;" + " i f ( uColor[0] == -1.0 ){" + " col = aColor;" + " }" + " vec3 norm = normali ze(vec3( uNormalTransform * vec4( aNormal, 0.0 ) ));" + " vec4 ecPos4 = uView * uModel * vec4(aVertex, 1.0);" + " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + " if( uLightCount == 0 ) {" + " vFrontColor = col + vec4(uMaterialSpecular, 1.0 );" + " }" + " else {" + " for( int i = 0; i < 8; i++ ) {" + " Light l = getLight(i);" + " if( i >= uLightCount ){" + " break;" + " } " + " if( l.type == 0 ) {" + " AmbientLight( finalAmbient, ecPos, l );" + " }" + " else if( l.type == 1 ) {" + " DirectionalLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " else if( l. type == 2 ) {" + " PointLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " else {" + " SpotLight( finalDiffuse, finalSpec ular, norm, ecPos, l );" + " }" + " }" + " if( uUsingMat == false ) {" + " vFrontColor = vec4(" + " vec3( col ) * finalAmbient +" + " vec3( col ) * finalDiffuse +" + " vec3( col ) * finalSpecular," + " col[3] );" + " }" + " else{" + " vFrontColor = vec4( " + " uMateri alEmissive + " + " (vec3(col) * uMaterialAmbient * finalAmbient ) + " + " (vec3(col) * finalDiffuse) + " + " (uMaterialSpecular * finalSpecula r), " + " col[3] );" + " }" + " }" + " vTexture.xy = aTexture.xy;" + " gl_Position = uProjection * uView * uModel * vec4( aVertex, 1.0 );" + "}"; var fragmentShaderSrc3D = "#ifdef GL_ES\n" + "precision highp float;\n" + "# endif\n" + "varying vec4 vFrontColor;" + "uniform sampler2D uSampler;" + "unifor m bool uUsingTexture;" + "varying vec2 vTexture;" + "void main(void){" + " if( uUsingTexture ){" + " gl_FragColor = vec4(texture2D(uSampler, vTexture.xy)) * vFrontColor;" + " }" + " else{" + " gl_FragColor = vFrontColor;" + " }" + "}"; function uniformf(cacheId, programObj, varName, varValue) {

var varLocation = curContextCache.locations[cacheId]; if (varLocation === undef) { varLocation = curContext.getUniformLocation(programObj, varName); curContextCache.locations[cacheId] = varLocation } if (varLocation !== null) if (varValue.length === 4) curContext.uniform4fv (varLocation, varValue); else if (varValue.length === 3) curContext.uniform3fv(varLocation, varValu e); else if (varValue.length === 2) curContext.uniform2fv(varLocation, varValu e); else curContext.uniform1f(varLocation, varValue) } function uniformi(cacheId, programObj, varName, varValue) { var varLocation = curContextCache.locations[cacheId]; if (varLocation === undef) { varLocation = curContext.getUniformLocation(programObj, varName); curContextCache.locations[cacheId] = varLocation } if (varLocation !== null) if (varValue.length === 4) curContext.uniform4iv (varLocation, varValue); else if (varValue.length === 3) curContext.uniform3iv(varLocation, varValu e); else if (varValue.length === 2) curContext.uniform2iv(varLocation, varValu e); else curContext.uniform1i(varLocation, varValue) } function uniformMatrix(cacheId, programObj, varName, transpose, matrix) { var varLocation = curContextCache.locations[cacheId]; if (varLocation === undef) { varLocation = curContext.getUniformLocation(programObj, varName); curContextCache.locations[cacheId] = varLocation } if (varLocation !== -1) if (matrix.length === 16) curContext.uniformMatrix 4fv(varLocation, transpose, matrix); else if (matrix.length === 9) curContext.uniformMatrix3fv(varLocation, tra nspose, matrix); else curContext.uniformMatrix2fv(varLocation, transpose, matrix) } function vertexAttribPointer(cacheId, programObj, varName, size, VBO) { var varLocation = curContextCache.attributes[cacheId]; if (varLocation === undef) { varLocation = curContext.getAttribLocation(programObj, varName); curContextCache.attributes[cacheId] = varLocation } if (varLocation !== -1) { curContext.bindBuffer(curContext.ARRAY_BUFFER, VBO); curContext.vertexAttribPointer(varLocation, size, curContext.FLOAT, fals e, 0, 0); curContext.enableVertexAttribArray(varLocation) } } function disableVertexAttribPointer(cacheId, programObj, varName) { var varLocation = curContextCache.attributes[cacheId]; if (varLocation === undef) { varLocation = curContext.getAttribLocation(programObj, varName); curContextCache.attributes[cacheId] = varLocation } if (varLocation !== -1) curContext.disableVertexAttribArray(varLocation) }

var createProgramObject = function(curContext, vetexShaderSource, fragmentSh aderSource) { var vertexShaderObject = curContext.createShader(curContext.VERTEX_SHADER) ; curContext.shaderSource(vertexShaderObject, vetexShaderSource); curContext.compileShader(vertexShaderObject); if (!curContext.getShaderParameter(vertexShaderObject, curContext.COMPILE_ STATUS)) throw curContext.getShaderInfoLog(vertexShaderObject); var fragmentShaderObject = curContext.createShader(curContext.FRAGMENT_SHA DER); curContext.shaderSource(fragmentShaderObject, fragmentShaderSource); curContext.compileShader(fragmentShaderObject); if (!curContext.getShaderParameter(fragmentShaderObject, curContext.COMPIL E_STATUS)) throw curContext.getShaderInfoLog(fragmentShaderObject); var programObject = curContext.createProgram(); curContext.attachShader(programObject, vertexShaderObject); curContext.attachShader(programObject, fragmentShaderObject); curContext.linkProgram(programObject); if (!curContext.getProgramParameter(programObject, curContext.LINK_STATUS) ) throw "Error linking shaders."; return programObject }; var imageModeCorner = function(x, y, w, h, whAreSizes) { return { x: x, y: y, w: w, h: h } }; var imageModeConvert = imageModeCorner; var imageModeCorners = function(x, y, w, h, whAreSizes) { return { x: x, y: y, w: whAreSizes ? w : w - x, h: whAreSizes ? h : h - y } }; var imageModeCenter = function(x, y, w, h, whAreSizes) { return { x: x - w / 2, y: y - h / 2, w: w, h: h } }; var DrawingShared = function() {}; var Drawing2D = function() {}; var Drawing3D = function() {}; var DrawingPre = function() {}; Drawing2D.prototype = new DrawingShared; Drawing2D.prototype.constructor = Drawing2D; Drawing3D.prototype = new DrawingShared; Drawing3D.prototype.constructor = Drawing3D; DrawingPre.prototype = new DrawingShared; DrawingPre.prototype.constructor = DrawingPre; DrawingShared.prototype.a3DOnlyFunction = nop; var charMap = {}; var Char = p.Character = function(chr) {

if (typeof chr === "string" && chr.length === 1) this.code = chr.charCodeA t(0); else if (typeof chr === "number") this.code = chr; else if (chr instanceof Char) this.code = chr; else this.code = NaN; return charMap[this.code] === undef ? charMap[this.code] = this : charMap[ this.code] }; Char.prototype.toString = function() { return String.fromCharCode(this.code) }; Char.prototype.valueOf = function() { return this.code }; var PShape = p.PShape = function(family) { this.family = family || 0; this.visible = true; this.style = true; this.children = []; this.nameTable = []; this.params = []; this.name = ""; this.image = null; this.matrix = null; this.kind = null; this.close = null; this.width = null; this.height = null; this.parent = null }; PShape.prototype = { isVisible: function() { return this.visible }, setVisible: function(visible) { this.visible = visible }, disableStyle: function() { this.style = false; for (var i = 0, j = this.children.length; i < j; i++) this.children[i].d isableStyle() }, enableStyle: function() { this.style = true; for (var i = 0, j = this.children.length; i < j; i++) this.children[i].e nableStyle() }, getFamily: function() { return this.family }, getWidth: function() { return this.width }, getHeight: function() { return this.height }, setName: function(name) { this.name = name }, getName: function() {

return this.name }, draw: function(renderContext) { renderContext = renderContext || p; if (this.visible) { this.pre(renderContext); this.drawImpl(renderContext); this.post(renderContext) } }, drawImpl: function(renderContext) { if (this.family === 0) this.drawGroup(renderContext); else if (this.family === 1) this.drawPrimitive(renderContext); else if (this.family === 3) this.drawGeometry(renderContext); else if (this.family === 21) this.drawPath(renderContext) }, drawPath: function(renderContext) { var i, j; if (this.vertices.length === 0) return; renderContext.beginShape(); if (this.vertexCodes.length === 0) if (this.vertices[0].length === 2) fo r (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertic es[i][0], this.vertices[i][1]); else for (i = 0, j = this.vertices.length; i < j; i++) renderContext.ver tex(this.vertices[i][0], this.vertices[i][1], this.vertices[i][2]); else { var index = 0; if (this.vertices[0].length === 2) for (i = 0, j = this.vertexCodes.le ngth; i < j; i++) if (this.vertexCodes[i] === 0) { renderContext.vertex(this.vertices[index][0], this.vertices[index][1 ], this.vertices[index]["moveTo"]); renderContext.breakShape = false; index++ } else if (this.vertexCodes[i] === 1) { renderContext.bezierVertex(this.vertices[index + 0][0], this.vertice s[index + 0][1], this.vertices[index + 1][0], this.vertices[index + 1][1], this. vertices[index + 2][0], this.vertices[index + 2][1]); index += 3 } else if (this.vertexCodes[i] === 2) { renderContext.curveVertex(this.vertices[index][0], this.vertices[ind ex][1]); index++ } else { if (this.vertexCodes[i] === 3) renderContext.breakShape = true } else for (i = 0, j = this.vertexCodes.length; i < j; i++) if (this.v ertexCodes[i] === 0) { renderContext.vertex(this.vertices[index][0], this.vertices[index][1 ], this.vertices[index][2]); if (this.vertices[index]["moveTo"] === true) vertArray[vertArray.len gth - 1]["moveTo"] = true; else if (this.vertices[index]["moveTo"] === false) vertArray[vertArr ay.length - 1]["moveTo"] = false; renderContext.breakShape = false } else if (this.vertexCodes[i] === 1) { renderContext.bezierVertex(this.vertices[index + 0][0], this.vertice s[index + 0][1], this.vertices[index + 0][2], this.vertices[index + 1][0], this. vertices[index + 1][1], this.vertices[index + 1][2], this.vertices[index + 2][0] , this.vertices[index + 2][1], this.vertices[index + 2][2]); index += 3 } else if (this.vertexCodes[i] === 2) {

renderContext.curveVertex(this.vertices[index][0], this.vertices[ind ex][1], this.vertices[index][2]); index++ } else if (this.vertexCodes[i] === 3) renderContext.breakShape = true } renderContext.endShape(this.close ? 2 : 1) }, drawGeometry: function(renderContext) { var i, j; renderContext.beginShape(this.kind); if (this.style) for (i = 0, j = this.vertices.length; i < j; i++) render Context.vertex(this.vertices[i]); else for (i = 0, j = this.vertices.length; i < j; i++) { var vert = this.vertices[i]; if (vert[2] === 0) renderContext.vertex(vert[0], vert[1]); else renderContext.vertex(vert[0], vert[1], vert[2]) } renderContext.endShape() }, drawGroup: function(renderContext) { for (var i = 0, j = this.children.length; i < j; i++) this.children[i].d raw(renderContext) }, drawPrimitive: function(renderContext) { if (this.kind === 2) renderContext.point(this.params[0], this.params[1]) ; else if (this.kind === 4) if (this.params.length === 4) renderContext.li ne(this.params[0], this.params[1], this.params[2], this.params[3]); else renderContext.line(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); else if (this.kind === 8) renderContext.triangle(this.params[0], this.pa rams[1], this.params[2], this.params[3], this.params[4], this.params[5]); else if (this.kind === 16) renderContext.quad(this.params[0], this.param s[1], this.params[2], this.params[3], this.params[4], this.params[5], this.param s[6], this.params[7]); else if (this.kind === 30) if (this.image !== null) { var imMode = imageModeConvert; renderContext.imageMode(0); renderContext.image(this.image, this.params[0], this.params[1], this.p arams[2], this.params[3]); imageModeConvert = imMode } else { var rcMode = curRectMode; renderContext.rectMode(0); renderContext.rect(this.params[0], this.params[1], this.params[2], thi s.params[3]); curRectMode = rcMode } else if (this.kind === 31) { var elMode = curEllipseMode; renderContext.ellipseMode(0); renderContext.ellipse(this.params[0], this.params[1], this.params[2], this.params[3]); curEllipseMode = elMode } else if (this.kind === 32) { var eMode = curEllipseMode; renderContext.ellipseMode(0); renderContext.arc(this.params[0], this.params[1], this.params[2], this .params[3], this.params[4], this.params[5]); curEllipseMode = eMode } else if (this.kind === 41) if (this.params.length === 1) renderContext

.box(this.params[0]); else renderContext.box(this.params[0], this.params[1], this.params[2]); else if (this.kind === 40) renderContext.sphere(this.params[0]) }, pre: function(renderContext) { if (this.matrix) { renderContext.pushMatrix(); renderContext.transform(this.matrix) } if (this.style) { renderContext.pushStyle(); this.styles(renderContext) } }, post: function(renderContext) { if (this.matrix) renderContext.popMatrix(); if (this.style) renderContext.popStyle() }, styles: function(renderContext) { if (this.stroke) { renderContext.stroke(this.strokeColor); renderContext.strokeWeight(this.strokeWeight); renderContext.strokeCap(this.strokeCap); renderContext.strokeJoin(this.strokeJoin) } else renderContext.noStroke(); if (this.fill) renderContext.fill(this.fillColor); else renderContext.noFill() }, getChild: function(child) { var i, j; if (typeof child === "number") return this.children[child]; var found; if (child === "" || this.name === child) return this; if (this.nameTable.length > 0) { for (i = 0, j = this.nameTable.length; i < j || found; i++) if (this.n ameTable[i].getName === child) { found = this.nameTable[i]; break } if (found) return found } for (i = 0, j = this.children.length; i < j; i++) { found = this.children[i].getChild(child); if (found) return found } return null }, getChildCount: function() { return this.children.length }, addChild: function(child) { this.children.push(child); child.parent = this; if (child.getName() !== null) this.addName(child.getName(), child) }, addName: function(name, shape) { if (this.parent !== null) this.parent.addName(name, shape); else this.nameTable.push([name, shape]) }, translate: function() {

if (arguments.length === 2) { this.checkMatrix(2); this.matrix.translate(arguments[0], arguments[1]) } else { this.checkMatrix(3); this.matrix.translate(arguments[0], arguments[1], 0) } }, checkMatrix: function(dimensions) { if (this.matrix === null) if (dimensions === 2) this.matrix = new p.PMat rix2D; else this.matrix = new p.PMatrix3D; else if (dimensions === 3 && this.matrix instanceof p.PMatrix2D) this.ma trix = new p.PMatrix3D }, rotateX: function(angle) { this.rotate(angle, 1, 0, 0) }, rotateY: function(angle) { this.rotate(angle, 0, 1, 0) }, rotateZ: function(angle) { this.rotate(angle, 0, 0, 1) }, rotate: function() { if (arguments.length === 1) { this.checkMatrix(2); this.matrix.rotate(arguments[0]) } else { this.checkMatrix(3); this.matrix.rotate(arguments[0], arguments[1], arguments[2], arguments [3]) } }, scale: function() { if (arguments.length === 2) { this.checkMatrix(2); this.matrix.scale(arguments[0], arguments[1]) } else if (arguments.length === 3) { this.checkMatrix(2); this.matrix.scale(arguments[0], arguments[1], arguments[2]) } else { this.checkMatrix(2); this.matrix.scale(arguments[0]) } }, resetMatrix: function() { this.checkMatrix(2); this.matrix.reset() }, applyMatrix: function(matrix) { if (arguments.length === 1) this.applyMatrix(matrix.elements[0], matrix. elements[1], 0, matrix.elements[2], matrix.elements[3], matrix.elements[4], 0, m atrix.elements[5], 0, 0, 1, 0, 0, 0, 0, 1); else if (arguments.length === 6) { this.checkMatrix(2); this.matrix.apply(arguments[0], arguments[1], arguments[2], 0, argumen ts[3], arguments[4], arguments[5], 0, 0, 0, 1, 0, 0, 0, 0, 1) } else if (arguments.length === 16) { this.checkMatrix(3);

this.matrix.apply(arguments[0], arguments[1], arguments[2], arguments[ 3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], argume nts[9], arguments[10], arguments[11], arguments[12], arguments[13], arguments[14 ], arguments[15]) } } }; var PShapeSVG = p.PShapeSVG = function() { p.PShape.call(this); if (arguments.length === 1) { this.element = arguments[0]; this.vertexCodes = []; this.vertices = []; this.opacity = 1; this.stroke = false; this.strokeColor = 4278190080; this.strokeWeight = 1; this.strokeCap = 'butt'; this.strokeJoin = 'miter'; this.strokeGradient = null; this.strokeGradientPaint = null; this.strokeName = null; this.strokeOpacity = 1; this.fill = true; this.fillColor = 4278190080; this.fillGradient = null; this.fillGradientPaint = null; this.fillName = null; this.fillOpacity = 1; if (this.element.getName() !== "svg") throw "root is not <svg>, it's <" + this.element.getName() + ">"; } else if (arguments.length === 2) if (typeof arguments[1] === "string") { if (arguments[1].indexOf(".svg") > -1) { this.element = new p.XMLElement(p, arguments[1]); this.vertexCodes = []; this.vertices = []; this.opacity = 1; this.stroke = false; this.strokeColor = 4278190080; this.strokeWeight = 1; this.strokeCap = 'butt'; this.strokeJoin = 'miter'; this.strokeGradient = ""; this.strokeGradientPaint = ""; this.strokeName = ""; this.strokeOpacity = 1; this.fill = true; this.fillColor = 4278190080; this.fillGradient = null; this.fillGradientPaint = null; this.fillOpacity = 1 } } else if (arguments[0]) { this.element = arguments[1]; this.vertexCodes = arguments[0].vertexCodes.slice(); this.vertices = arguments[0].vertices.slice(); this.stroke = arguments[0].stroke; this.strokeColor = arguments[0].strokeColor; this.strokeWeight = arguments[0].strokeWeight; this.strokeCap = arguments[0].strokeCap;

this.strokeJoin = arguments[0].strokeJoin; this.strokeGradient = arguments[0].strokeGradient; this.strokeGradientPaint = arguments[0].strokeGradientPaint; this.strokeName = arguments[0].strokeName; this.fill = arguments[0].fill; this.fillColor = arguments[0].fillColor; this.fillGradient = arguments[0].fillGradient; this.fillGradientPaint = arguments[0].fillGradientPaint; this.fillName = arguments[0].fillName; this.strokeOpacity = arguments[0].strokeOpacity; this.fillOpacity = arguments[0].fillOpacity; this.opacity = arguments[0].opacity } this.name = this.element.getStringAttribute("id"); var displayStr = this.element.getStringAttribute("display", "inline"); this.visible = displayStr !== "none"; var str = this.element.getAttribute("transform"); if (str) this.matrix = this.parseMatrix(str); var viewBoxStr = this.element.getStringAttribute("viewBox"); if (viewBoxStr !== null) { var viewBox = viewBoxStr.split(" "); this.width = viewBox[2]; this.height = viewBox[3] } var unitWidth = this.element.getStringAttribute("width"); var unitHeight = this.element.getStringAttribute("height"); if (unitWidth !== null) { this.width = this.parseUnitSize(unitWidth); this.height = this.parseUnitSize(unitHeight) } else if (this.width === 0 || this.height === 0) { this.width = 1; this.height = 1; throw "The width and/or height is not " + "readable in the <svg> tag of this file."; } this.parseColors(this.element); this.parseChildren(this.element) }; PShapeSVG.prototype = new PShape; PShapeSVG.prototype.parseMatrix = function() { function getCoords(s) { var m = []; s.replace(/\((.*?)\)/, function() { return function(all, params) { m = params.replace(/,+/g, " ").split(/\s+/) } }()); return m } return function(str) { this.checkMatrix(2); var pieces = []; str.replace(/\s*(\w+)\((.*?)\)/g, function(all) { pieces.push(p.trim(all)) }); if (pieces.length === 0) return null; for (var i = 0, j = pieces.length; i < j; i++) { var m = getCoords(pieces[i]); if (pieces[i].indexOf("matrix") !== -1) this.matrix.set(m[0], m[2], m[ 4], m[1], m[3], m[5]);

else if (pieces[i].indexOf("translate") !== -1) { var tx = m[0]; var ty = m.length === 2 ? m[1] : 0; this.matrix.translate(tx, ty) } else if (pieces[i].indexOf("scale") !== -1) { var sx = m[0]; var sy = m.length === 2 ? m[1] : m[0]; this.matrix.scale(sx, sy) } else if (pieces[i].indexOf("rotate") !== -1) { var angle = m[0]; if (m.length === 1) this.matrix.rotate(p.radians(angle)); else if (m.length === 3) { this.matrix.translate(m[1], m[2]); this.matrix.rotate(p.radians(m[0])); this.matrix.translate(-m[1], -m[2]) } } else if (pieces[i].indexOf("skewX") !== -1) this.matrix.skewX(parseF loat(m[0])); else if (pieces[i].indexOf("skewY") !== -1) this.matrix.skewY(m[0]); else if (pieces[i].indexOf("shearX") !== -1) this.matrix.shearX(m[0]); else if (pieces[i].indexOf("shearY") !== -1) this.matrix.shearY(m[0]) } return this.matrix } }(); PShapeSVG.prototype.parseChildren = function(element) { var newelement = element.getChildren(); var children = new p.PShape; for (var i = 0, j = newelement.length; i < j; i++) { var kid = this.parseChild(newelement[i]); if (kid) children.addChild(kid) } this.children.push(children) }; PShapeSVG.prototype.getName = function() { return this.name }; PShapeSVG.prototype.parseChild = function(elem) { var name = elem.getName(); var shape; if (name === "g") shape = new PShapeSVG(this, elem); else if (name === "defs") shape = new PShapeSVG(this, elem); else if (name === "line") { shape = new PShapeSVG(this, elem); shape.parseLine() } else if (name === "circle") { shape = new PShapeSVG(this, elem); shape.parseEllipse(true) } else if (name === "ellipse") { shape = new PShapeSVG(this, elem); shape.parseEllipse(false) } else if (name === "rect") { shape = new PShapeSVG(this, elem); shape.parseRect() } else if (name === "polygon") { shape = new PShapeSVG(this, elem); shape.parsePoly(true) } else if (name === "polyline") { shape = new PShapeSVG(this, elem); shape.parsePoly(false)

} else if (name === "path") { shape = new PShapeSVG(this, elem); shape.parsePath() } else if (name === "radialGradient") unimplemented("PShapeSVG.prototype.p arseChild, name = radialGradient"); else if (name === "linearGradient") unimplemented("PShapeSVG.prototype.par seChild, name = linearGradient"); else if (name === "text") unimplemented("PShapeSVG.prototype.parseChild, n ame = text"); else if (name === "filter") unimplemented("PShapeSVG.prototype.parseChild, name = filter"); else if (name === "mask") unimplemented("PShapeSVG.prototype.parseChild, n ame = mask"); else nop(); return shape }; PShapeSVG.prototype.parsePath = function() { this.family = 21; this.kind = 0; var pathDataChars = []; var c; var pathData = p.trim(this.element.getStringAttribute("d").replace(/[\s,]+ /g, " ")); if (pathData === null) return; pathData = p.__toCharArray(pathData); var cx = 0, cy = 0, ctrlX = 0, ctrlY = 0, ctrlX1 = 0, ctrlX2 = 0, ctrlY1 = 0, ctrlY2 = 0, endX = 0, endY = 0, ppx = 0, ppy = 0, px = 0, py = 0, i = 0, valOf = 0; var str = ""; var tmpArray = []; var flag = false; var lastInstruction; var command; var j, k; while (i < pathData.length) { valOf = pathData[i].valueOf(); if (valOf >= 65 && valOf <= 90 || valOf >= 97 && valOf <= 122) { j = i; i++; if (i < pathData.length) { tmpArray = []; valOf = pathData[i].valueOf(); while (! (valOf >= 65 && valOf <= 90 || valOf >= 97 && valOf <= 100 || valOf >= 102 && valOf <= 122) && flag === false) { if (valOf === 32) { if (str !== "") { tmpArray.push(parseFloat(str));

str = "" } i++ } else if (valOf === 45) if (pathData[i - 1].valueOf() === 101) { str += pathData[i].toString(); i++ } else { if (str !== "") tmpArray.push(parseFloat(str)); str = pathData[i].toString(); i++ } else { str += pathData[i].toString(); i++ } if (i === pathData.length) flag = true; else valOf = pathData[i].valueOf() } } if (str !== "") { tmpArray.push(parseFloat(str)); str = "" } command = pathData[j]; valOf = command.valueOf(); if (valOf === 77) { if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { cx = tmpArray[0]; cy = tmpArray[1]; this.parsePathMoveto(cx, cy); if (tmpArray.length > 2) for (j = 2, k = tmpArray.length; j < k; j += 2) { cx = tmpArray[j]; cy = tmpArray[j + 1]; this.parsePathLineto(cx, cy) } } } else if (valOf === 109) { if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { cx += tmpArray[0]; cy += tmpArray[1]; this.parsePathMoveto(cx, cy); if (tmpArray.length > 2) for (j = 2, k = tmpArray.length; j < k; j += 2) { cx += tmpArray[j]; cy += tmpArray[j + 1]; this.parsePathLineto(cx, cy) } } } else if (valOf === 76) { if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { cx = tmpArray[j]; cy = tmpArray[j + 1]; this.parsePathLineto(cx, cy) } } else if (valOf === 108) { if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { cx += tmpArray[j]; cy += tmpArray[j + 1];

this.parsePathLineto(cx, cy) } } else if (valOf === 72) for (j = 0, k = tmpArray.length; j < k; j++) { cx = tmpArray[j]; this.parsePathLineto(cx, cy) } else if (valOf === 104) for (j = 0, k = tmpArray.length; j < k; j++) { cx += tmpArray[j]; this.parsePathLineto(cx, cy) } else if (valOf === 86) for (j = 0, k = tmpArray.length; j < k; j++) { cy = tmpArray[j]; this.parsePathLineto(cx, cy) } else if (valOf === 118) for (j = 0, k = tmpArray.length; j < k; j++) { cy += tmpArray[j]; this.parsePathLineto(cx, cy) } else if (valOf === 67) { if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) for (j = 0, k = tmpArray.length; j < k; j += 6) { ctrlX1 = tmpArray[j]; ctrlY1 = tmpArray[j + 1]; ctrlX2 = tmpArray[j + 2]; ctrlY2 = tmpArray[j + 3]; endX = tmpArray[j + 4]; endY = tmpArray[j + 5]; this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); cx = endX; cy = endY } } else if (valOf === 99) { if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) for (j = 0, k = tmpArray.length; j < k; j += 6) { ctrlX1 = cx + tmpArray[j]; ctrlY1 = cy + tmpArray[j + 1]; ctrlX2 = cx + tmpArray[j + 2]; ctrlY2 = cy + tmpArray[j + 3]; endX = cx + tmpArray[j + 4]; endY = cy + tmpArray[j + 5]; this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); cx = endX; cy = endY } } else if (valOf === 83) { if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { if (lastInstruction.toLowerCase() === "c" || lastInstruction.toLow erCase() === "s") { ppx = this.vertices[this.vertices.length - 2][0]; ppy = this.vertices[this.vertices.length - 2][1]; px = this.vertices[this.vertices.length - 1][0]; py = this.vertices[this.vertices.length - 1][1]; ctrlX1 = px + (px - ppx); ctrlY1 = py + (py - ppy) } else { ctrlX1 = this.vertices[this.vertices.length - 1][0]; ctrlY1 = this.vertices[this.vertices.length - 1][1] } ctrlX2 = tmpArray[j];

ctrlY2 = tmpArray[j + 1]; endX = tmpArray[j + 2]; endY = tmpArray[j + 3]; this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); cx = endX; cy = endY } } else if (valOf === 115) { if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { if (lastInstruction.toLowerCase() === "c" || lastInstruction.toLow erCase() === "s") { ppx = this.vertices[this.vertices.length - 2][0]; ppy = this.vertices[this.vertices.length - 2][1]; px = this.vertices[this.vertices.length - 1][0]; py = this.vertices[this.vertices.length - 1][1]; ctrlX1 = px + (px - ppx); ctrlY1 = py + (py - ppy) } else { ctrlX1 = this.vertices[this.vertices.length - 1][0]; ctrlY1 = this.vertices[this.vertices.length - 1][1] } ctrlX2 = cx + tmpArray[j]; ctrlY2 = cy + tmpArray[j + 1]; endX = cx + tmpArray[j + 2]; endY = cy + tmpArray[j + 3]; this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); cx = endX; cy = endY } } else if (valOf === 81) { if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { ctrlX = tmpArray[j]; ctrlY = tmpArray[j + 1]; endX = tmpArray[j + 2]; endY = tmpArray[j + 3]; this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); cx = endX; cy = endY } } else if (valOf === 113) { if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { ctrlX = cx + tmpArray[j]; ctrlY = cy + tmpArray[j + 1]; endX = cx + tmpArray[j + 2]; endY = cy + tmpArray[j + 3]; this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); cx = endX; cy = endY } } else if (valOf === 84) { if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { if (lastInstruction.toLowerCase() === "q" || lastInstruction.toLow erCase() === "t") { ppx = this.vertices[this.vertices.length - 2][0]; ppy = this.vertices[this.vertices.length - 2][1]; px = this.vertices[this.vertices.length - 1][0];

py = this.vertices[this.vertices.length - 1][1]; ctrlX = px + (px - ppx); ctrlY = py + (py - ppy) } else { ctrlX = cx; ctrlY = cy } endX = tmpArray[j]; endY = tmpArray[j + 1]; this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); cx = endX; cy = endY } } else if (valOf === 116) { if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { if (lastInstruction.toLowerCase() === "q" || lastInstruction.toLow erCase() === "t") { ppx = this.vertices[this.vertices.length - 2][0]; ppy = this.vertices[this.vertices.length - 2][1]; px = this.vertices[this.vertices.length - 1][0]; py = this.vertices[this.vertices.length - 1][1]; ctrlX = px + (px - ppx); ctrlY = py + (py - ppy) } else { ctrlX = cx; ctrlY = cy } endX = cx + tmpArray[j]; endY = cy + tmpArray[j + 1]; this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); cx = endX; cy = endY } } else if (valOf === 90 || valOf === 122) this.close = true; lastInstruction = command.toString() } else i++ } }; PShapeSVG.prototype.parsePathQuadto = function(x1, y1, cx, cy, x2, y2) { if (this.vertices.length > 0) { this.parsePathCode(1); this.parsePathVertex(x1 + (cx - x1) * 2 / 3, y1 + (cy - y1) * 2 / 3); this.parsePathVertex(x2 + (cx - x2) * 2 / 3, y2 + (cy - y2) * 2 / 3); this.parsePathVertex(x2, y2) } else throw "Path must start with M/m"; }; PShapeSVG.prototype.parsePathCurveto = function(x1, y1, x2, y2, x3, y3) { if (this.vertices.length > 0) { this.parsePathCode(1); this.parsePathVertex(x1, y1); this.parsePathVertex(x2, y2); this.parsePathVertex(x3, y3) } else throw "Path must start with M/m"; }; PShapeSVG.prototype.parsePathLineto = function(px, py) { if (this.vertices.length > 0) { this.parsePathCode(0); this.parsePathVertex(px, py); this.vertices[this.vertices.length - 1]["moveTo"] = false

} else throw "Path must start with M/m"; }; PShapeSVG.prototype.parsePathMoveto = function(px, py) { if (this.vertices.length > 0) this.parsePathCode(3); this.parsePathCode(0); this.parsePathVertex(px, py); this.vertices[this.vertices.length - 1]["moveTo"] = true }; PShapeSVG.prototype.parsePathVertex = function(x, y) { var verts = []; verts[0] = x; verts[1] = y; this.vertices.push(verts) }; PShapeSVG.prototype.parsePathCode = function(what) { this.vertexCodes.push(what) }; PShapeSVG.prototype.parsePoly = function(val) { this.family = 21; this.close = val; var pointsAttr = p.trim(this.element.getStringAttribute("points").replace( /[,\s]+/g, " ")); if (pointsAttr !== null) { var pointsBuffer = pointsAttr.split(" "); if (pointsBuffer.length % 2 === 0) for (var i = 0, j = pointsBuffer.leng th; i < j; i++) { var verts = []; verts[0] = pointsBuffer[i]; verts[1] = pointsBuffer[++i]; this.vertices.push(verts) } else throw "Error parsing polygon points: odd number of coordinates pr ovided"; } }; PShapeSVG.prototype.parseRect = function() { this.kind = 30; this.family = 1; this.params = []; this.params[0] = this.element.getFloatAttribute("x"); this.params[1] = this.element.getFloatAttribute("y"); this.params[2] = this.element.getFloatAttribute("width"); this.params[3] = this.element.getFloatAttribute("height"); if (this.params[2] < 0 || this.params[3] < 0) throw "svg error: negative w idth or height found while parsing <rect>"; }; PShapeSVG.prototype.parseEllipse = function(val) { this.kind = 31; this.family = 1; this.params = []; this.params[0] = this.element.getFloatAttribute("cx") | 0; this.params[1] = this.element.getFloatAttribute("cy") | 0; var rx, ry; if (val) { rx = ry = this.element.getFloatAttribute("r"); if (rx < 0) throw "svg error: negative radius found while parsing <circl e>"; } else { rx = this.element.getFloatAttribute("rx"); ry = this.element.getFloatAttribute("ry"); if (rx < 0 || ry < 0) throw "svg error: negative x-axis radius or y-axis

radius found while parsing <ellipse>"; } this.params[0] -= rx; this.params[1] -= ry; this.params[2] = rx * 2; this.params[3] = ry * 2 }; PShapeSVG.prototype.parseLine = function() { this.kind = 4; this.family = 1; this.params = []; this.params[0] = this.element.getFloatAttribute("x1"); this.params[1] = this.element.getFloatAttribute("y1"); this.params[2] = this.element.getFloatAttribute("x2"); this.params[3] = this.element.getFloatAttribute("y2") }; PShapeSVG.prototype.parseColors = function(element) { if (element.hasAttribute("opacity")) this.setOpacity(element.getAttribute( "opacity")); if (element.hasAttribute("stroke")) this.setStroke(element.getAttribute("s troke")); if (element.hasAttribute("stroke-width")) this.setStrokeWeight(element.get Attribute("stroke-width")); if (element.hasAttribute("stroke-linejoin")) this.setStrokeJoin(element.ge tAttribute("stroke-linejoin")); if (element.hasAttribute("stroke-linecap")) this.setStrokeCap(element.getS tringAttribute("stroke-linecap")); if (element.hasAttribute("fill")) this.setFill(element.getStringAttribute( "fill")); if (element.hasAttribute("style")) { var styleText = element.getStringAttribute("style"); var styleTokens = styleText.toString().split(";"); for (var i = 0, j = styleTokens.length; i < j; i++) { var tokens = p.trim(styleTokens[i].split(":")); if (tokens[0] === "fill") this.setFill(tokens[1]); else if (tokens[0] === "fill-opacity") this.setFillOpacity(tokens[1]); else if (tokens[0] === "stroke") this.setStroke(tokens[1]); else if (tokens[0] === "stroke-width") this.setStrokeWeight(tokens[1]) ; else if (tokens[0] === "stroke-linecap") this.setStrokeCap(tokens[1]); else if (tokens[0] === "stroke-linejoin") this.setStrokeJoin(tokens[1] ); else if (tokens[0] === "stroke-opacity") this.setStrokeOpacity(tokens[ 1]); else if (tokens[0] === "opacity") this.setOpacity(tokens[1]) } } }; PShapeSVG.prototype.setFillOpacity = function(opacityText) { this.fillOpacity = parseFloat(opacityText); this.fillColor = this.fillOpacity * 255 << 24 | this.fillColor & 16777215 }; PShapeSVG.prototype.setFill = function(fillText) { var opacityMask = this.fillColor & 4278190080; if (fillText === "none") this.fill = false; else if (fillText.indexOf("#") === 0) { this.fill = true; if (fillText.length === 4) fillText = fillText.replace(/#(.)(.)(.)/, "#$ 1$1$2$2$3$3"); this.fillColor = opacityMask | parseInt(fillText.substring(1), 16) & 167

77215 } else if (fillText.indexOf("rgb") === 0) { this.fill = true; this.fillColor = opacityMask | this.parseRGB(fillText) } else if (fillText.indexOf("url(#") === 0) this.fillName = fillText.subst ring(5, fillText.length - 1); else if (colors[fillText]) { this.fill = true; this.fillColor = opacityMask | parseInt(colors[fillText].substring(1), 1 6) & 16777215 } }; PShapeSVG.prototype.setOpacity = function(opacity) { this.strokeColor = parseFloat(opacity) * 255 << 24 | this.strokeColor & 16 777215; this.fillColor = parseFloat(opacity) * 255 << 24 | this.fillColor & 167772 15 }; PShapeSVG.prototype.setStroke = function(strokeText) { var opacityMask = this.strokeColor & 4278190080; if (strokeText === "none") this.stroke = false; else if (strokeText.charAt(0) === "#") { this.stroke = true; if (strokeText.length === 4) strokeText = strokeText.replace(/#(.)(.)(.) /, "#$1$1$2$2$3$3"); this.strokeColor = opacityMask | parseInt(strokeText.substring(1), 16) & 16777215 } else if (strokeText.indexOf("rgb") === 0) { this.stroke = true; this.strokeColor = opacityMask | this.parseRGB(strokeText) } else if (strokeText.indexOf("url(#") === 0) this.strokeName = strokeText .substring(5, strokeText.length - 1); else if (colors[strokeText]) { this.stroke = true; this.strokeColor = opacityMask | parseInt(colors[strokeText].substring(1 ), 16) & 16777215 } }; PShapeSVG.prototype.setStrokeWeight = function(weight) { this.strokeWeight = this.parseUnitSize(weight) }; PShapeSVG.prototype.setStrokeJoin = function(linejoin) { if (linejoin === "miter") this.strokeJoin = 'miter'; else if (linejoin === "round") this.strokeJoin = 'round'; else if (linejoin === "bevel") this.strokeJoin = 'bevel' }; PShapeSVG.prototype.setStrokeCap = function(linecap) { if (linecap === "butt") this.strokeCap = 'butt'; else if (linecap === "round") this.strokeCap = 'round'; else if (linecap === "square") this.strokeCap = 'square' }; PShapeSVG.prototype.setStrokeOpacity = function(opacityText) { this.strokeOpacity = parseFloat(opacityText); this.strokeColor = this.strokeOpacity * 255 << 24 | this.strokeColor & 167 77215 }; PShapeSVG.prototype.parseRGB = function(color) { var sub = color.substring(color.indexOf("(") + 1, color.indexOf(")")); var values = sub.split(", "); return values[0] << 16 | values[1] << 8 | values[2]

* * * * *

}; PShapeSVG.prototype.parseUnitSize = function(text) { var len = text.length - 2; if (len < 0) return text; if (text.indexOf("pt") === len) return parseFloat(text.substring(0, len)) 1.25; if (text.indexOf("pc") === len) return parseFloat(text.substring(0, len)) 15; if (text.indexOf("mm") === len) return parseFloat(text.substring(0, len)) 3.543307; if (text.indexOf("cm") === len) return parseFloat(text.substring(0, len)) 35.43307; if (text.indexOf("in") === len) return parseFloat(text.substring(0, len)) 90; if (text.indexOf("px") === len) return parseFloat(text.substring(0, len)); return parseFloat(text) }; p.shape = function(shape, x, y, width, height) { if (arguments.length >= 1 && arguments[0] !== null) if (shape.isVisible()) {

p.pushMatrix(); if (curShapeMode === 3) if (arguments.length === 5) { p.translate(x - width / 2, y - height / 2); p.scale(width / shape.getWidth(), height / shape.getHeight()) } else if (arguments.length === 3) p.translate(x - shape.getWidth() / 2, -shape.getHeight() / 2); else p.translate(-shape.getWidth() / 2, -shape.getHeight() / 2); else if (curShapeMode === 0) if (arguments.length === 5) { p.translate(x, y); p.scale(width / shape.getWidth(), height / shape.getHeight()) } else { if (arguments.length === 3) p.translate(x, y) } else if (curShapeMode === 1) if (arguments.length === 5) { width -= x; height -= y; p.translate(x, y); p.scale(width / shape.getWidth(), height / shape.getHeight()) } else if (arguments.length === 3) p.translate(x, y); shape.draw(p); if (arguments.length === 1 && curShapeMode === 3 || arguments.length > 1 ) p.popMatrix() } }; p.shapeMode = function(mode) { curShapeMode = mode }; p.loadShape = function(filename) { if (arguments.length === 1) if (filename.indexOf(".svg") > -1) return new PShapeSVG(null, filename); return null }; var XMLAttribute = function(fname, n, nameSpace, v, t) { this.fullName = fname || ""; this.name = n || ""; this.namespace = nameSpace || ""; this.value = v; this.type = t }; XMLAttribute.prototype = { getName: function() {

return this.name }, getFullName: function() { return this.fullName }, getNamespace: function() { return this.namespace }, getValue: function() { return this.value }, getType: function() { return this.type }, setValue: function(newval) { this.value = newval } }; var XMLElement = p.XMLElement = function(selector, uri, sysid, line) { this.attributes = []; this.children = []; this.fullName = null; this.name = null; this.namespace = ""; this.content = null; this.parent = null; this.lineNr = ""; this.systemID = ""; this.type = "ELEMENT"; if (selector) if (typeof selector === "string") if (uri === undef && selec tor.indexOf("<") > -1) this.parse(selector); else { this.fullName = selector; this.namespace = uri; this.systemId = sysid; this.lineNr = line } else this.parse(uri) }; XMLElement.prototype = { parse: function(textstring) { var xmlDoc; try { var extension = textstring.substring(textstring.length - 4); if (extension === ".xml" || extension === ".svg") textstring = ajax(te xtstring); xmlDoc = (new DOMParser).parseFromString(textstring, "text/xml"); var elements = xmlDoc.documentElement; if (elements) this.parseChildrenRecursive(null, elements); else throw "Error loading document"; return this } catch(e) { throw e; } }, parseChildrenRecursive: function(parent, elementpath) { var xmlelement, xmlattribute, tmpattrib, l, m, child; if (!parent) { this.fullName = elementpath.localName; this.name = elementpath.nodeName; xmlelement = this

} else { xmlelement = new XMLElement(elementpath.nodeName); xmlelement.parent = parent } if (elementpath.nodeType === 3 && elementpath.textContent !== "") return this.createPCDataElement(elementpath.textContent); if (elementpath.nodeType === 4) return this.createCDataElement(elementpa th.textContent); if (elementpath.attributes) for (l = 0, m = elementpath.attributes.lengt h; l < m; l++) { tmpattrib = elementpath.attributes[l]; xmlattribute = new XMLAttribute(tmpattrib.getname, tmpattrib.nodeName, tmpattrib.namespaceURI, tmpattrib.nodeValue, tmpattrib.nodeType); xmlelement.attributes.push(xmlattribute) } if (elementpath.childNodes) for (l = 0, m = elementpath.childNodes.lengt h; l < m; l++) { var node = elementpath.childNodes[l]; child = xmlelement.parseChildrenRecursive(xmlelement, node); if (child !== null) xmlelement.children.push(child) } return xmlelement }, createElement: function(fullname, namespaceuri, sysid, line) { if (sysid === undef) return new XMLElement(fullname, namespaceuri); return new XMLElement(fullname, namespaceuri, sysid, line) }, createPCDataElement: function(content, isCDATA) { if (content.replace(/^\s+$/g, "") === "") return null; var pcdata = new XMLElement; pcdata.type = "TEXT"; pcdata.content = content; return pcdata }, createCDataElement: function(content) { var cdata = this.createPCDataElement(content); if (cdata === null) return null; cdata.type = "CDATA"; var htmlentities = { "<": "&lt;", ">": "&gt;", "'": "&apos;", '"': "&quot;" }, entity; for (entity in htmlentities) if (!Object.hasOwnProperty(htmlentities, en tity)) content = content.replace(new RegExp(entity, "g"), htmlentities[entity]); cdata.cdata = content; return cdata }, hasAttribute: function() { if (arguments.length === 1) return this.getAttribute(arguments[0]) !== n ull; if (arguments.length === 2) return this.getAttribute(arguments[0], argum ents[1]) !== null }, equals: function(other) { if (! (other instanceof XMLElement)) return false; var i, j; if (this.fullName !== other.fullName) return false;

if (this.attributes.length !== other.getAttributeCount()) return false; if (this.attributes.length !== other.attributes.length) return false; var attr_name, attr_ns, attr_value, attr_type, attr_other; for (i = 0, j = this.attributes.length; i < j; i++) { attr_name = this.attributes[i].getName(); attr_ns = this.attributes[i].getNamespace(); attr_other = other.findAttribute(attr_name, attr_ns); if (attr_other === null) return false; if (this.attributes[i].getValue() !== attr_other.getValue()) return fa lse; if (this.attributes[i].getType() !== attr_other.getType()) return fals e } if (this.children.length !== other.getChildCount()) return false; if (this.children.length > 0) { var child1, child2; for (i = 0, j = this.children.length; i < j; i++) { child1 = this.getChild(i); child2 = other.getChild(i); if (!child1.equals(child2)) return false } return true } return this.content === other.content }, getContent: function() { if (this.type === "TEXT" || this.type === "CDATA") return this.content; var children = this.children; if (children.length === 1 && (children[0].type === "TEXT" || children[0] .type === "CDATA")) return children[0].content; return null }, getAttribute: function() { var attribute; if (arguments.length === 2) { attribute = this.findAttribute(arguments[0]); if (attribute) return attribute.getValue(); return arguments[1] } else if (arguments.length === 1) { attribute = this.findAttribute(arguments[0]); if (attribute) return attribute.getValue(); return null } else if (arguments.length === 3) { attribute = this.findAttribute(arguments[0], arguments[1]); if (attribute) return attribute.getValue(); return arguments[2] } }, getStringAttribute: function() { if (arguments.length === 1) return this.getAttribute(arguments[0]); if (arguments.length === 2) return this.getAttribute(arguments[0], argum ents[1]); return this.getAttribute(arguments[0], arguments[1], arguments[2]) }, getString: function(attributeName) { return this.getStringAttribute(attributeName) }, getFloatAttribute: function() { if (arguments.length === 1) return parseFloat(this.getAttribute(argument s[0], 0));

if (arguments.length === 2) return this.getAttribute(arguments[0], argum ents[1]); return this.getAttribute(arguments[0], arguments[1], arguments[2]) }, getFloat: function(attributeName) { return this.getFloatAttribute(attributeName) }, getIntAttribute: function() { if (arguments.length === 1) return this.getAttribute(arguments[0], 0); if (arguments.length === 2) return this.getAttribute(arguments[0], argum ents[1]); return this.getAttribute(arguments[0], arguments[1], arguments[2]) }, getInt: function(attributeName) { return this.getIntAttribute(attributeName) }, hasChildren: function() { return this.children.length > 0 }, addChild: function(child) { if (child !== null) { child.parent = this; this.children.push(child) } }, insertChild: function(child, index) { if (child) { if (child.getLocalName() === null && !this.hasChildren()) { var lastChild = this.children[this.children.length - 1]; if (lastChild.getLocalName() === null) { lastChild.setContent(lastChild.getContent() + child.getContent()); return } } child.parent = this; this.children.splice(index, 0, child) } }, getChild: function(selector) { if (typeof selector === "number") return this.children[selector]; if (selector.indexOf("/") !== -1) return this.getChildRecursive(selector .split("/"), 0); var kid, kidName; for (var i = 0, j = this.getChildCount(); i < j; i++) { kid = this.getChild(i); kidName = kid.getName(); if (kidName !== null && kidName === selector) return kid } return null }, getChildren: function() { if (arguments.length === 1) { if (typeof arguments[0] === "number") return this.getChild(arguments[0 ]); if (arguments[0].indexOf("/") !== -1) return this.getChildrenRecursive (arguments[0].split("/"), 0); var matches = []; var kid, kidName; for (var i = 0, j = this.getChildCount(); i < j; i++) { kid = this.getChild(i);

kidName = kid.getName(); if (kidName !== null && kidName === arguments[0]) matches.push(kid) } return matches } return this.children }, getChildCount: function() { return this.children.length }, getChildRecursive: function(items, offset) { if (offset === items.length) return this; var kid, kidName, matchName = items[offset]; for (var i = 0, j = this.getChildCount(); i < j; i++) { kid = this.getChild(i); kidName = kid.getName(); if (kidName !== null && kidName === matchName) return kid.getChildRecu rsive(items, offset + 1) } return null }, getChildrenRecursive: function(items, offset) { if (offset === items.length - 1) return this.getChildren(items[offset]); var matches = this.getChildren(items[offset]); var kidMatches = []; for (var i = 0; i < matches.length; i++) kidMatches = kidMatches.concat( matches[i].getChildrenRecursive(items, offset + 1)); return kidMatches }, isLeaf: function() { return !this.hasChildren() }, listChildren: function() { var arr = []; for (var i = 0, j = this.children.length; i < j; i++) arr.push(this.getC hild(i).getName()); return arr }, removeAttribute: function(name, namespace) { this.namespace = namespace || ""; for (var i = 0, j = this.attributes.length; i < j; i++) if (this.attribu tes[i].getName() === name && this.attributes[i].getNamespace() === this.namespac e) { this.attributes.splice(i, 1); break } }, removeChild: function(child) { if (child) for (var i = 0, j = this.children.length; i < j; i++) if (thi s.children[i].equals(child)) { this.children.splice(i, 1); break } }, removeChildAtIndex: function(index) { if (this.children.length > index) this.children.splice(index, 1) }, findAttribute: function(name, namespace) { this.namespace = namespace || ""; for (var i = 0, j = this.attributes.length; i < j; i++) if (this.attribu

tes[i].getName() === name && this.attributes[i].getNamespace() === this.namespac e) return this.attributes[i]; return null }, setAttribute: function() { var attr; if (arguments.length === 3) { var index = arguments[0].indexOf(":"); var name = arguments[0].substring(index + 1); attr = this.findAttribute(name, arguments[1]); if (attr) attr.setValue(arguments[2]); else { attr = new XMLAttribute(arguments[0], name, arguments[1], arguments[ 2], "CDATA"); this.attributes.push(attr) } } else { attr = this.findAttribute(arguments[0]); if (attr) attr.setValue(arguments[1]); else { attr = new XMLAttribute(arguments[0], arguments[0], null, arguments[ 1], "CDATA"); this.attributes.push(attr) } } }, setString: function(attribute, value) { this.setAttribute(attribute, value) }, setInt: function(attribute, value) { this.setAttribute(attribute, value) }, setFloat: function(attribute, value) { this.setAttribute(attribute, value) }, setContent: function(content) { if (this.children.length > 0) Processing.debug("Tried to set content for XMLElement with children"); this.content = content }, setName: function() { if (arguments.length === 1) { this.name = arguments[0]; this.fullName = arguments[0]; this.namespace = null } else { var index = arguments[0].indexOf(":"); if (arguments[1] === null || index < 0) this.name = arguments[0]; else this.name = arguments[0].substring(index + 1); this.fullName = arguments[0]; this.namespace = arguments[1] } }, getName: function() { return this.fullName }, getLocalName: function() { return this.name }, getAttributeCount: function() {

return this.attributes.length }, toString: function() { if (this.type === "TEXT") return this.content; if (this.type === "CDATA") return this.cdata; var tagstring = this.fullName; var xmlstring = "<" + tagstring; var a, c; for (a = 0; a < this.attributes.length; a++) { var attr = this.attributes[a]; xmlstring += " " + attr.getName() + "=" + '"' + attr.getValue() + '"' } if (this.children.length === 0) if (this.content === "") xmlstring += "/ >"; else xmlstring += ">" + this.content + "</" + tagstring + ">"; else { xmlstring += ">"; for (c = 0; c < this.children.length; c++) xmlstring += this.children[ c].toString(); xmlstring += "</" + tagstring + ">" } return xmlstring } }; XMLElement.parse = function(xmlstring) { var element = new XMLElement; element.parse(xmlstring); return element }; var XML = p.XML = p.XMLElement; p.loadXML = function(uri) { return new XML(p, uri) }; var printMatrixHelper = function(elements) { var big = 0; for (var i = 0; i < elements.length; i++) if (i !== 0) big = Math.max(big, Math.abs(elements[i])); else big = Math.abs(elements[i]); var digits = (big + "").indexOf("."); if (digits === 0) digits = 1; else if (digits === -1) digits = (big + "").length; return digits }; var PMatrix2D = p.PMatrix2D = function() { if (arguments.length === 0) this.reset(); else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) this .set(arguments[0].array()); else if (arguments.length === 6) this.set(arguments[0], arguments[1], argu ments[2], arguments[3], arguments[4], arguments[5]) }; PMatrix2D.prototype = { set: function() { if (arguments.length === 6) { var a = arguments; this.set([a[0], a[1], a[2], a[3], a[4], a[5]]) } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) this.elements = arguments[0].array(); else if (arguments.length === 1 && arguments[0] instanceof Array) this.e lements = arguments[0].slice() },

get: function() { var outgoing = new PMatrix2D; outgoing.set(this.elements); return outgoing }, reset: function() { this.set([1, 0, 0, 0, 1, 0]) }, array: function array() { return this.elements.slice() }, translate: function(tx, ty) { this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this. elements[2]; this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this. elements[5] }, invTranslate: function(tx, ty) { this.translate(-tx, -ty) }, transpose: function() {}, mult: function(source, target) { var x, y; if (source instanceof PVector) { x = source.x; y = source.y; if (!target) target = new PVector } else if (source instanceof Array) { x = source[0]; y = source[1]; if (!target) target = [] } if (target instanceof Array) { target[0] = this.elements[0] * x + this.elements[1] * y + this.element s[2]; target[1] = this.elements[3] * x + this.elements[4] * y + this.element s[5] } else if (target instanceof PVector) { target.x = this.elements[0] * x + this.elements[1] * y + this.elements [2]; target.y = this.elements[3] * x + this.elements[4] * y + this.elements [5]; target.z = 0 } return target }, multX: function(x, y) { return x * this.elements[0] + y * this.elements[1] + this.elements[2] }, multY: function(x, y) { return x * this.elements[3] + y * this.elements[4] + this.elements[5] }, skewX: function(angle) { this.apply(1, 0, 1, angle, 0, 0) }, skewY: function(angle) { this.apply(1, 0, 1, 0, angle, 0) }, shearX: function(angle) {

this.apply(1, 0, 1, Math.tan(angle), 0, 0) }, shearY: function(angle) { this.apply(1, 0, 1, 0, Math.tan(angle), 0) }, determinant: function() { return this.elements[0] * this.elements[4] - this.elements[1] * this.ele ments[3] }, invert: function() { var d = this.determinant(); if (Math.abs(d) > -2147483648) { var old00 = this.elements[0]; var old01 = this.elements[1]; var old02 = this.elements[2]; var old10 = this.elements[3]; var old11 = this.elements[4]; var old12 = this.elements[5]; this.elements[0] = old11 / d; this.elements[3] = -old10 / d; this.elements[1] = -old01 / d; this.elements[4] = old00 / d; this.elements[2] = (old01 * old12 - old11 * old02) / d; this.elements[5] = (old10 * old02 - old00 * old12) / d; return true } return false }, scale: function(sx, sy) { if (sx && !sy) sy = sx; if (sx && sy) { this.elements[0] *= sx; this.elements[1] *= sy; this.elements[3] *= sx; this.elements[4] *= sy } }, invScale: function(sx, sy) { if (sx && !sy) sy = sx; this.scale(1 / sx, 1 / sy) }, apply: function() { var source; if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) source = arguments[0].array(); else if (arguments.length === 6) source = Array.prototype.slice.call(arg uments); else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; var result = [0, 0, this.elements[2], 0, 0, this.elements[5]]; var e = 0; for (var row = 0; row < 2; row++) for (var col = 0; col < 3; col++, e++) result[e] += this.elements[row * 3 + 0] * source[col + 0] + this.elements[row * 3 + 1] * source[col + 3]; this.elements = result.slice() }, preApply: function() { var source; if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) source = arguments[0].array();

else if (arguments.length === 6) source = Array.prototype.slice.call(arg uments); else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; var result = [0, 0, source[2], 0, 0, source[5]]; result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1]; result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4]; result[0] = this.elements[0] * source[0] + this.elements[3] * source[1]; result[3] = this.elements[0] * source[3] + this.elements[3] * source[4]; result[1] = this.elements[1] * source[0] + this.elements[4] * source[1]; result[4] = this.elements[1] * source[3] + this.elements[4] * source[4]; this.elements = result.slice() }, rotate: function(angle) { var c = Math.cos(angle); var s = Math.sin(angle); var temp1 = this.elements[0]; var temp2 = this.elements[1]; this.elements[0] = c * temp1 + s * temp2; this.elements[1] = -s * temp1 + c * temp2; temp1 = this.elements[3]; temp2 = this.elements[4]; this.elements[3] = c * temp1 + s * temp2; this.elements[4] = -s * temp1 + c * temp2 }, rotateZ: function(angle) { this.rotate(angle) }, invRotateZ: function(angle) { this.rotateZ(angle - Math.PI) }, print: function() { var digits = printMatrixHelper(this.elements); var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this. elements[1], digits, 4) + " " + p.nfs(this.elements[2], digits, 4) + "\n" + p.nf s(this.elements[3], digits, 4) + " " + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + "\n\n"; p.println(output) } }; var PMatrix3D = p.PMatrix3D = function() { this.reset() }; PMatrix3D.prototype = { set: function() { if (arguments.length === 16) this.elements = Array.prototype.slice.call( arguments); else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) th is.elements = arguments[0].array(); else if (arguments.length === 1 && arguments[0] instanceof Array) this.e lements = arguments[0].slice() }, get: function() { var outgoing = new PMatrix3D; outgoing.set(this.elements); return outgoing }, reset: function() {

this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }, array: function array() { return this.elements.slice() }, translate: function(tx, ty, tz) { if (tz === undef) tz = 0; this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2]; this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6]; this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10]; this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + t z * this.elements[14] }, transpose: function() { var temp = this.elements[4]; this.elements[4] = this.elements[1]; this.elements[1] = temp; temp = this.elements[8]; this.elements[8] = this.elements[2]; this.elements[2] = temp; temp = this.elements[6]; this.elements[6] = this.elements[9]; this.elements[9] = temp; temp = this.elements[3]; this.elements[3] = this.elements[12]; this.elements[12] = temp; temp = this.elements[7]; this.elements[7] = this.elements[13]; this.elements[13] = temp; temp = this.elements[11]; this.elements[11] = this.elements[14]; this.elements[14] = temp }, mult: function(source, target) { var x, y, z, w; if (source instanceof PVector) { x = source.x; y = source.y; z = source.z; w = 1; if (!target) target = new PVector } else if (source instanceof Array) { x = source[0]; y = source[1]; z = source[2]; w = source[3] || 1; if (!target || target.length !== 3 && target.length !== 4) target = [0 , 0, 0] } if (target instanceof Array) if (target.length === 3) { target[0] = this.elements[0] * x + this.elements[1] * y + this.element s[2] * z + this.elements[3]; target[1] = this.elements[4] * x + this.elements[5] * y + this.element s[6] * z + this.elements[7]; target[2] = this.elements[8] * x + this.elements[9] * y + this.element s[10] * z + this.elements[11]

} else if (target.length === 4) { target[0] = this.elements[0] * x + this.elements[1] * y + this.element s[2] * z + this.elements[3] * w; target[1] = this.elements[4] * x + this.elements[5] * y + this.element s[6] * z + this.elements[7] * w; target[2] = this.elements[8] * x + this.elements[9] * y + this.element s[10] * z + this.elements[11] * w; target[3] = this.elements[12] * x + this.elements[13] * y + this.eleme nts[14] * z + this.elements[15] * w } if (target instanceof PVector) { target.x = this.elements[0] * x + this.elements[1] * y + this.elements [2] * z + this.elements[3]; target.y = this.elements[4] * x + this.elements[5] * y + this.elements [6] * z + this.elements[7]; target.z = this.elements[8] * x + this.elements[9] * y + this.elements [10] * z + this.elements[11] } return target }, preApply: function() { var source; if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) source = arguments[0].array(); else if (arguments.length === 16) source = Array.prototype.slice.call(ar guments); else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; var result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var e = 0; for (var row = 0; row < 4; row++) for (var col = 0; col < 4; col++, e++) result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] * source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] + this. elements[col + 12] * source[row * 4 + 3]; this.elements = result.slice() }, apply: function() { var source; if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) source = arguments[0].array(); else if (arguments.length === 16) source = Array.prototype.slice.call(ar guments); else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; var result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var e = 0; for (var row = 0; row < 4; row++) for (var col = 0; col < 4; col++, e++) result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] * source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] + this. elements[row * 4 + 3] * source[col + 12]; this.elements = result.slice() }, rotate: function(angle, v0, v1, v2) { if (!v1) this.rotateZ(angle); else { var c = p.cos(angle); var s = p.sin(angle); var t = 1 - c; this.apply(t * v0 * v0 + c, t * v0 * v1 - s * v2, t * v0 * v2 + s * v1 , 0, t * v0 * v1 + s * v2, t * v1 * v1 + c, t * v1 * v2 - s * v0, 0, t * v0 * v2

- s * v1, t * v1 * v2 + s * v0, t * v2 * v2 + c, 0, 0, 0, 0, 1) } }, invApply: function() { if (inverseCopy === undef) inverseCopy = new PMatrix3D; var a = arguments; inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[ 9], a[10], a[11], a[12], a[13], a[14], a[15]); if (!inverseCopy.invert()) return false; this.preApply(inverseCopy); return true }, rotateX: function(angle) { var c = p.cos(angle); var s = p.sin(angle); this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]) }, rotateY: function(angle) { var c = p.cos(angle); var s = p.sin(angle); this.apply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]) }, rotateZ: function(angle) { var c = Math.cos(angle); var s = Math.sin(angle); this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) }, scale: function(sx, sy, sz) { if (sx && !sy && !sz) sy = sz = sx; else if (sx && sy && !sz) sz = 1; if (sx && sy && sz) { this.elements[0] *= sx; this.elements[1] *= sy; this.elements[2] *= sz; this.elements[4] *= sx; this.elements[5] *= sy; this.elements[6] *= sz; this.elements[8] *= sx; this.elements[9] *= sy; this.elements[10] *= sz; this.elements[12] *= sx; this.elements[13] *= sy; this.elements[14] *= sz } }, skewX: function(angle) { var t = Math.tan(angle); this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) }, skewY: function(angle) { var t = Math.tan(angle); this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) }, shearX: function(angle) { var t = Math.tan(angle); this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) }, shearY: function(angle) { var t = Math.tan(angle);

this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) }, multX: function(x, y, z, w) { if (!z) return this.elements[0] * x + this.elements[1] * y + this.elemen ts[3]; if (!w) return this.elements[0] * x + this.elements[1] * y + this.elemen ts[2] * z + this.elements[3]; return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w }, multY: function(x, y, z, w) { if (!z) return this.elements[4] * x + this.elements[5] * y + this.elemen ts[7]; if (!w) return this.elements[4] * x + this.elements[5] * y + this.elemen ts[6] * z + this.elements[7]; return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w }, multZ: function(x, y, z, w) { if (!w) return this.elements[8] * x + this.elements[9] * y + this.elemen ts[10] * z + this.elements[11]; return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w }, multW: function(x, y, z, w) { if (!w) return this.elements[12] * x + this.elements[13] * y + this.elem ents[14] * z + this.elements[15]; return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w }, invert: function() { var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this. elements[4]; var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this. elements[4]; var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this. elements[4]; var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this. elements[5]; var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this. elements[5]; var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this. elements[6]; var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this .elements[12]; var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * thi s.elements[12]; var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * thi s.elements[12]; var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * thi s.elements[13]; var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * thi s.elements[13]; var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * th is.elements[14]; var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + f A5 * fB0; if (Math.abs(fDet) <= 1.0E-9) return false; var kInv = []; kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elemen

ts[7] * fB3; kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elemen ts[7] * fB1; kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elemen ts[7] * fB0; kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.eleme nts[6] * fB0; kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elemen ts[3] * fB3; kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elemen ts[3] * fB1; kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elemen ts[3] * fB0; kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.eleme nts[2] * fB0; kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elem ents[15] * fA3; kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elem ents[15] * fA1; kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.ele ments[15] * fA0; kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.ele ments[14] * fA0; kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.eleme nts[11] * fA3; kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.eleme nts[11] * fA1; kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.eleme nts[11] * fA0; kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.eleme nts[10] * fA0; var fInvDet = 1 / fDet; kInv[0] *= fInvDet; kInv[1] *= fInvDet; kInv[2] *= fInvDet; kInv[3] *= fInvDet; kInv[4] *= fInvDet; kInv[5] *= fInvDet; kInv[6] *= fInvDet; kInv[7] *= fInvDet; kInv[8] *= fInvDet; kInv[9] *= fInvDet; kInv[10] *= fInvDet; kInv[11] *= fInvDet; kInv[12] *= fInvDet; kInv[13] *= fInvDet; kInv[14] *= fInvDet; kInv[15] *= fInvDet; this.elements = kInv.slice(); return true }, toString: function() { var str = ""; for (var i = 0; i < 15; i++) str += this.elements[i] + ", "; str += this.elements[15]; return str }, print: function() { var digits = printMatrixHelper(this.elements); var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.

elements[1], digits, 4) + " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs (this.elements[3], digits, 4) + "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) + "\n" + p.nfs(this.elements[8], digi ts, 4) + " " + p.nfs(this.elements[9], digits, 4) + " " + p.nfs(this.elements[10 ], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) + "\n" + p.nfs(this.el ements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) + " " + p.nfs (this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n \n"; p.println(output) }, invTranslate: function(tx, ty, tz) { this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1) }, invRotateX: function(angle) { var c = Math.cos(-angle); var s = Math.sin(-angle); this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]) }, invRotateY: function(angle) { var c = Math.cos(-angle); var s = Math.sin(-angle); this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]) }, invRotateZ: function(angle) { var c = Math.cos(-angle); var s = Math.sin(-angle); this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) }, invScale: function(x, y, z) { this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]) } }; var PMatrixStack = p.PMatrixStack = function() { this.matrixStack = [] }; PMatrixStack.prototype.load = function() { var tmpMatrix = drawing.$newPMatrix(); if (arguments.length === 1) tmpMatrix.set(arguments[0]); else tmpMatrix.set(arguments); this.matrixStack.push(tmpMatrix) }; Drawing2D.prototype.$newPMatrix = function() { return new PMatrix2D }; Drawing3D.prototype.$newPMatrix = function() { return new PMatrix3D }; PMatrixStack.prototype.push = function() { this.matrixStack.push(this.peek()) }; PMatrixStack.prototype.pop = function() { return this.matrixStack.pop() }; PMatrixStack.prototype.peek = function() { var tmpMatrix = drawing.$newPMatrix(); tmpMatrix.set(this.matrixStack[this.matrixStack.length - 1]); return tmpMatrix };

PMatrixStack.prototype.mult = function(matrix) { this.matrixStack[this.matrixStack.length - 1].apply(matrix) }; p.split = function(str, delim) { return str.split(delim) }; p.splitTokens = function(str, tokens) { if (tokens === undef) return str.split(/\s+/g); var chars = tokens.split(/()/g), buffer = "", len = str.length, i, c, tokenized = []; for (i = 0; i < len; i++) { c = str[i]; if (chars.indexOf(c) > -1) { if (buffer !== "") tokenized.push(buffer); buffer = "" } else buffer += c } if (buffer !== "") tokenized.push(buffer); return tokenized }; p.append = function(array, element) { array[array.length] = element; return array }; p.concat = function(array1, array2) { return array1.concat(array2) }; p.sort = function(array, numElem) { var ret = []; if (array.length > 0) { var elemsToCopy = numElem > 0 ? numElem : array.length; for (var i = 0; i < elemsToCopy; i++) ret.push(array[i]); if (typeof array[0] === "string") ret.sort(); else ret.sort(function(a, b) { return a - b }); if (numElem > 0) for (var j = ret.length; j < array.length; j++) ret.pus h(array[j]) } return ret }; p.splice = function(array, value, index) { if (value.length === 0) return array; if (value instanceof Array) for (var i = 0, j = index; i < value.length; j ++, i++) array.splice(j, 0, value[i]); else array.splice(index, 0, value); return array }; p.subset = function(array, offset, length) { var end = length !== undef ? offset + length : array.length; return array.slice(offset, end) }; p.join = function(array, seperator) { return array.join(seperator) }; p.shorten = function(ary) { var newary = []; var len = ary.length;

for (var i = 0; i < len; i++) newary[i] = ary[i]; newary.pop(); return newary }; p.expand = function(ary, targetSize) { var temp = ary.slice(0), newSize = targetSize || ary.length * 2; temp.length = newSize; return temp }; p.arrayCopy = function() { var src, srcPos = 0, dest, destPos = 0, length; if (arguments.length === 2) { src = arguments[0]; dest = arguments[1]; length = src.length } else if (arguments.length === 3) { src = arguments[0]; dest = arguments[1]; length = arguments[2] } else if (arguments.length === 5) { src = arguments[0]; srcPos = arguments[1]; dest = arguments[2]; destPos = arguments[3]; length = arguments[4] } for (var i = srcPos, j = destPos; i < length + srcPos; i++, j++) if (dest[ j] !== undef) dest[j] = src[i]; else throw "array index out of bounds exception"; }; p.reverse = function(array) { return array.reverse() }; p.mix = function(a, b, f) { return a + ((b - a) * f >> 8) }; p.peg = function(n) { return n < 0 ? 0 : n > 255 ? 255 : n }; p.modes = function() { var ALPHA_MASK = 4278190080, RED_MASK = 16711680, GREEN_MASK = 65280, BLUE_MASK = 255, min = Math.min, max = Math.max; function applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) { var a = min(((c1 & 4278190080) >>> 24) + f, 255) << 24; var r = ar + ((cr - ar) * f >> 8); r = (r < 0 ? 0 : r > 255 ? 255 : r) << 16; var g = ag + ((cg - ag) * f >> 8); g = (g < 0 ? 0 : g > 255 ? 255 : g) << 8; var b = ab + ((cb - ab) * f >> 8); b = b < 0 ? 0 : b > 255 ? 255 : b; return a | r | g | b }

return { replace: function(c1, c2) { return c2 }, blend: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = c1 & RED_MASK, ag = c1 & GREEN_MASK, ab = c1 & BLUE_MASK, br = c2 & RED_MASK, bg = c2 & GREEN_MASK, bb = c2 & BLUE_MASK; return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | ar + ((br - ar ) * f >> 8) & RED_MASK | ag + ((bg - ag) * f >> 8) & GREEN_MASK | ab + ((bb - ab ) * f >> 8) & BLUE_MASK }, add: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24; return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | min((c1 & RED_ MASK) + ((c2 & RED_MASK) >> 8) * f, RED_MASK) & RED_MASK | min((c1 & GREEN_MASK) + ((c2 & GREEN_MASK) >> 8) * f, GREEN_MASK) & GREEN_MASK | min((c1 & BLUE_MASK) + ((c2 & BLUE_MASK) * f >> 8), BLUE_MASK) }, subtract: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24; return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | max((c1 & RED_ MASK) - ((c2 & RED_MASK) >> 8) * f, GREEN_MASK) & RED_MASK | max((c1 & GREEN_MAS K) - ((c2 & GREEN_MASK) >> 8) * f, BLUE_MASK) & GREEN_MASK | max((c1 & BLUE_MASK ) - ((c2 & BLUE_MASK) * f >> 8), 0) }, lightest: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24; return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | max(c1 & RED_M ASK, ((c2 & RED_MASK) >> 8) * f) & RED_MASK | max(c1 & GREEN_MASK, ((c2 & GREEN_ MASK) >> 8) * f) & GREEN_MASK | max(c1 & BLUE_MASK, (c2 & BLUE_MASK) * f >> 8) }, darkest: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = c1 & RED_MASK, ag = c1 & GREEN_MASK, ab = c1 & BLUE_MASK, br = min(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f), bg = min(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f), bb = min(c1 & BLUE_MASK, (c2 & BLUE_MASK) * f >> 8); return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | ar + ((br - ar ) * f >> 8) & RED_MASK | ag + ((bg - ag) * f >> 8) & GREEN_MASK | ab + ((bb - ab ) * f >> 8) & BLUE_MASK }, difference: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK, cr = ar > br ? ar - br : br - ar, cg = ag > bg ? ag - bg : bg - ag, cb = ab > bb ? ab - bb : bb - ab; return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb)

}, exclusion: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK, cr = ar + br - (ar * br >> 7), cg = ag + bg - (ag * bg >> 7), cb = ab + bb - (ab * bb >> 7); return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) }, multiply: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK, cr = ar * br >> 8, cg = ag * bg >> 8, cb = ab * bb >> 8; return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) }, screen: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK, cr = 255 - ((255 - ar) * (255 - br) >> 8), cg = 255 - ((255 - ag) * (255 - bg) >> 8), cb = 255 - ((255 - ab) * (255 - bb) >> 8); return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) }, hard_light: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK, cr = br < 128 ? ar * br >> 7 : 255 - ((255 - ar) * (255 - br) >> 7), cg = bg < 128 ? ag * bg >> 7 : 255 - ((255 - ag) * (255 - bg) >> 7), cb = bb < 128 ? ab * bb >> 7 : 255 - ((255 - ab) * (255 - bb) >> 7); return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) }, soft_light: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8,

bb = cr = cg = cb = return

c2 & BLUE_MASK, (ar * br >> 7) + (ag * bg >> 7) + (ab * bb >> 7) + applyMode(c1, f,

(ar (ag (ab ar,

* ar >> * ag >> * ab >> ag, ab,

8) - (ar * ar * 8) - (ag * ag * 8) - (ab * ab * br, bg, bb, cr,

br >> 15), bg >> 15), bb >> 15); cg, cb)

}, overlay: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK, cr = ar < 128 ? ar * br >> 7 : 255 - ((255 - ar) * (255 - br) >> 7), cg = ag < 128 ? ag * bg >> 7 : 255 - ((255 - ag) * (255 - bg) >> 7), cb = ab < 128 ? ab * bb >> 7 : 255 - ((255 - ab) * (255 - bb) >> 7); return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) }, dodge: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK; var cr = 255; if (br !== 255) { cr = (ar << 8) / (255 - br); cr = cr < 0 ? 0 : cr > 255 ? 255 : cr } var cg = 255; if (bg !== 255) { cg = (ag << 8) / (255 - bg); cg = cg < 0 ? 0 : cg > 255 ? 255 : cg } var cb = 255; if (bb !== 255) { cb = (ab << 8) / (255 - bb); cb = cb < 0 ? 0 : cb > 255 ? 255 : cb } return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) }, burn: function(c1, c2) { var f = (c2 & ALPHA_MASK) >>> 24, ar = (c1 & RED_MASK) >> 16, ag = (c1 & GREEN_MASK) >> 8, ab = c1 & BLUE_MASK, br = (c2 & RED_MASK) >> 16, bg = (c2 & GREEN_MASK) >> 8, bb = c2 & BLUE_MASK; var cr = 0; if (br !== 0) { cr = (255 - ar << 8) / br; cr = 255 - (cr < 0 ? 0 : cr > 255 ? 255 : cr) } var cg = 0; if (bg !== 0) { cg = (255 - ag << 8) / bg;

cg = } var cb if (bb cb = cb = } return } } }();

255 - (cg < 0 ? 0 : cg > 255 ? 255 : cg) = 0; !== 0) { (255 - ab << 8) / bb; 255 - (cb < 0 ? 0 : cb > 255 ? 255 : cb) applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb)

function color$4(aValue1, aValue2, aValue3, aValue4) { var r, g, b, a; if (curColorMode === 3) { var rgb = p.color.toRGB(aValue1, aValue2, aValue3); r = rgb[0]; g = rgb[1]; b = rgb[2] } else { r = Math.round(255 * (aValue1 / colorModeX)); g = Math.round(255 * (aValue2 / colorModeY)); b = Math.round(255 * (aValue3 / colorModeZ)) } a = Math.round(255 * (aValue4 / colorModeA)); r = r < 0 ? 0 : r; g = g < 0 ? 0 : g; b = b < 0 ? 0 : b; a = a < 0 ? 0 : a; r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; b = b > 255 ? 255 : b; a = a > 255 ? 255 : a; return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 25 5 } function color$2(aValue1, aValue2) { var a; if (aValue1 & 4278190080) { a = Math.round(255 * (aValue2 / colorModeA)); a = a > 255 ? 255 : a; a = a < 0 ? 0 : a; return aValue1 - (aValue1 & 4278190080) + (a << 24 & 4278190080) } if (curColorMode === 1) return color$4(aValue1, aValue1, aValue1, aValue2) ; if (curColorMode === 3) return color$4(0, 0, aValue1 / colorModeX * colorM odeZ, aValue2) } function color$1(aValue1) { if (aValue1 <= colorModeX && aValue1 >= 0) { if (curColorMode === 1) return color$4(aValue1, aValue1, aValue1, colorM odeA); if (curColorMode === 3) return color$4(0, 0, aValue1 / colorModeX * colo rModeZ, colorModeA) } if (aValue1) { if (aValue1 > 2147483647) aValue1 -= 4294967296; return aValue1 }

} p.color = function(aValue1, aValue2, aValue3, aValue4) { if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef && aValue4 !== undef) return color$4(aValue1, aValue2, aValue3, aValue4); if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef) return co lor$4(aValue1, aValue2, aValue3, colorModeA); if (aValue1 !== undef && aValue2 !== undef) return color$2(aValue1, aValue 2); if (typeof aValue1 === "number") return color$1(aValue1); return color$4(colorModeX, colorModeY, colorModeZ, colorModeA) }; p.color.toString = function(colorInt) { return "rgba(" + ((colorInt >> 16) & 255) + "," + ((colorInt >> 8) & 255) + "," + (colorInt & 255) + "," + ((colorInt >> 24) & 255) / 255 + ")" }; p.color.toInt = function(r, g, b, a) { return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 25 5 }; p.color.toArray = function(colorInt) { return [(colorInt >> 16) & 255, (colorInt >> 8) & 255, colorInt & 255, (co lorInt >> 24) & 255] }; p.color.toGLArray = function(colorInt) { return [((colorInt & 16711680) >>> 16) / 255, ((colorInt >> 8) & 255) / 25 5, (colorInt & 255) / 255, ((colorInt >> 24) & 255) / 255] }; p.color.toRGB = function(h, s, b) { h = h > colorModeX ? colorModeX : h; s = s > colorModeY ? colorModeY : s; b = b > colorModeZ ? colorModeZ : b; h = h / colorModeX * 360; s = s / colorModeY * 100; b = b / colorModeZ * 100; var br = Math.round(b / 100 * 255); if (s === 0) return [br, br, br]; var hue = h % 360; var f = hue % 60; var p = Math.round(b * (100 - s) / 1E4 * 255); var q = Math.round(b * (6E3 - s * f) / 6E5 * 255); var t = Math.round(b * (6E3 - s * (60 - f)) / 6E5 * 255); switch (Math.floor(hue / 60)) { case 0: return [br, t, p]; case 1: return [q, br, p]; case 2: return [p, br, t]; case 3: return [p, q, br]; case 4: return [t, p, br]; case 5: return [br, p, q] } }; function colorToHSB(colorInt) { var red, green, blue; red = ((colorInt >> 16) & 255) / 255;

green = ((colorInt >> 8) & 255) / 255; blue = (colorInt & 255) / 255; var max = p.max(p.max(red, green), blue), min = p.min(p.min(red, green), blue), hue, saturation; if (min === max) return [0, 0, max * colorModeZ]; saturation = (max - min) / max; if (red === max) hue = (green - blue) / (max - min); else if (green === max) hue = 2 + (blue - red) / (max - min); else hue = 4 + (red - green) / (max - min); hue /= 6; if (hue < 0) hue += 1; else if (hue > 1) hue -= 1; return [hue * colorModeX, saturation * colorModeY, max * colorModeZ] } p.brightness = function(colInt) { return colorToHSB(colInt)[2] }; p.saturation = function(colInt) { return colorToHSB(colInt)[1] }; p.hue = function(colInt) { return colorToHSB(colInt)[0] }; p.red = function(aColor) { return ((aColor >> 16) & 255) / 255 * colorModeX }; p.green = function(aColor) { return ((aColor & 65280) >>> 8) / 255 * colorModeY }; p.blue = function(aColor) { return (aColor & 255) / 255 * colorModeZ }; p.alpha = function(aColor) { return ((aColor >> 24) & 255) / 255 * colorModeA }; p.lerpColor = function(c1, c2, amt) { var r, g, b, a, r1, g1, b1, a1, r2, g2, b2, a2; var hsb1, hsb2, rgb, h, s; var colorBits1 = p.color(c1); var colorBits2 = p.color(c2); if (curColorMode === 3) { hsb1 = colorToHSB(colorBits1); a1 = ((colorBits1 >> 24) & 255) / colorModeA; hsb2 = colorToHSB(colorBits2); a2 = ((colorBits2 & 4278190080) >>> 24) / colorModeA; h = p.lerp(hsb1[0], hsb2[0], amt); s = p.lerp(hsb1[1], hsb2[1], amt); b = p.lerp(hsb1[2], hsb2[2], amt); rgb = p.color.toRGB(h, s, b); a = p.lerp(a1, a2, amt) * colorModeA; return a << 24 & 4278190080 | (rgb[0] & 255) << 16 | (rgb[1] & 255) << 8 | rgb[2] & 255 } r1 = (colorBits1 >> 16) & 255; g1 = (colorBits1 >> 8) & 255; b1 = colorBits1 & 255; a1 = ((colorBits1 >> 24) & 255) / colorModeA; r2 = (colorBits2 & 16711680) >>> 16; g2 = (colorBits2 >> 8) & 255;

b2 = colorBits2 & 255; a2 = ((colorBits2 >> 24) & 255) / colorModeA; r = p.lerp(r1, r2, amt) | 0; g = p.lerp(g1, g2, amt) | 0; b = p.lerp(b1, b2, amt) | 0; a = p.lerp(a1, a2, amt) * colorModeA; return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 25 5 }; p.colorMode = function() { curColorMode = arguments[0]; if (arguments.length > 1) { colorModeX = arguments[1]; colorModeY = arguments[2] || arguments[1]; colorModeZ = arguments[3] || arguments[1]; colorModeA = arguments[4] || arguments[1] } }; p.blendColor = function(c1, c2, mode) { if (mode === 0) return p.modes.replace(c1, c2); else if (mode === 1) return p.modes.blend(c1, c2); else if (mode === 2) return p.modes.add(c1, c2); else if (mode === 4) return p.modes.subtract(c1, c2); else if (mode === 8) return p.modes.lightest(c1, c2); else if (mode === 16) return p.modes.darkest(c1, c2); else if (mode === 32) return p.modes.difference(c1, c2); else if (mode === 64) return p.modes.exclusion(c1, c2); else if (mode === 128) return p.modes.multiply(c1, c2); else if (mode === 256) return p.modes.screen(c1, c2); else if (mode === 1024) return p.modes.hard_light(c1, c2); else if (mode === 2048) return p.modes.soft_light(c1, c2); else if (mode === 512) return p.modes.overlay(c1, c2); else if (mode === 4096) return p.modes.dodge(c1, c2); else if (mode === 8192) return p.modes.burn(c1, c2) }; function saveContext() { curContext.save() } function restoreContext() { curContext.restore(); isStrokeDirty = true; isFillDirty = true } p.printMatrix = function() { modelView.print() }; Drawing2D.prototype.translate = function(x, y) { modelView.translate(x, y); modelViewInv.invTranslate(x, y); curContext.translate(x, y) }; Drawing3D.prototype.translate = function(x, y, z) { modelView.translate(x, y, z); modelViewInv.invTranslate(x, y, z) }; Drawing2D.prototype.scale = function(x, y) { modelView.scale(x, y); modelViewInv.invScale(x, y); curContext.scale(x, y || x)

}; Drawing3D.prototype.scale = function(x, y, z) { modelView.scale(x, y, z); modelViewInv.invScale(x, y, z) }; Drawing2D.prototype.transform = function(pmatrix) { var e = pmatrix.array(); curContext.transform(e[0], e[3], e[1], e[4], e[2], e[5]) }; Drawing3D.prototype.transformm = function(pmatrix3d) { throw "p.transform is currently not supported in 3D mode"; }; Drawing2D.prototype.pushMatrix = function() { userMatrixStack.load(modelView); userReverseMatrixStack.load(modelViewInv); saveContext() }; Drawing3D.prototype.pushMatrix = function() { userMatrixStack.load(modelView); userReverseMatrixStack.load(modelViewInv) }; Drawing2D.prototype.popMatrix = function() { modelView.set(userMatrixStack.pop()); modelViewInv.set(userReverseMatrixStack.pop()); restoreContext() }; Drawing3D.prototype.popMatrix = function() { modelView.set(userMatrixStack.pop()); modelViewInv.set(userReverseMatrixStack.pop()) }; Drawing2D.prototype.resetMatrix = function() { modelView.reset(); modelViewInv.reset(); curContext.setTransform(1, 0, 0, 1, 0, 0) }; Drawing3D.prototype.resetMatrix = function() { modelView.reset(); modelViewInv.reset() }; DrawingShared.prototype.applyMatrix = function() { var a = arguments; modelView.apply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9] , a[10], a[11], a[12], a[13], a[14], a[15]); modelViewInv.invApply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8] , a[9], a[10], a[11], a[12], a[13], a[14], a[15]) }; Drawing2D.prototype.applyMatrix = function() { var a = arguments; for (var cnt = a.length; cnt < 16; cnt++) a[cnt] = 0; a[10] = a[15] = 1; DrawingShared.prototype.applyMatrix.apply(this, a) }; p.rotateX = function(angleInRadians) { modelView.rotateX(angleInRadians); modelViewInv.invRotateX(angleInRadians) }; Drawing2D.prototype.rotateZ = function() { throw "rotateZ() is not supported in 2D mode. Use rotate(float) instead."; }; Drawing3D.prototype.rotateZ = function(angleInRadians) {

modelView.rotateZ(angleInRadians); modelViewInv.invRotateZ(angleInRadians) }; p.rotateY = function(angleInRadians) { modelView.rotateY(angleInRadians); modelViewInv.invRotateY(angleInRadians) }; Drawing2D.prototype.rotate = function(angleInRadians) { modelView.rotateZ(angleInRadians); modelViewInv.invRotateZ(angleInRadians); curContext.rotate(angleInRadians) }; Drawing3D.prototype.rotate = function(angleInRadians) { p.rotateZ(angleInRadians) }; Drawing2D.prototype.shearX = function(angleInRadians) { modelView.shearX(angleInRadians); curContext.transform(1, 0, angleInRadians, 1, 0, 0) }; Drawing3D.prototype.shearX = function(angleInRadians) { modelView.shearX(angleInRadians) }; Drawing2D.prototype.shearY = function(angleInRadians) { modelView.shearY(angleInRadians); curContext.transform(1, angleInRadians, 0, 1, 0, 0) }; Drawing3D.prototype.shearY = function(angleInRadians) { modelView.shearY(angleInRadians) }; p.pushStyle = function() { saveContext(); p.pushMatrix(); var newState = { "doFill": doFill, "currentFillColor": currentFillColor, "doStroke": doStroke, "currentStrokeColor": currentStrokeColor, "curTint": curTint, "curRectMode": curRectMode, "curColorMode": curColorMode, "colorModeX": colorModeX, "colorModeZ": colorModeZ, "colorModeY": colorModeY, "colorModeA": colorModeA, "curTextFont": curTextFont, "horizontalTextAlignment": horizontalTextAlignment, "verticalTextAlignment": verticalTextAlignment, "textMode": textMode, "curFontName": curFontName, "curTextSize": curTextSize, "curTextAscent": curTextAscent, "curTextDescent": curTextDescent, "curTextLeading": curTextLeading }; styleArray.push(newState) }; p.popStyle = function() { var oldState = styleArray.pop(); if (oldState) { restoreContext();

p.popMatrix(); doFill = oldState.doFill; currentFillColor = oldState.currentFillColor; doStroke = oldState.doStroke; currentStrokeColor = oldState.currentStrokeColor; curTint = oldState.curTint; curRectMode = oldState.curRectMode; curColorMode = oldState.curColorMode; colorModeX = oldState.colorModeX; colorModeZ = oldState.colorModeZ; colorModeY = oldState.colorModeY; colorModeA = oldState.colorModeA; curTextFont = oldState.curTextFont; curFontName = oldState.curFontName; curTextSize = oldState.curTextSize; horizontalTextAlignment = oldState.horizontalTextAlignment; verticalTextAlignment = oldState.verticalTextAlignment; textMode = oldState.textMode; curTextAscent = oldState.curTextAscent; curTextDescent = oldState.curTextDescent; curTextLeading = oldState.curTextLeading } else throw "Too many popStyle() without enough pushStyle()"; }; p.year = function() { return (new Date).getFullYear() }; p.month = function() { return (new Date).getMonth() + 1 }; p.day = function() { return (new Date).getDate() }; p.hour = function() { return (new Date).getHours() }; p.minute = function() { return (new Date).getMinutes() }; p.second = function() { return (new Date).getSeconds() }; p.millis = function() { return Date.now() - start }; function redrawHelper() { var sec = (Date.now() - timeSinceLastFPS) / 1E3; framesSinceLastFPS++; var fps = framesSinceLastFPS / sec; if (sec > 0.5) { timeSinceLastFPS = Date.now(); framesSinceLastFPS = 0; p.__frameRate = fps } p.frameCount++ } Drawing2D.prototype.redraw = function() { redrawHelper(); curContext.lineWidth = lineWidth; var pmouseXLastEvent = p.pmouseX,

pmouseYLastEvent = p.pmouseY; p.pmouseX = pmouseXLastFrame; p.pmouseY = pmouseYLastFrame; saveContext(); p.draw(); restoreContext(); pmouseXLastFrame = p.mouseX; pmouseYLastFrame = p.mouseY; p.pmouseX = pmouseXLastEvent; p.pmouseY = pmouseYLastEvent }; Drawing3D.prototype.redraw = function() { redrawHelper(); var pmouseXLastEvent = p.pmouseX, pmouseYLastEvent = p.pmouseY; p.pmouseX = pmouseXLastFrame; p.pmouseY = pmouseYLastFrame; curContext.clear(curContext.DEPTH_BUFFER_BIT); curContextCache = { attributes: {}, locations: {} }; p.noLights(); p.lightFalloff(1, 0, 0); p.shininess(1); p.ambient(255, 255, 255); p.specular(0, 0, 0); p.emissive(0, 0, 0); p.camera(); p.draw(); pmouseXLastFrame = p.mouseX; pmouseYLastFrame = p.mouseY; p.pmouseX = pmouseXLastEvent; p.pmouseY = pmouseYLastEvent }; p.noLoop = function() { doLoop = false; loopStarted = false; clearInterval(looping); curSketch.onPause() }; p.loop = function() { if (loopStarted) return; timeSinceLastFPS = Date.now(); framesSinceLastFPS = 0; looping = window.setInterval(function() { try { curSketch.onFrameStart(); p.redraw(); curSketch.onFrameEnd() } catch(e_loop) { window.clearInterval(looping); throw e_loop; } }, curMsPerFrame); doLoop = true; loopStarted = true; curSketch.onLoop() };

p.frameRate = function(aRate) { curFrameRate = aRate; curMsPerFrame = 1E3 / curFrameRate; if (doLoop) { p.noLoop(); p.loop() } }; var eventHandlers = []; function attachEventHandler(elem, type, fn) { if (elem.addEventListener) elem.addEventListener(type, fn, false); else elem.attachEvent("on" + type, fn); eventHandlers.push({ elem: elem, type: type, fn: fn }) } function detachEventHandler(eventHandler) { var elem = eventHandler.elem, type = eventHandler.type, fn = eventHandler.fn; if (elem.removeEventListener) elem.removeEventListener(type, fn, false); else if (elem.detachEvent) elem.detachEvent("on" + type, fn) } p.exit = function() { window.clearInterval(looping); removeInstance(p.externals.canvas.id); delete curElement.onmousedown; for (var lib in Processing.lib) if (Processing.lib.hasOwnProperty(lib)) if (Processing.lib[lib].hasOwnProperty("detach")) Processing.lib[lib].detach(p); var i = eventHandlers.length; while (i--) detachEventHandler(eventHandlers[i]); curSketch.onExit() }; p.cursor = function() { if (arguments.length > 1 || arguments.length === 1 && arguments[0] instanc eof p.PImage) { var image = arguments[0], x, y; if (arguments.length >= 3) { x = arguments[1]; y = arguments[2]; if (x < 0 || y < 0 || y >= image.height || x >= image.width) throw "x and y must be non-negative and less than the dimensions of the image"; } else { x = image.width >>> 1; y = image.height >>> 1 } var imageDataURL = image.toDataURL(); var style = 'url("' + imageDataURL + '") ' + x + " " + y + ", default"; curCursor = curElement.style.cursor = style } else if (arguments.length === 1) { var mode = arguments[0]; curCursor = curElement.style.cursor = mode } else curCursor = curElement.style.cursor = oldCursor }; p.noCursor = function() { curCursor = curElement.style.cursor = PConstants.NOCURSOR

}; p.link = function(href, target) { if (target !== undef) window.open(href, target); else window.location = href }; p.beginDraw = nop; p.endDraw = nop; Drawing2D.prototype.toImageData = function(x, y, w, h) { x = x !== undef ? x : 0; y = y !== undef ? y : 0; w = w !== undef ? w : p.width; h = h !== undef ? h : p.height; return curContext.getImageData(x, y, w, h) }; Drawing3D.prototype.toImageData = function(x, y, w, h) { x = x !== undef ? x : 0; y = y !== undef ? y : 0; w = w !== undef ? w : p.width; h = h !== undef ? h : p.height; var c = document.createElement("canvas"), ctx = c.getContext("2d"), obj = ctx.createImageData(w, h), uBuff = new Uint8Array(w * h * 4); curContext.readPixels(x, y, w, h, curContext.RGBA, curContext.UNSIGNED_BYT E, uBuff); for (var i = 0, ul = uBuff.length, obj_data = obj.data; i < ul; i++) obj_d ata[i] = uBuff[(h - 1 - Math.floor(i / 4 / w)) * w * 4 + i % (w * 4)]; return obj }; p.status = function(text) { window.status = text }; p.binary = function(num, numBits) { var bit; if (numBits > 0) bit = numBits; else if (num instanceof Char) { bit = 16; num |= 0 } else { bit = 32; while (bit > 1 && !(num >>> bit - 1 & 1)) bit-} var result = ""; while (bit > 0) result += num >>> --bit & 1 ? "1" : "0"; return result }; p.unbinary = function(binaryString) { var i = binaryString.length - 1, mask = 1, result = 0; while (i >= 0) { var ch = binaryString[i--]; if (ch !== "0" && ch !== "1") throw "the value passed into unbinary was not an 8 bit binary number"; if (ch === "1") result += mask; mask <<= 1 } return result };

function nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) { var sign = value < 0 ? minus : plus; var autoDetectDecimals = rightDigits === 0; var rightDigitsOfDefault = rightDigits === undef || rightDigits < 0 ? 0 : rightDigits; var absValue = Math.abs(value); if (autoDetectDecimals) { rightDigitsOfDefault = 1; absValue *= 10; while (Math.abs(Math.round(absValue) - absValue) > 1.0E-6 && rightDigits OfDefault < 7) { ++rightDigitsOfDefault; absValue *= 10 } } else if (rightDigitsOfDefault !== 0) absValue *= Math.pow(10, rightDigit sOfDefault); var number, doubled = absValue * 2; if (Math.floor(absValue) === absValue) number = absValue; else if (Math.floor(doubled) === doubled) { var floored = Math.floor(absValue); number = floored + floored % 2 } else number = Math.round(absValue); var buffer = ""; var totalDigits = leftDigits + rightDigitsOfDefault; while (totalDigits > 0 || number > 0) { totalDigits--; buffer = "" + number % 10 + buffer; number = Math.floor(number / 10) } if (group !== undef) { var i = buffer.length - 3 - rightDigitsOfDefault; while (i > 0) { buffer = buffer.substring(0, i) + group + buffer.substring(i); i -= 3 } } if (rightDigitsOfDefault > 0) return sign + buffer.substring(0, buffer.len gth - rightDigitsOfDefault) + "." + buffer.substring(buffer.length - rightDigits OfDefault, buffer.length); return sign + buffer } function nfCore(value, plus, minus, leftDigits, rightDigits, group) { if (value instanceof Array) { var arr = []; for (var i = 0, len = value.length; i < len; i++) arr.push(nfCoreScalar( value[i], plus, minus, leftDigits, rightDigits, group)); return arr } return nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) } p.nf = function(value, leftDigits, rightDigits) { return nfCore(value, "", "-", leftDigits, rightDigits) }; p.nfs = function(value, leftDigits, rightDigits) { return nfCore(value, " ", "-", leftDigits, rightDigits) }; p.nfp = function(value, leftDigits, rightDigits) { return nfCore(value, "+", "-", leftDigits, rightDigits) }; p.nfc = function(value, leftDigits, rightDigits) {

return nfCore(value, "", "-", leftDigits, rightDigits, ",") }; var decimalToHex = function(d, padding) { padding = padding === undef || padding === null ? padding = 8 : padding; if (d < 0) d = 4294967295 + d + 1; var hex = Number(d).toString(16).toUpperCase(); while (hex.length < padding) hex = "0" + hex; if (hex.length >= padding) hex = hex.substring(hex.length - padding, hex.l ength); return hex }; p.hex = function(value, len) { if (arguments.length === 1) if (value instanceof Char) len = 4; else len = 8; return decimalToHex(value, len) }; function unhexScalar(hex) { var value = parseInt("0x" + hex, 16); if (value > 2147483647) value -= 4294967296; return value } p.unhex = function(hex) { if (hex instanceof Array) { var arr = []; for (var i = 0; i < hex.length; i++) arr.push(unhexScalar(hex[i])); return arr } return unhexScalar(hex) }; p.loadStrings = function(filename) { if (localStorage[filename]) return localStorage[filename].split("\n"); var filecontent = ajax(filename); if (typeof filecontent !== "string" || filecontent === "") return []; filecontent = filecontent.replace(/(\r\n?)/g, "\n").replace(/\n$/, ""); return filecontent.split("\n") }; p.saveStrings = function(filename, strings) { localStorage[filename] = strings.join("\n") }; p.loadBytes = function(url) { var string = ajax(url); var ret = []; for (var i = 0; i < string.length; i++) ret.push(string.charCodeAt(i)); return ret }; function removeFirstArgument(args) { return Array.prototype.slice.call(args, 1) } p.matchAll = function(aString, aRegExp) { var results = [], latest; var regexp = new RegExp(aRegExp, "g"); while ((latest = regexp.exec(aString)) !== null) { results.push(latest); if (latest[0].length === 0)++regexp.lastIndex } return results.length > 0 ? results : null };

p.__contains = function(subject, subStr) { if (typeof subject !== "string") return subject.contains.apply(subject, re moveFirstArgument(arguments)); return subject !== null && subStr !== null && typeof subStr === "string" & & subject.indexOf(subStr) > -1 }; p.__replaceAll = function(subject, regex, replacement) { if (typeof subject !== "string") return subject.replaceAll.apply(subject, removeFirstArgument(arguments)); return subject.replace(new RegExp(regex, "g"), replacement) }; p.__replaceFirst = function(subject, regex, replacement) { if (typeof subject !== "string") return subject.replaceFirst.apply(subject , removeFirstArgument(arguments)); return subject.replace(new RegExp(regex, ""), replacement) }; p.__replace = function(subject, what, replacement) { if (typeof subject !== "string") return subject.replace.apply(subject, rem oveFirstArgument(arguments)); if (what instanceof RegExp) return subject.replace(what, replacement); if (typeof what !== "string") what = what.toString(); if (what === "") return subject; var i = subject.indexOf(what); if (i < 0) return subject; var j = 0, result = ""; do { result += subject.substring(j, i) + replacement; j = i + what.length } while ((i = subject.indexOf(what, j)) >= 0); return result + subject.substring(j) }; p.__equals = function(subject, other) { if (subject.equals instanceof Function) return subject.equals.apply(subject, removeFirstArgument(argumen ts)); return subject.valueOf() === other.valueOf() }; p.__equalsIgnoreCase = function(subject, other) { if (typeof subject !== "string") return subject.equalsIgnoreCase.apply(sub ject, removeFirstArgument(arguments)); return subject.toLowerCase() === other.toLowerCase() }; p.__toCharArray = function(subject) { if (typeof subject !== "string") return subject.toCharArray.apply(subject, removeFirstArgument(arguments)); var chars = []; for (var i = 0, len = subject.length; i < len; ++i) chars[i] = new Char(su bject.charAt(i)); return chars }; p.__split = function(subject, regex, limit) { if (typeof subject !== "string") return subject.split.apply(subject, remov eFirstArgument(arguments)); var pattern = new RegExp(regex); if (limit === undef || limit < 1) return subject.split(pattern); var result = [], currSubject = subject, pos; while ((pos = currSubject.search(pattern)) !== -1 && result.length < limit

- 1) { var match = pattern.exec(currSubject).toString(); result.push(currSubject.substring(0, pos)); currSubject = currSubject.substring(pos + match.length) } if (pos !== -1 || currSubject !== "") result.push(currSubject); return result }; p.__codePointAt = function(subject, idx) { var code = subject.charCodeAt(idx), hi, low; if (55296 <= code && code <= 56319) { hi = code; low = subject.charCodeAt(idx + 1); return (hi - 55296) * 1024 + (low - 56320) + 65536 } return code }; p.match = function(str, regexp) { return str.match(regexp) }; p.__matches = function(str, regexp) { return (new RegExp(regexp)).test(str) }; p.__startsWith = function(subject, prefix, toffset) { if (typeof subject !== "string") return subject.startsWith.apply(subject, removeFirstArgument(arguments)); toffset = toffset || 0; if (toffset < 0 || toffset > subject.length) return false; return prefix === "" || prefix === subject ? true : subject.indexOf(prefix ) === toffset }; p.__endsWith = function(subject, suffix) { if (typeof subject !== "string") return subject.endsWith.apply(subject, re moveFirstArgument(arguments)); var suffixLen = suffix ? suffix.length : 0; return suffix === "" || suffix === subject ? true : subject.indexOf(suffix ) === subject.length - suffixLen }; p.__hashCode = function(subject) { if (subject.hashCode instanceof Function) return subject.hashCode.apply(subject, removeFirstArgument(argum ents)); return virtHashCode(subject) }; p.__printStackTrace = function(subject) { p.println("Exception: " + subject.toString()) }; var logBuffer = []; p.println = function(message) { var bufferLen = logBuffer.length; if (bufferLen) { Processing.logger.log(logBuffer.join("")); logBuffer.length = 0 } if (arguments.length === 0 && bufferLen === 0) Processing.logger.log(""); else if (arguments.length !== 0) Processing.logger.log(message) }; p.print = function(message) { logBuffer.push(message)

}; p.str = function(val) { if (val instanceof Array) { var arr = []; for (var i = 0; i < val.length; i++) arr.push(val[i].toString() + ""); return arr } return val.toString() + "" }; p.trim = function(str) { if (str instanceof Array) { var arr = []; for (var i = 0; i < str.length; i++) arr.push(str[i].replace(/^\s*/, "") .replace(/\s*$/, "").replace(/\r*$/, "")); return arr } return str.replace(/^\s*/, "").replace(/\s*$/, "").replace(/\r*$/, "") }; function booleanScalar(val) { if (typeof val === "number") return val !== 0; if (typeof val === "boolean") return val; if (typeof val === "string") return val.toLowerCase() === "true"; if (val instanceof Char) return val.code === 49 || val.code === 84 || val. code === 116 } p.parseBoolean = function(val) { if (val instanceof Array) { var ret = []; for (var i = 0; i < val.length; i++) ret.push(booleanScalar(val[i])); return ret } return booleanScalar(val) }; p.parseByte = function(what) { if (what instanceof Array) { var bytes = []; for (var i = 0; i < what.length; i++) bytes.push(0 - (what[i] & 128) | w hat[i] & 127); return bytes } return 0 - (what & 128) | what & 127 }; p.parseChar = function(key) { if (typeof key === "number") return new Char(String.fromCharCode(key & 655 35)); if (key instanceof Array) { var ret = []; for (var i = 0; i < key.length; i++) ret.push(new Char(String.fromCharCo de(key[i] & 65535))); return ret } throw "char() may receive only one argument of type int, byte, int[], or b yte[]."; }; function floatScalar(val) { if (typeof val === "number") return val; if (typeof val === "boolean") return val ? 1 : 0; if (typeof val === "string") return parseFloat(val);

if (val instanceof Char) return val.code } p.parseFloat = function(val) { if (val instanceof Array) { var ret = []; for (var i = 0; i < val.length; i++) ret.push(floatScalar(val[i])); return ret } return floatScalar(val) }; function intScalar(val, radix) { if (typeof val === "number") return val & 4294967295; if (typeof val === "boolean") return val ? 1 : 0; if (typeof val === "string") { var number = parseInt(val, radix || 10); return number & 4294967295 } if (val instanceof Char) return val.code } p.parseInt = function(val, radix) { if (val instanceof Array) { var ret = []; for (var i = 0; i < val.length; i++) if (typeof val[i] === "string" && ! /^\s*[+\-]?\d+\s*$/.test(val[i])) ret.push(0); else ret.push(intScalar(val[i], radix)); return ret } return intScalar(val, radix) }; p.__int_cast = function(val) { return 0 | val }; p.__instanceof = function(obj, type) { if (typeof type !== "function") throw "Function is expected as type argume nt for instanceof operator"; if (typeof obj === "string") return type === Object || type === String; if (obj instanceof type) return true; if (typeof obj !== "object" || obj === null) return false; var objType = obj.constructor; if (type.$isInterface) { var interfaces = []; while (objType) { if (objType.$interfaces) interfaces = interfaces.concat(objType.$inter faces); objType = objType.$base } while (interfaces.length > 0) { var i = interfaces.shift(); if (i === type) return true; if (i.$interfaces) interfaces = interfaces.concat(i.$interfaces) } return false } while (objType.hasOwnProperty("$base")) { objType = objType.$base; if (objType === type) return true } return false

}; p.abs = Math.abs; p.ceil = Math.ceil; p.constrain = function(aNumber, aMin, aMax) { return aNumber > aMax ? aMax : aNumber < aMin ? aMin : aNumber }; p.dist = function() { var dx, dy, dz; if (arguments.length === 4) { dx = arguments[0] - arguments[2]; dy = arguments[1] - arguments[3]; return Math.sqrt(dx * dx + dy * dy) } if (arguments.length === 6) { dx = arguments[0] - arguments[3]; dy = arguments[1] - arguments[4]; dz = arguments[2] - arguments[5]; return Math.sqrt(dx * dx + dy * dy + dz * dz) } }; p.exp = Math.exp; p.floor = Math.floor; p.lerp = function(value1, value2, amt) { return (value2 - value1) * amt + value1 }; p.log = Math.log; p.mag = function(a, b, c) { if (c) return Math.sqrt(a * a + b * b + c * c); return Math.sqrt(a * a + b * b) }; p.map = function(value, istart, istop, ostart, ostop) { return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)) }; p.max = function() { if (arguments.length === 2) return arguments[0] < arguments[1] ? arguments [1] : arguments[0]; var numbers = arguments.length === 1 ? arguments[0] : arguments; if (! ("length" in numbers && numbers.length > 0)) throw "Non-empty array is expected"; var max = numbers[0], count = numbers.length; for (var i = 1; i < count; ++i) if (max < numbers[i]) max = numbers[i]; return max }; p.min = function() { if (arguments.length === 2) return arguments[0] < arguments[1] ? arguments [0] : arguments[1]; var numbers = arguments.length === 1 ? arguments[0] : arguments; if (! ("length" in numbers && numbers.length > 0)) throw "Non-empty array is expected"; var min = numbers[0], count = numbers.length; for (var i = 1; i < count; ++i) if (min > numbers[i]) min = numbers[i]; return min }; p.norm = function(aNumber, low, high) { return (aNumber - low) / (high - low) }; p.pow = Math.pow; p.round = Math.round;

p.sq = function(aNumber) { return aNumber * aNumber }; p.sqrt = Math.sqrt; p.acos = Math.acos; p.asin = Math.asin; p.atan = Math.atan; p.atan2 = Math.atan2; p.cos = Math.cos; p.degrees = function(aAngle) { return aAngle * 180 / Math.PI }; p.radians = function(aAngle) { return aAngle / 180 * Math.PI }; p.sin = Math.sin; p.tan = Math.tan; var currentRandom = Math.random; p.random = function() { if (arguments.length === 0) return currentRandom(); if (arguments.length === 1) return currentRandom() * arguments[0]; var aMin = arguments[0], aMax = arguments[1]; return currentRandom() * (aMax - aMin) + aMin }; function Marsaglia(i1, i2) { var z = i1 || 362436069, w = i2 || 521288629; var nextInt = function() { z = 36969 * (z & 65535) + (z >>> 16) & 4294967295; w = 18E3 * (w & 65535) + (w >>> 16) & 4294967295; return ((z & 65535) << 16 | w & 65535) & 4294967295 }; this.nextDouble = function() { var i = nextInt() / 4294967296; return i < 0 ? 1 + i : i }; this.nextInt = nextInt } Marsaglia.createRandomized = function() { var now = new Date; return new Marsaglia(now / 6E4 & 4294967295, now & 4294967295) }; p.randomSeed = function(seed) { currentRandom = (new Marsaglia(seed)).nextDouble }; p.Random = function(seed) { var haveNextNextGaussian = false, nextNextGaussian, random; this.nextGaussian = function() { if (haveNextNextGaussian) { haveNextNextGaussian = false; return nextNextGaussian } var v1, v2, s; do { v1 = 2 * random() - 1; v2 = 2 * random() - 1; 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 }; random = seed === undef ? Math.random : (new Marsaglia(seed)).nextDouble }; function PerlinNoise(seed) { var rnd = seed !== undef ? new Marsaglia(seed) : Marsaglia.createRandomize d(); var i, j; var perm = new Uint8Array(512); for (i = 0; i < 256; ++i) perm[i] = i; for (i = 0; i < 256; ++i) { var t = perm[j = rnd.nextInt() & 255]; perm[j] = perm[i]; perm[i] = t } for (i = 0; i < 256; ++i) perm[i + 256] = perm[i]; function grad3d(i, x, y, z) { var h = i & 15; var u = h < 8 ? x : y, v = h < 4 ? y : h === 12 || h === 14 ? x : z; return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v) } function grad2d(i, x, y) { var v = (i & 1) === 0 ? x : y; return (i & 2) === 0 ? -v : v } function grad1d(i, x) { return (i & 1) === 0 ? -x : x } function lerp(t, a, b) { return a + t * (b - a) } this.noise3d = function(x, y, z) { var X = Math.floor(x) & 255, Y = Math.floor(y) & 255, Z = Math.floor(z) & 255; x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z); var fx = (3 - 2 * x) * x * x, fy = (3 - 2 * y) * y * y, fz = (3 - 2 * z) * z * z; var p0 = perm[X] + Y, p00 = perm[p0] + Z, p01 = perm[p0 + 1] + Z, p1 = perm[X + 1] + Y, p10 = perm[p1] + Z, p11 = perm[p1 + 1] + Z; return lerp(fz, lerp(fy, lerp(fx, grad3d(perm[p00], x, y, z), grad3d(per m[p10], x - 1, y, z)), lerp(fx, grad3d(perm[p01], x, y - 1, z), grad3d(perm[p11] , x - 1, y - 1, z))), lerp(fy, lerp(fx, grad3d(perm[p00 + 1], x, y, z - 1), grad 3d(perm[p10 + 1], x - 1, y, z - 1)), lerp(fx, grad3d(perm[p01 + 1], x, y - 1, z - 1), grad3d(perm[p11 + 1], x - 1, y - 1, z - 1)))) };

this.noise2d = function(x, y) { var X = Math.floor(x) & 255, Y = Math.floor(y) & 255; x -= Math.floor(x); y -= Math.floor(y); var fx = (3 - 2 * x) * x * x, fy = (3 - 2 * y) * y * y; var p0 = perm[X] + Y, p1 = perm[X + 1] + Y; return lerp(fy, lerp(fx, grad2d(perm[p0], x, y), grad2d(perm[p1], x - 1, y)), lerp(fx, grad2d(perm[p0 + 1], x, y - 1), grad2d(perm[p1 + 1], x - 1, y - 1 ))) }; this.noise1d = function(x) { var X = Math.floor(x) & 255; x -= Math.floor(x); var fx = (3 - 2 * x) * x * x; return lerp(fx, grad1d(perm[X], x), grad1d(perm[X + 1], x - 1)) } } var noiseProfile = { generator: undef, octaves: 4, fallout: 0.5, seed: undef }; p.noise = function(x, y, z) { if (noiseProfile.generator === undef) noiseProfile.generator = new PerlinN oise(noiseProfile.seed); var generator = noiseProfile.generator; var effect = 1, k = 1, sum = 0; for (var i = 0; i < noiseProfile.octaves; ++i) { effect *= noiseProfile.fallout; switch (arguments.length) { case 1: sum += effect * (1 + generator.noise1d(k * x)) / 2; break; case 2: sum += effect * (1 + generator.noise2d(k * x, k * y)) / 2; break; case 3: sum += effect * (1 + generator.noise3d(k * x, k * y, k * z)) / 2; break } k *= 2 } return sum }; p.noiseDetail = function(octaves, fallout) { noiseProfile.octaves = octaves; if (fallout !== undef) noiseProfile.fallout = fallout }; p.noiseSeed = function(seed) { noiseProfile.seed = seed; noiseProfile.generator = undef }; DrawingShared.prototype.size = function(aWidth, aHeight, aMode) { if (doStroke) p.stroke(0);

if (doFill) p.fill(255); var savedProperties = { fillStyle: curContext.fillStyle, strokeStyle: curContext.strokeStyle, lineCap: curContext.lineCap, lineJoin: curContext.lineJoin }; if (curElement.style.length > 0) { curElement.style.removeProperty("width"); curElement.style.removeProperty("height") } curElement.width = p.width = aWidth || 100; curElement.height = p.height = aHeight || 100; for (var prop in savedProperties) if (savedProperties.hasOwnProperty(prop) ) curContext[prop] = savedProperties[prop]; p.textFont(curTextFont); p.background(); maxPixelsCached = Math.max(1E3, aWidth * aHeight * 0.05); p.externals.context = curContext; for (var i = 0; i < 720; i++) { sinLUT[i] = p.sin(i * (Math.PI / 180) * 0.5); cosLUT[i] = p.cos(i * (Math.PI / 180) * 0.5) } }; Drawing2D.prototype.size = function(aWidth, aHeight, aMode) { if (curContext === undef) { curContext = curElement.getContext("2d"); userMatrixStack = new PMatrixStack; userReverseMatrixStack = new PMatrixStack; modelView = new PMatrix2D; modelViewInv = new PMatrix2D } DrawingShared.prototype.size.apply(this, arguments) }; Drawing3D.prototype.size = function() { var size3DCalled = false; return function size(aWidth, aHeight, aMode) { if (size3DCalled) throw "Multiple calls to size() for 3D renders are not allowed."; size3DCalled = true; function getGLContext(canvas) { var ctxNames = ["experimental-webgl", "webgl", "webkit-3d"], gl; for (var i = 0, l = ctxNames.length; i < l; i++) { gl = canvas.getContext(ctxNames[i], { antialias: false, preserveDrawingBuffer: true }); if (gl) break } return gl } try { curElement.width = p.width = aWidth || 100; curElement.height = p.height = aHeight || 100; curContext = getGLContext(curElement); canTex = curContext.createTexture(); textTex = curContext.createTexture() } catch(e_size) {

Processing.debug(e_size) } if (!curContext) throw "WebGL context is not supported on this browser." ; curContext.viewport(0, 0, curElement.width, curElement.height); curContext.enable(curContext.DEPTH_TEST); curContext.enable(curContext.BLEND); curContext.blendFunc(curContext.SRC_ALPHA, curContext.ONE_MINUS_SRC_ALPH A); programObject2D = createProgramObject(curContext, vertexShaderSrc2D, fra gmentShaderSrc2D); programObjectUnlitShape = createProgramObject(curContext, vertexShaderSr cUnlitShape, fragmentShaderSrcUnlitShape); p.strokeWeight(1); programObject3D = createProgramObject(curContext, vertexShaderSrc3D, fra gmentShaderSrc3D); curContext.useProgram(programObject3D); uniformi("usingTexture3d", programObject3D, "usingTexture", usingTexture ); p.lightFalloff(1, 0, 0); p.shininess(1); p.ambient(255, 255, 255); p.specular(0, 0, 0); p.emissive(0, 0, 0); boxBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, boxBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, boxVerts, curContext.STAT IC_DRAW); boxNormBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, boxNormBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, boxNorms, curContext.STAT IC_DRAW); boxOutlineBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, boxOutlineBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, boxOutlineVerts, curConte xt.STATIC_DRAW); rectBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, rectBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, rectVerts, curContext.STA TIC_DRAW); rectNormBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, rectNormBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, rectNorms, curContext.STA TIC_DRAW); sphereBuffer = curContext.createBuffer(); lineBuffer = curContext.createBuffer(); fillBuffer = curContext.createBuffer(); fillColorBuffer = curContext.createBuffer(); strokeColorBuffer = curContext.createBuffer(); shapeTexVBO = curContext.createBuffer(); pointBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, pointBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 0 ]), curContext.STATIC_DRAW); textBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, textBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([1, 1, 0 , -1, 1, 0, -1, -1, 0, 1, -1, 0]), curContext.STATIC_DRAW); textureBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ARRAY_BUFFER, textureBuffer);

curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 1 , 0, 1, 1, 0, 1]), curContext.STATIC_DRAW); indexBuffer = curContext.createBuffer(); curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); curContext.bufferData(curContext.ELEMENT_ARRAY_BUFFER, new Uint16Array([ 0, 1, 2, 2, 3, 0]), curContext.STATIC_DRAW); cam = new PMatrix3D; cameraInv = new PMatrix3D; modelView = new PMatrix3D; modelViewInv = new PMatrix3D; projection = new PMatrix3D; p.camera(); p.perspective(); userMatrixStack = new PMatrixStack; userReverseMatrixStack = new PMatrixStack; curveBasisMatrix = new PMatrix3D; curveToBezierMatrix = new PMatrix3D; curveDrawMatrix = new PMatrix3D; bezierDrawMatrix = new PMatrix3D; bezierBasisInverse = new PMatrix3D; bezierBasisMatrix = new PMatrix3D; bezierBasisMatrix.set(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0 ); DrawingShared.prototype.size.apply(this, arguments) } }(); Drawing2D.prototype.ambientLight = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.ambientLight = function(r, g, b, x, y, z) { if (lightCount === 8) throw "can only create " + 8 + " lights"; var pos = new PVector(x, y, z); var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.mult(pos, pos); var col = color$4(r, g, b, 0); var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; curContext.useProgram(programObject3D); uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + li ghtCount + ".color", normalizedCol); uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lig htCount + ".type", 0); uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) }; Drawing2D.prototype.directionalLight = DrawingShared.prototype.a3DOnlyFuncti on; Drawing3D.prototype.directionalLight = function(r, g, b, nx, ny, nz) { if (lightCount === 8) throw "can only create " + 8 + " lights"; curContext.useProgram(programObject3D); var mvm = new PMatrix3D; mvm.scale(1, -1, 1); mvm.apply(modelView.array()); mvm = mvm.array(); var dir = [mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, mvm[1] * nx + mvm[5] * ny + mvm[9] * nz, mvm[2] * nx + mvm[6] * ny + mvm[10] * nz]; var col = color$4(r, g, b, 0); var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255];

uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + li ghtCount + ".color", normalizedCol); uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", dir); uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lig htCount + ".type", 1); uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) }; Drawing2D.prototype.lightFalloff = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.lightFalloff = function(constant, linear, quadratic) { curContext.useProgram(programObject3D); uniformf("uFalloff3d", programObject3D, "uFalloff", [constant, linear, qua dratic]) }; Drawing2D.prototype.lightSpecular = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.lightSpecular = function(r, g, b) { var col = color$4(r, g, b, 0); var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; curContext.useProgram(programObject3D); uniformf("uSpecular3d", programObject3D, "uSpecular", normalizedCol) }; p.lights = function() { p.ambientLight(128, 128, 128); p.directionalLight(128, 128, 128, 0, 0, -1); p.lightFalloff(1, 0, 0); p.lightSpecular(0, 0, 0) }; Drawing2D.prototype.pointLight = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.pointLight = function(r, g, b, x, y, z) { if (lightCount === 8) throw "can only create " + 8 + " lights"; var pos = new PVector(x, y, z); var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.mult(pos, pos); var col = color$4(r, g, b, 0); var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; curContext.useProgram(programObject3D); uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + li ghtCount + ".color", normalizedCol); uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lig htCount + ".type", 2); uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) }; Drawing2D.prototype.noLights = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.noLights = function() { lightCount = 0; curContext.useProgram(programObject3D); uniformi("uLightCount3d", programObject3D, "uLightCount", lightCount) }; Drawing2D.prototype.spotLight = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.spotLight = function(r, g, b, x, y, z, nx, ny, nz, angle , concentration) { if (lightCount === 8) throw "can only create " + 8 + " lights"; curContext.useProgram(programObject3D); var pos = new PVector(x, y, z);

var mvm = new PMatrix3D; mvm.scale(1, -1, 1); mvm.apply(modelView.array()); mvm.mult(pos, pos); mvm = mvm.array(); var dir = [mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, mvm[1] * nx + mvm[5] * ny + mvm[9] * nz, mvm[2] * nx + mvm[6] * ny + mvm[10] * nz ]; var col = color$4(r, g, b, 0); var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + li ghtCount + ".color", normalizedCol); uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); uniformf("uLights.direction.3d." + lightCount, programObject3D, "uLights" + lightCount + ".direction", dir); uniformf("uLights.concentration.3d." + lightCount, programObject3D, "uLigh ts" + lightCount + ".concentration", concentration); uniformf("uLights.angle.3d." + lightCount, programObject3D, "uLights" + li ghtCount + ".angle", angle); uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lig htCount + ".type", 3); uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) }; Drawing2D.prototype.beginCamera = function() { throw "beginCamera() is not available in 2D mode"; }; Drawing3D.prototype.beginCamera = function() { if (manipulatingCamera) throw "You cannot call beginCamera() again before calling endCamera()"; manipulatingCamera = true; modelView = cameraInv; modelViewInv = cam }; Drawing2D.prototype.endCamera = function() { throw "endCamera() is not available in 2D mode"; }; Drawing3D.prototype.endCamera = function() { if (!manipulatingCamera) throw "You cannot call endCamera() before calling beginCamera()"; modelView.set(cam); modelViewInv.set(cameraInv); manipulatingCamera = false }; p.camera = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, u pZ) { if (eyeX === undef) { cameraX = p.width / 2; cameraY = p.height / 2; cameraZ = cameraY / Math.tan(cameraFOV / 2); eyeX = cameraX; eyeY = cameraY; eyeZ = cameraZ; centerX = cameraX; centerY = cameraY; centerZ = 0; upX = 0; upY = 1; upZ = 0

} var z = new PVector(eyeX - centerX, eyeY - centerY, eyeZ - centerZ); var y = new PVector(upX, upY, upZ); z.normalize(); var x = PVector.cross(y, z); y = PVector.cross(z, x); x.normalize(); y.normalize(); var xX = x.x, xY = x.y, xZ = x.z; var yX = y.x, yY = y.y, yZ = y.z; var zX = z.x, zY = z.y, zZ = z.z; cam.set(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); cam.translate(-eyeX, -eyeY, -eyeZ); cameraInv.reset(); cameraInv.invApply(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1 ); cameraInv.translate(eyeX, eyeY, eyeZ); modelView.set(cam); modelViewInv.set(cameraInv) }; p.perspective = function(fov, aspect, near, far) { if (arguments.length === 0) { cameraY = curElement.height / 2; cameraZ = cameraY / Math.tan(cameraFOV / 2); cameraNear = cameraZ / 10; cameraFar = cameraZ * 10; cameraAspect = p.width / p.height; fov = cameraFOV; aspect = cameraAspect; near = cameraNear; far = cameraFar } var yMax, yMin, xMax, xMin; yMax = near * Math.tan(fov / 2); yMin = -yMax; xMax = yMax * aspect; xMin = yMin * aspect; p.frustum(xMin, xMax, yMin, yMax, near, far) }; Drawing2D.prototype.frustum = function() { throw "Processing.js: frustum() is not supported in 2D mode"; }; Drawing3D.prototype.frustum = function(left, right, bottom, top, near, far) { frustumMode = true; projection = new PMatrix3D; projection.set(2 * near / (right - left), 0, (right + left) / (right - lef t), 0, 0, 2 * near / (top - bottom), (top + bottom) / (top - bottom), 0, 0, 0, (far + near) / (far - near), -(2 * far * near) / (far - near), 0, 0, -1, 0); var proj = new PMatrix3D; proj.set(projection); proj.transpose(); curContext.useProgram(programObject2D); uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.

array()); curContext.useProgram(programObject3D); uniformMatrix("projection3d", programObject3D, "uProjection", false, proj. array()); curContext.useProgram(programObjectUnlitShape); uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", fal se, proj.array()) }; p.ortho = function(left, right, bottom, top, near, far) { if (arguments.length === 0) { left = 0; right = p.width; bottom = 0; top = p.height; near = -10; far = 10 } var x = 2 / (right - left); var y = 2 / (top - bottom); var z = -2 / (far - near); var tx = -(right + left) / (right - left); var ty = -(top + bottom) / (top - bottom); var tz = -(far + near) / (far - near); projection = new PMatrix3D; projection.set(x, 0, 0, tx, 0, y, 0, ty, 0, 0, z, tz, 0, 0, 0, 1); var proj = new PMatrix3D; proj.set(projection); proj.transpose(); curContext.useProgram(programObject2D); uniformMatrix("projection2d", programObject2D, "uProjection", false, proj. array()); curContext.useProgram(programObject3D); uniformMatrix("projection3d", programObject3D, "uProjection", false, proj. array()); curContext.useProgram(programObjectUnlitShape); uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", fal se, proj.array()); frustumMode = false }; p.printProjection = function() { projection.print() }; p.printCamera = function() { cam.print() }; Drawing2D.prototype.box = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.box = function(w, h, d) { if (!h || !d) h = d = w; var model = new PMatrix3D; model.scale(w, h, d); var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); if (doFill) { curContext.useProgram(programObject3D); uniformMatrix("model3d", programObject3D, "uModel", false, model.array() ); uniformMatrix("view3d", programObject3D, "uView", false, view.array()); curContext.enable(curContext.POLYGON_OFFSET_FILL);

curContext.polygonOffset(1, 1); uniformf("color3d", programObject3D, "uColor", fillStyle); if (lightCount > 0) { var v = new PMatrix3D; v.set(view); var m = new PMatrix3D; m.set(model); v.mult(m); var normalMatrix = new PMatrix3D; normalMatrix.set(v); normalMatrix.invert(); normalMatrix.transpose(); uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform ", false, normalMatrix.array()); vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, boxNor mBuffer) } else disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal "); vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, boxBuffe r); disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); curContext.drawArrays(curContext.TRIANGLES, 0, boxVerts.length / 3); curContext.disable(curContext.POLYGON_OFFSET_FILL) } if (lineWidth > 0 && doStroke) { curContext.useProgram(programObject2D); uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array( )); uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); uniformf("uColor2d", programObject2D, "uColor", strokeStyle); uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); vertexAttribPointer("vertex2d", programObject2D, "aVertex", 3, boxOutlin eBuffer); disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTexture Coord"); curContext.drawArrays(curContext.LINES, 0, boxOutlineVerts.length / 3) } }; var initSphere = function() { var i; sphereVerts = []; for (i = 0; i < sphereDetailU; i++) { sphereVerts.push(0); sphereVerts.push(-1); sphereVerts.push(0); sphereVerts.push(sphereX[i]); sphereVerts.push(sphereY[i]); sphereVerts.push(sphereZ[i]) } sphereVerts.push(0); sphereVerts.push(-1); sphereVerts.push(0); sphereVerts.push(sphereX[0]); sphereVerts.push(sphereY[0]); sphereVerts.push(sphereZ[0]); var v1, v11, v2; var voff = 0; for (i = 2; i < sphereDetailV; i++) { v1 = v11 = voff;

voff += sphereDetailU; v2 = voff; for (var j = 0; j < sphereDetailU; j++) { sphereVerts.push(sphereX[v1]); sphereVerts.push(sphereY[v1]); sphereVerts.push(sphereZ[v1++]); sphereVerts.push(sphereX[v2]); sphereVerts.push(sphereY[v2]); sphereVerts.push(sphereZ[v2++]) } v1 = v11; v2 = voff; sphereVerts.push(sphereX[v1]); sphereVerts.push(sphereY[v1]); sphereVerts.push(sphereZ[v1]); sphereVerts.push(sphereX[v2]); sphereVerts.push(sphereY[v2]); sphereVerts.push(sphereZ[v2]) } for (i = 0; i < sphereDetailU; i++) { v2 = voff + i; sphereVerts.push(sphereX[v2]); sphereVerts.push(sphereY[v2]); sphereVerts.push(sphereZ[v2]); sphereVerts.push(0); sphereVerts.push(1); sphereVerts.push(0) } sphereVerts.push(sphereX[voff]); sphereVerts.push(sphereY[voff]); sphereVerts.push(sphereZ[voff]); sphereVerts.push(0); sphereVerts.push(1); sphereVerts.push(0); curContext.bindBuffer(curContext.ARRAY_BUFFER, sphereBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(sphereVert s), curContext.STATIC_DRAW) }; p.sphereDetail = function(ures, vres) { var i; if (arguments.length === 1) ures = vres = arguments[0]; if (ures < 3) ures = 3; if (vres < 2) vres = 2; if (ures === sphereDetailU && vres === sphereDetailV) return; var delta = 720 / ures; var cx = new Float32Array(ures); var cz = new Float32Array(ures); for (i = 0; i < ures; i++) { cx[i] = cosLUT[i * delta % 720 | 0]; cz[i] = sinLUT[i * delta % 720 | 0] } var vertCount = ures * (vres - 1) + 2; var currVert = 0; sphereX = new Float32Array(vertCount); sphereY = new Float32Array(vertCount); sphereZ = new Float32Array(vertCount); var angle_step = 720 * 0.5 / vres; var angle = angle_step; for (i = 1; i < vres; i++) { var curradius = sinLUT[angle % 720 | 0];

var currY = -cosLUT[angle % 720 | 0]; for (var j = 0; j < ures; j++) { sphereX[currVert] = cx[j] * curradius; sphereY[currVert] = currY; sphereZ[currVert++] = cz[j] * curradius } angle += angle_step } sphereDetailU = ures; sphereDetailV = vres; initSphere() }; Drawing2D.prototype.sphere = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.sphere = function() { var sRad = arguments[0]; if (sphereDetailU < 3 || sphereDetailV < 2) p.sphereDetail(30); var model = new PMatrix3D; model.scale(sRad, sRad, sRad); var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); if (doFill) { if (lightCount > 0) { var v = new PMatrix3D; v.set(view); var m = new PMatrix3D; m.set(model); v.mult(m); var normalMatrix = new PMatrix3D; normalMatrix.set(v); normalMatrix.invert(); normalMatrix.transpose(); uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform ", false, normalMatrix.array()); vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, sphere Buffer) } else disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal "); curContext.useProgram(programObject3D); disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array( )); uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, sphereBu ffer); disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); curContext.enable(curContext.POLYGON_OFFSET_FILL); curContext.polygonOffset(1, 1); uniformf("uColor3d", programObject3D, "uColor", fillStyle); curContext.drawArrays(curContext.TRIANGLE_STRIP, 0, sphereVerts.length / 3); curContext.disable(curContext.POLYGON_OFFSET_FILL) } if (lineWidth > 0 && doStroke) { curContext.useProgram(programObject2D); uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array( )); uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, sphereBu

ffer); disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTexture Coord"); uniformf("uColor2d", programObject2D, "uColor", strokeStyle); uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); curContext.drawArrays(curContext.LINE_STRIP, 0, sphereVerts.length / 3) } }; p.modelX = function(x, y, z) { var mv = modelView.array(); var ci = cameraInv.array(); var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw; var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; return ow !== 0 ? ox / ow : ox }; p.modelY = function(x, y, z) { var mv = modelView.array(); var ci = cameraInv.array(); var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw; var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; return ow !== 0 ? oy / ow : oy }; p.modelZ = function(x, y, z) { var mv = modelView.array(); var ci = cameraInv.array(); var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; var oz = ci[8] * ax + ci[9] * ay + ci[10] * az + ci[11] * aw; var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; return ow !== 0 ? oz / ow : oz }; Drawing2D.prototype.ambient = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.ambient = function(v1, v2, v3) { curContext.useProgram(programObject3D); uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); var col = p.color(v1, v2, v3); uniformf("uMaterialAmbient3d", programObject3D, "uMaterialAmbient", p.colo r.toGLArray(col).slice(0, 3)) }; Drawing2D.prototype.emissive = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.emissive = function(v1, v2, v3) { curContext.useProgram(programObject3D); uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); var col = p.color(v1, v2, v3); uniformf("uMaterialEmissive3d", programObject3D, "uMaterialEmissive", p.co lor.toGLArray(col).slice(0, 3)) }; Drawing2D.prototype.shininess = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.shininess = function(shine) { curContext.useProgram(programObject3D);

uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); uniformf("uShininess3d", programObject3D, "uShininess", shine) }; Drawing2D.prototype.specular = DrawingShared.prototype.a3DOnlyFunction; Drawing3D.prototype.specular = function(v1, v2, v3) { curContext.useProgram(programObject3D); uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); var col = p.color(v1, v2, v3); uniformf("uMaterialSpecular3d", programObject3D, "uMaterialSpecular", p.co lor.toGLArray(col).slice(0, 3)) }; p.screenX = function(x, y, z) { var mv = modelView.array(); if (mv.length === 16) { var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; var pj = projection.array(); var ox = pj[0] * ax + pj[1] * ay + pj[2] * az + pj[3] * aw; var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; if (ow !== 0) ox /= ow; return p.width * (1 + ox) / 2 } return modelView.multX(x, y) }; p.screenY = function screenY(x, y, z) { var mv = modelView.array(); if (mv.length === 16) { var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; var pj = projection.array(); var oy = pj[4] * ax + pj[5] * ay + pj[6] * az + pj[7] * aw; var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; if (ow !== 0) oy /= ow; return p.height * (1 + oy) / 2 } return modelView.multY(x, y) }; p.screenZ = function screenZ(x, y, z) { var mv = modelView.array(); if (mv.length !== 16) return 0; var pj = projection.array(); var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; var oz = pj[8] * ax + pj[9] * ay + pj[10] * az + pj[11] * aw; var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; if (ow !== 0) oz /= ow; return (oz + 1) / 2 }; DrawingShared.prototype.fill = function() { var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3] ); if (color === currentFillColor && doFill) return; doFill = true; currentFillColor = color

}; Drawing2D.prototype.fill = function() { DrawingShared.prototype.fill.apply(this, arguments); isFillDirty = true }; Drawing3D.prototype.fill = function() { DrawingShared.prototype.fill.apply(this, arguments); fillStyle = p.color.toGLArray(currentFillColor) }; function executeContextFill() { if (doFill) { if (isFillDirty) { curContext.fillStyle = p.color.toString(currentFillColor); isFillDirty = false } curContext.fill() } } p.noFill = function() { doFill = false }; DrawingShared.prototype.stroke = function() { var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3] ); if (color === currentStrokeColor && doStroke) return; doStroke = true; currentStrokeColor = color }; Drawing2D.prototype.stroke = function() { DrawingShared.prototype.stroke.apply(this, arguments); isStrokeDirty = true }; Drawing3D.prototype.stroke = function() { DrawingShared.prototype.stroke.apply(this, arguments); strokeStyle = p.color.toGLArray(currentStrokeColor) }; function executeContextStroke() { if (doStroke) { if (isStrokeDirty) { curContext.strokeStyle = p.color.toString(currentStrokeColor); isStrokeDirty = false } curContext.stroke() } } p.noStroke = function() { doStroke = false }; DrawingShared.prototype.strokeWeight = function(w) { lineWidth = w }; Drawing2D.prototype.strokeWeight = function(w) { DrawingShared.prototype.strokeWeight.apply(this, arguments); curContext.lineWidth = w }; Drawing3D.prototype.strokeWeight = function(w) { DrawingShared.prototype.strokeWeight.apply(this, arguments); curContext.useProgram(programObject2D);

uniformf("pointSize2d", programObject2D, "uPointSize", w); curContext.useProgram(programObjectUnlitShape); uniformf("pointSizeUnlitShape", programObjectUnlitShape, "uPointSize", w); curContext.lineWidth(w) }; p.strokeCap = function(value) { drawing.$ensureContext().lineCap = value }; p.strokeJoin = function(value) { drawing.$ensureContext().lineJoin = value }; Drawing2D.prototype.smooth = function() { renderSmooth = true; var style = curElement.style; style.setProperty("image-rendering", "optimizeQuality", "important"); style.setProperty("-ms-interpolation-mode", "bicubic", "important"); if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) curContext.mozI mageSmoothingEnabled = true }; Drawing3D.prototype.smooth = function() { renderSmooth = true }; Drawing2D.prototype.noSmooth = function() { renderSmooth = false; var style = curElement.style; style.setProperty("image-rendering", "optimizeSpeed", "important"); style.setProperty("image-rendering", "-moz-crisp-edges", "important"); style.setProperty("image-rendering", "-webkit-optimize-contrast", "importa nt"); style.setProperty("image-rendering", "optimize-contrast", "important"); style.setProperty("-ms-interpolation-mode", "nearest-neighbor", "important "); if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) curContext.mozI mageSmoothingEnabled = false }; Drawing3D.prototype.noSmooth = function() { renderSmooth = false }; Drawing2D.prototype.point = function(x, y) { if (!doStroke) return; x = Math.round(x); y = Math.round(y); curContext.fillStyle = p.color.toString(currentStrokeColor); isFillDirty = true; if (lineWidth > 1) { curContext.beginPath(); curContext.arc(x, y, lineWidth / 2, 0, 6.283185307179586, false); curContext.fill() } else curContext.fillRect(x, y, 1, 1) }; Drawing3D.prototype.point = function(x, y, z) { var model = new PMatrix3D; model.translate(x, y, z || 0); model.transpose(); var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); curContext.useProgram(programObject2D); uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array())

; uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); if (lineWidth > 0 && doStroke) { uniformf("uColor2d", programObject2D, "uColor", strokeStyle); uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); uniformi("uSmooth2d", programObject2D, "uSmooth", renderSmooth); vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, pointBuf fer); disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTexture Coord"); curContext.drawArrays(curContext.POINTS, 0, 1) } }; p.beginShape = function(type) { curShape = type; curvePoints = []; vertArray = [] }; Drawing2D.prototype.vertex = function(x, y, moveTo) { var vert = []; if (firstVert) firstVert = false; vert["isVert"] = true; vert[0] = x; vert[1] = y; vert[2] = 0; vert[3] = 0; vert[4] = 0; vert[5] = currentFillColor; vert[6] = currentStrokeColor; vertArray.push(vert); if (moveTo) vertArray[vertArray.length - 1]["moveTo"] = moveTo }; Drawing3D.prototype.vertex = function(x, y, z, u, v) { var vert = []; if (firstVert) firstVert = false; vert["isVert"] = true; if (v === undef && usingTexture) { v = u; u = z; z = 0 } if (u !== undef && v !== undef) { if (curTextureMode === 2) { u /= curTexture.width; v /= curTexture.height } u = u > 1 ? 1 : u; u = u < 0 ? 0 : u; v = v > 1 ? 1 : v; v = v < 0 ? 0 : v } vert[0] = x; vert[1] = y; vert[2] = z || 0; vert[3] = u || 0; vert[4] = v || 0; vert[5] = fillStyle[0]; vert[6] = fillStyle[1]; vert[7] = fillStyle[2]; vert[8] = fillStyle[3];

vert[9] = strokeStyle[0]; vert[10] = strokeStyle[1]; vert[11] = strokeStyle[2]; vert[12] = strokeStyle[3]; vert[13] = normalX; vert[14] = normalY; vert[15] = normalZ; vertArray.push(vert) }; var point3D = function(vArray, cArray) { var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); curContext.useProgram(programObjectUnlitShape); uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.arr ay()); uniformi("uSmoothUS", programObjectUnlitShape, "uSmooth", renderSmooth); vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, po intBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), c urContext.STREAM_DRAW); vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, fill ColorBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), c urContext.STREAM_DRAW); curContext.drawArrays(curContext.POINTS, 0, vArray.length / 3) }; var line3D = function(vArray, mode, cArray) { var ctxMode; if (mode === "LINES") ctxMode = curContext.LINES; else if (mode === "LINE_LOOP") ctxMode = curContext.LINE_LOOP; else ctxMode = curContext.LINE_STRIP; var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); curContext.useProgram(programObjectUnlitShape); uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.arr ay()); vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, li neBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), c urContext.STREAM_DRAW); vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, stro keColorBuffer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), c urContext.STREAM_DRAW); curContext.drawArrays(ctxMode, 0, vArray.length / 3) }; var fill3D = function(vArray, mode, cArray, tArray) { var ctxMode; if (mode === "TRIANGLES") ctxMode = curContext.TRIANGLES; else if (mode === "TRIANGLE_FAN") ctxMode = curContext.TRIANGLE_FAN; else ctxMode = curContext.TRIANGLE_STRIP; var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); curContext.useProgram(programObject3D);

uniformMatrix("model3d", programObject3D, "uModel", false, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); uniformMatrix("view3d", programObject3D, "uView", false, view.array()); curContext.enable(curContext.POLYGON_OFFSET_FILL); curContext.polygonOffset(1, 1); uniformf("color3d", programObject3D, "uColor", [-1, 0, 0, 0]); vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, fillBuffer) ; curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), c urContext.STREAM_DRAW); if (usingTexture && curTint !== null) curTint3d(cArray); vertexAttribPointer("aColor3d", programObject3D, "aColor", 4, fillColorBuf fer); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), c urContext.STREAM_DRAW); disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); if (usingTexture) { uniformi("uUsingTexture3d", programObject3D, "uUsingTexture", usingTextu re); vertexAttribPointer("aTexture3d", programObject3D, "aTexture", 2, shapeT exVBO); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(tArray), curContext.STREAM_DRAW) } curContext.drawArrays(ctxMode, 0, vArray.length / 3); curContext.disable(curContext.POLYGON_OFFSET_FILL) }; function fillStrokeClose() { executeContextFill(); executeContextStroke(); curContext.closePath() } Drawing2D.prototype.endShape = function(mode) { if (vertArray.length === 0) return; var closeShape = mode === 2; if (closeShape) vertArray.push(vertArray[0]); var lineVertArray = []; var fillVertArray = []; var colorVertArray = []; var strokeVertArray = []; var texVertArray = []; var cachedVertArray; firstVert = true; var i, j, k; var vertArrayLength = vertArray.length; for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) fillVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i];

texVertArray.push(cachedVertArray[3]); texVertArray.push(cachedVertArray[4]) } if (isCurve && (curShape === 20 || curShape === undef)) { if (vertArrayLength > 3) { var b = [], s = 1 - curTightness; curContext.beginPath(); curContext.moveTo(vertArray[1][0], vertArray[1][1]); for (i = 1; i + 2 < vertArrayLength; i++) { cachedVertArray = vertArray[i]; b[0] = [cachedVertArray[0], cachedVertArray[1]]; b[1] = [cachedVertArray[0] + (s * vertArray[i + 1][0] - s * vertArra y[i - 1][0]) / 6, cachedVertArray[1] + (s * vertArray[i + 1][1] - s * vertArray[ i - 1][1]) / 6]; b[2] = [vertArray[i + 1][0] + (s * vertArray[i][0] - s * vertArray[i + 2][0]) / 6, vertArray[i + 1][1] + (s * vertArray[i][1] - s * vertArray[i + 2] [1]) / 6]; b[3] = [vertArray[i + 1][0], vertArray[i + 1][1]]; curContext.bezierCurveTo(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0] , b[3][1]) } fillStrokeClose() } } else if (isBezier && (curShape === 20 || curShape === undef)) { curContext.beginPath(); for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; if (vertArray[i]["isVert"]) if (vertArray[i]["moveTo"]) curContext.mov eTo(cachedVertArray[0], cachedVertArray[1]); else curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); else curContext.bezierCurveTo(vertArray[i][0], vertArray[i][1], vertAr ray[i][2], vertArray[i][3], vertArray[i][4], vertArray[i][5]) } fillStrokeClose() } else if (curShape === 2) for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; if (doStroke) p.stroke(cachedVertArray[6]); p.point(cachedVertArray[0], cachedVertArray[1]) } else if (curShape === 4) for (i = 0; i + 1 < vertArrayLength; i += 2) { cachedVertArray = vertArray[i]; if (doStroke) p.stroke(vertArray[i + 1][6]); p.line(cachedVertArray[0], cachedVertArray[1], vertArray[i + 1][0], vert Array[i + 1][1]) } else if (curShape === 9) for (i = 0; i + 2 < vertArrayLength; i += 3) { cachedVertArray = vertArray[i]; curContext.beginPath(); curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]); curContext.lineTo(vertArray[i + 2][0], vertArray[i + 2][1]); curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); if (doFill) { p.fill(vertArray[i + 2][5]); executeContextFill() } if (doStroke) { p.stroke(vertArray[i + 2][6]); executeContextStroke() } curContext.closePath()

} else if (curShape === 10) for (i = 0; i + 1 < vertArrayLength; i++) { cachedVertArray = vertArray[i]; curContext.beginPath(); curContext.moveTo(vertArray[i + 1][0], vertArray[i + 1][1]); curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); if (doStroke) p.stroke(vertArray[i + 1][6]); if (doFill) p.fill(vertArray[i + 1][5]); if (i + 2 < vertArrayLength) { curContext.lineTo(vertArray[i + 2][0], vertArray[i + 2][1]); if (doStroke) p.stroke(vertArray[i + 2][6]); if (doFill) p.fill(vertArray[i + 2][5]) } fillStrokeClose() } else if (curShape === 11) { if (vertArrayLength > 2) { curContext.beginPath(); curContext.moveTo(vertArray[0][0], vertArray[0][1]); curContext.lineTo(vertArray[1][0], vertArray[1][1]); curContext.lineTo(vertArray[2][0], vertArray[2][1]); if (doFill) { p.fill(vertArray[2][5]); executeContextFill() } if (doStroke) { p.stroke(vertArray[2][6]); executeContextStroke() } curContext.closePath(); for (i = 3; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; curContext.beginPath(); curContext.moveTo(vertArray[0][0], vertArray[0][1]); curContext.lineTo(vertArray[i - 1][0], vertArray[i - 1][1]); curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); if (doFill) { p.fill(cachedVertArray[5]); executeContextFill() } if (doStroke) { p.stroke(cachedVertArray[6]); executeContextStroke() } curContext.closePath() } } } else if (curShape === 16) for (i = 0; i + 3 < vertArrayLength; i += 4) { cachedVertArray = vertArray[i]; curContext.beginPath(); curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); for (j = 1; j < 4; j++) curContext.lineTo(vertArray[i + j][0], vertArray [i + j][1]); curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); if (doFill) { p.fill(vertArray[i + 3][5]); executeContextFill() } if (doStroke) { p.stroke(vertArray[i + 3][6]); executeContextStroke() }

curContext.closePath() } else if (curShape === 17) { if (vertArrayLength > 3) for (i = 0; i + 1 < vertArrayLength; i += 2) { cachedVertArray = vertArray[i]; curContext.beginPath(); if (i + 3 < vertArrayLength) { curContext.moveTo(vertArray[i + 2][0], vertArray[i + 2][1]); curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]); curContext.lineTo(vertArray[i + 3][0], vertArray[i + 3][1]); if (doFill) p.fill(vertArray[i + 3][5]); if (doStroke) p.stroke(vertArray[i + 3][6]) } else { curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]) } fillStrokeClose() } } else { curContext.beginPath(); curContext.moveTo(vertArray[0][0], vertArray[0][1]); for (i = 1; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; if (cachedVertArray["isVert"]) if (cachedVertArray["moveTo"]) curConte xt.moveTo(cachedVertArray[0], cachedVertArray[1]); else curContext.lineTo(cachedVertArray[0], cachedVertArray[1]) } fillStrokeClose() } isCurve = false; isBezier = false; curveVertArray = []; curveVertCount = 0; if (closeShape) vertArray.pop() }; Drawing3D.prototype.endShape = function(mode) { if (vertArray.length === 0) return; var closeShape = mode === 2; var lineVertArray = []; var fillVertArray = []; var colorVertArray = []; var strokeVertArray = []; var texVertArray = []; var cachedVertArray; firstVert = true; var i, j, k; var vertArrayLength = vertArray.length; for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) fillVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) {

cachedVertArray = vertArray[i]; texVertArray.push(cachedVertArray[3]); texVertArray.push(cachedVertArray[4]) } if (closeShape) { fillVertArray.push(vertArray[0][0]); fillVertArray.push(vertArray[0][1]); fillVertArray.push(vertArray[0][2]); for (i = 5; i < 9; i++) colorVertArray.push(vertArray[0][i]); for (i = 9; i < 13; i++) strokeVertArray.push(vertArray[0][i]); texVertArray.push(vertArray[0][3]); texVertArray.push(vertArray[0][4]) } if (isCurve && (curShape === 20 || curShape === undef)) { lineVertArray = fillVertArray; if (doStroke) line3D(lineVertArray, null, strokeVertArray); if (doFill) fill3D(fillVertArray, null, colorVertArray) } else if (isBezier && (curShape === 20 || curShape === undef)) { lineVertArray = fillVertArray; lineVertArray.splice(lineVertArray.length - 3); strokeVertArray.splice(strokeVertArray.length - 4); if (doStroke) line3D(lineVertArray, null, strokeVertArray); if (doFill) fill3D(fillVertArray, "TRIANGLES", colorVertArray) } else { if (curShape === 2) { for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) } point3D(lineVertArray, strokeVertArray) } else if (curShape === 4) { for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) } for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) } line3D(lineVertArray, "LINES", strokeVertArray) } else if (curShape === 9) { if (vertArrayLength > 2) for (i = 0; i + 2 < vertArrayLength; i += 3) { fillVertArray = []; texVertArray = []; lineVertArray = []; colorVertArray = []; strokeVertArray = []; for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { lineVertArray.push(vertArray[i + j][k]); fillVertArray.push(vertArray[i + j][k]) } for (j = 0; j < 3; j++) for (k = 3; k < 5; k++) texVertArray.push(ve rtArray[i + j][k]); for (j = 0; j < 3; j++) for (k = 5; k < 9; k++) { colorVertArray.push(vertArray[i + j][k]); strokeVertArray.push(vertArray[i + j][k + 4]) } if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLES", color

VertArray, texVertArray) } } else if (curShape === 10) { if (vertArrayLength > 2) for (i = 0; i + 2 < vertArrayLength; i++) { lineVertArray = []; fillVertArray = []; strokeVertArray = []; colorVertArray = []; texVertArray = []; for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { lineVertArray.push(vertArray[i + j][k]); fillVertArray.push(vertArray[i + j][k]) } for (j = 0; j < 3; j++) for (k = 3; k < 5; k++) texVertArray.push(ve rtArray[i + j][k]); for (j = 0; j < 3; j++) for (k = 5; k < 9; k++) { strokeVertArray.push(vertArray[i + j][k + 4]); colorVertArray.push(vertArray[i + j][k]) } if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray); if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray) } } else if (curShape === 11) { if (vertArrayLength > 2) { for (i = 0; i < 3; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) } for (i = 0; i < 3; i++) { cachedVertArray = vertArray[i]; for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) } if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); for (i = 2; i + 1 < vertArrayLength; i++) { lineVertArray = []; strokeVertArray = []; lineVertArray.push(vertArray[0][0]); lineVertArray.push(vertArray[0][1]); lineVertArray.push(vertArray[0][2]); strokeVertArray.push(vertArray[0][9]); strokeVertArray.push(vertArray[0][10]); strokeVertArray.push(vertArray[0][11]); strokeVertArray.push(vertArray[0][12]); for (j = 0; j < 2; j++) for (k = 0; k < 3; k++) lineVertArray.push (vertArray[i + j][k]); for (j = 0; j < 2; j++) for (k = 9; k < 13; k++) strokeVertArray.p ush(vertArray[i + j][k]); if (doStroke) line3D(lineVertArray, "LINE_STRIP", strokeVertArray) } if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_FAN", co lorVertArray, texVertArray) } } else if (curShape === 16) for (i = 0; i + 3 < vertArrayLength; i += 4) { lineVertArray = []; for (j = 0; j < 4; j++) { cachedVertArray = vertArray[i + j]; for (k = 0; k < 3; k++) lineVertArray.push(cachedVertArray[k]) }

if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); if (doFill) { fillVertArray = []; colorVertArray = []; texVertArray = []; for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i][j]); for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i][j]); for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 1][j]); for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 1][j]); for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 3][j]); for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 3][j]); for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 2][j]); for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 2][j]); if (usingTexture) { texVertArray.push(vertArray[i + 0][3]); texVertArray.push(vertArray[i + 0][4]); texVertArray.push(vertArray[i + 1][3]); texVertArray.push(vertArray[i + 1][4]); texVertArray.push(vertArray[i + 3][3]); texVertArray.push(vertArray[i + 3][4]); texVertArray.push(vertArray[i + 2][3]); texVertArray.push(vertArray[i + 2][4]) } fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray ) } } else if (curShape === 17) { var tempArray = []; if (vertArrayLength > 3) { for (i = 0; i < 2; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) } for (i = 0; i < 2; i++) { cachedVertArray = vertArray[i]; for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) } line3D(lineVertArray, "LINE_STRIP", strokeVertArray); if (vertArrayLength > 4 && vertArrayLength % 2 > 0) { tempArray = fillVertArray.splice(fillVertArray.length - 3); vertArray.pop() } for (i = 0; i + 3 < vertArrayLength; i += 2) { lineVertArray = []; strokeVertArray = []; for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 1][j]); for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 3][j]); for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 2][j]); for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 0][j]); for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 1][j]) ; for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 3][j]) ; for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 2][j]) ; for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 0][j]) ; if (doStroke) line3D(lineVertArray, "LINE_STRIP", strokeVertArray) } if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_LIST", c

olorVertArray, texVertArray) } } else if (vertArrayLength === 1) { for (j = 0; j < 3; j++) lineVertArray.push(vertArray[0][j]); for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[0][j]); point3D(lineVertArray, strokeVertArray) } else { for (i = 0; i < vertArrayLength; i++) { cachedVertArray = vertArray[i]; for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]); for (j = 5; j < 9; j++) strokeVertArray.push(cachedVertArray[j]) } if (doStroke && closeShape) line3D(lineVertArray, "LINE_LOOP", strokeV ertArray); else if (doStroke && !closeShape) line3D(lineVertArray, "LINE_STRIP", strokeVertArray); if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_FAN", colo rVertArray, texVertArray) } usingTexture = false; curContext.useProgram(programObject3D); uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTextur e) } isCurve = false; isBezier = false; curveVertArray = []; curveVertCount = 0 }; var splineForward = function(segments, matrix) { var f = 1 / segments; var ff = f * f; var fff = ff * f; matrix.set(0, 0, 0, 1, fff, ff, f, 0, 6 * fff, 2 * ff, 0, 0, 6 * fff, 0, 0 , 0) }; var curveInit = function() { if (!curveDrawMatrix) { curveBasisMatrix = new PMatrix3D; curveDrawMatrix = new PMatrix3D; curveInited = true } var s = curTightness; curveBasisMatrix.set((s - 1) / 2, (s + 3) / 2, (-3 - s) / 2, (1 - s) / 2, 1 - s, (-5 - s) / 2, s + 2, (s - 1) / 2, (s - 1) / 2, 0, (1 - s) / 2, 0, 0, 1, 0 , 0); splineForward(curveDet, curveDrawMatrix); if (!bezierBasisInverse) curveToBezierMatrix = new PMatrix3D; curveToBezierMatrix.set(curveBasisMatrix); curveToBezierMatrix.preApply(bezierBasisInverse); curveDrawMatrix.apply(curveBasisMatrix) }; Drawing2D.prototype.bezierVertex = function() { isBezier = true; var vert = []; if (firstVert) throw "vertex() must be used at least once before calling b ezierVertex()"; for (var i = 0; i < arguments.length; i++) vert[i] = arguments[i]; vertArray.push(vert); vertArray[vertArray.length - 1]["isVert"] = false

}; Drawing3D.prototype.bezierVertex = function() { isBezier = true; var vert = []; if (firstVert) throw "vertex() must be used at least once before calling b ezierVertex()"; if (arguments.length === 9) { if (bezierDrawMatrix === undef) bezierDrawMatrix = new PMatrix3D; var lastPoint = vertArray.length - 1; splineForward(bezDetail, bezierDrawMatrix); bezierDrawMatrix.apply(bezierBasisMatrix); var draw = bezierDrawMatrix.array(); var x1 = vertArray[lastPoint][0], y1 = vertArray[lastPoint][1], z1 = vertArray[lastPoint][2]; var xplot1 = draw[4] * x1 + draw[5] * arguments[0] + draw[6] * arguments [3] + draw[7] * arguments[6]; var xplot2 = draw[8] * x1 + draw[9] * arguments[0] + draw[10] * argument s[3] + draw[11] * arguments[6]; var xplot3 = draw[12] * x1 + draw[13] * arguments[0] + draw[14] * argume nts[3] + draw[15] * arguments[6]; var yplot1 = draw[4] * y1 + draw[5] * arguments[1] + draw[6] * arguments [4] + draw[7] * arguments[7]; var yplot2 = draw[8] * y1 + draw[9] * arguments[1] + draw[10] * argument s[4] + draw[11] * arguments[7]; var yplot3 = draw[12] * y1 + draw[13] * arguments[1] + draw[14] * argume nts[4] + draw[15] * arguments[7]; var zplot1 = draw[4] * z1 + draw[5] * arguments[2] + draw[6] * arguments [5] + draw[7] * arguments[8]; var zplot2 = draw[8] * z1 + draw[9] * arguments[2] + draw[10] * argument s[5] + draw[11] * arguments[8]; var zplot3 = draw[12] * z1 + draw[13] * arguments[2] + draw[14] * argume nts[5] + draw[15] * arguments[8]; for (var j = 0; j < bezDetail; j++) { x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; p.vertex(x1, y1, z1) } p.vertex(arguments[6], arguments[7], arguments[8]) } }; p.texture = function(pimage) { var curContext = drawing.$ensureContext(); if (pimage.__texture) curContext.bindTexture(curContext.TEXTURE_2D, pimage .__texture); else if (pimage.localName === "canvas") { curContext.bindTexture(curContext.TEXTURE_2D, canTex); curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curCont ext.RGBA, curContext.UNSIGNED_BYTE, pimage); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_F ILTER, curContext.LINEAR); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_F ILTER, curContext.LINEAR);

curContext.generateMipmap(curContext.TEXTURE_2D); curTexture.width = pimage.width; curTexture.height = pimage.height } else { var texture = curContext.createTexture(), cvs = document.createElement("canvas"), cvsTextureCtx = cvs.getContext("2d"), pot; if (pimage.width & pimage.width - 1 === 0) cvs.width = pimage.width; else { pot = 1; while (pot < pimage.width) pot *= 2; cvs.width = pot } if (pimage.height & pimage.height - 1 === 0) cvs.height = pimage.height; else { pot = 1; while (pot < pimage.height) pot *= 2; cvs.height = pot } cvsTextureCtx.drawImage(pimage.sourceImg, 0, 0, pimage.width, pimage.hei ght, 0, 0, cvs.width, cvs.height); curContext.bindTexture(curContext.TEXTURE_2D, texture); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_F ILTER, curContext.LINEAR_MIPMAP_LINEAR); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_F ILTER, curContext.LINEAR); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_ T, curContext.CLAMP_TO_EDGE); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_ S, curContext.CLAMP_TO_EDGE); curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curCont ext.RGBA, curContext.UNSIGNED_BYTE, cvs); curContext.generateMipmap(curContext.TEXTURE_2D); pimage.__texture = texture; curTexture.width = pimage.width; curTexture.height = pimage.height } usingTexture = true; curContext.useProgram(programObject3D); uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture) }; p.textureMode = function(mode) { curTextureMode = mode }; var curveVertexSegment = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4 , z4) { var x0 = x2; var y0 = y2; var z0 = z2; var draw = curveDrawMatrix.array(); var xplot1 = draw[4] * x1 + draw[5] * x2 + draw[6] * x3 + draw[7] * x4; var xplot2 = draw[8] * x1 + draw[9] * x2 + draw[10] * x3 + draw[11] * x4; var xplot3 = draw[12] * x1 + draw[13] * x2 + draw[14] * x3 + draw[15] * x4 ; var yplot1 = draw[4] * y1 + draw[5] * y2 + draw[6] * y3 + draw[7] * y4; var yplot2 = draw[8] * y1 + draw[9] * y2 + draw[10] * y3 + draw[11] * y4; var yplot3 = draw[12] * y1 + draw[13] * y2 + draw[14] * y3 + draw[15] * y4 ; var zplot1 = draw[4] * z1 + draw[5] * z2 + draw[6] * z3 + draw[7] * z4;

var zplot2 = draw[8] * z1 + draw[9] * z2 + draw[10] * z3 + draw[11] * z4; var zplot3 = draw[12] * z1 + draw[13] * z2 + draw[14] * z3 + draw[15] * z4 ; p.vertex(x0, y0, z0); for (var j = 0; j < curveDet; j++) { x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3; y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3; z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3; p.vertex(x0, y0, z0) } }; Drawing2D.prototype.curveVertex = function(x, y) { isCurve = true; p.vertex(x, y) }; Drawing3D.prototype.curveVertex = function(x, y, z) { isCurve = true; if (!curveInited) curveInit(); var vert = []; vert[0] = x; vert[1] = y; vert[2] = z; curveVertArray.push(vert); curveVertCount++; if (curveVertCount > 3) curveVertexSegment(curveVertArray[curveVertCount 4][0], curveVertArray[curveVertCount - 4][1], curveVertArray[curveVertCount - 4 ][2], curveVertArray[curveVertCount - 3][0], curveVertArray[curveVertCount - 3][ 1], curveVertArray[curveVertCount - 3][2], curveVertArray[curveVertCount - 2][0] , curveVertArray[curveVertCount - 2][1], curveVertArray[curveVertCount - 2][2], curveVertArray[curveVertCount - 1][0], curveVertArray[curveVertCount - 1][1], cu rveVertArray[curveVertCount - 1][2]) }; Drawing2D.prototype.curve = function(x1, y1, x2, y2, x3, y3, x4, y4) { p.beginShape(); p.curveVertex(x1, y1); p.curveVertex(x2, y2); p.curveVertex(x3, y3); p.curveVertex(x4, y4); p.endShape() }; Drawing3D.prototype.curve = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { if (z4 !== undef) { p.beginShape(); p.curveVertex(x1, y1, z1); p.curveVertex(x2, y2, z2); p.curveVertex(x3, y3, z3); p.curveVertex(x4, y4, z4); p.endShape(); return } p.beginShape(); p.curveVertex(x1, y1); p.curveVertex(z1, x2);

p.curveVertex(y2, z2); p.curveVertex(x3, y3); p.endShape() }; p.curveTightness = function(tightness) { curTightness = tightness }; p.curveDetail = function(detail) { curveDet = detail; curveInit() }; p.rectMode = function(aRectMode) { curRectMode = aRectMode }; p.imageMode = function(mode) { switch (mode) { case 0: imageModeConvert = imageModeCorner; break; case 1: imageModeConvert = imageModeCorners; break; case 3: imageModeConvert = imageModeCenter; break; default: throw "Invalid imageMode"; } }; p.ellipseMode = function(aEllipseMode) { curEllipseMode = aEllipseMode }; p.arc = function(x, y, width, height, start, stop) { if (width <= 0 || stop < start) return; if (curEllipseMode === 1) { width = width - x; height = height - y } else if (curEllipseMode === 2) { x = x - width; y = y - height; width = width * 2; height = height * 2 } else if (curEllipseMode === 3) { x = x - width / 2; y = y - height / 2 } while (start < 0) { start += 6.283185307179586; stop += 6.283185307179586 } if (stop - start > 6.283185307179586) { start = 0; stop = 6.283185307179586 } var hr = width / 2, vr = height / 2, centerX = x + hr, centerY = y + vr, startLUT = 0 | 0.5 + start * p.RAD_TO_DEG * 2, stopLUT = 0 | 0.5 + stop * p.RAD_TO_DEG * 2,

i, j; if (doFill) { var savedStroke = doStroke; doStroke = false; p.beginShape(); p.vertex(centerX, centerY); for (i = startLUT; i <= stopLUT; j = i % 720; p.vertex(centerX + cosLUT[j] * } p.endShape(2); doStroke = savedStroke } if (doStroke) { var savedFill = doFill; doFill = false; p.beginShape(); for (i = startLUT; i <= stopLUT; j = i % 720; p.vertex(centerX + cosLUT[j] * } p.endShape(); doFill = savedFill }

i++) { hr, centerY + sinLUT[j] * vr)

i++) { hr, centerY + sinLUT[j] * vr)

}; Drawing2D.prototype.line = function(x1, y1, x2, y2) { if (!doStroke) return; x1 = Math.round(x1); x2 = Math.round(x2); y1 = Math.round(y1); y2 = Math.round(y2); if (x1 === x2 && y1 === y2) { p.point(x1, y1); return } var swap = undef, lineCap = undef, drawCrisp = true, currentModelView = modelView.array(), identityMatrix = [1, 0, 0, 0, 1, 0]; for (var i = 0; i < 6 && drawCrisp; i++) drawCrisp = currentModelView[i] = == identityMatrix[i]; if (drawCrisp) { if (x1 === x2) { if (y1 > y2) { swap = y1; y1 = y2; y2 = swap } y2++; if (lineWidth % 2 === 1) curContext.translate(0.5, 0) } else if (y1 === y2) { if (x1 > x2) { swap = x1; x1 = x2; x2 = swap } x2++; if (lineWidth % 2 === 1) curContext.translate(0, 0.5) }

if (lineWidth === 1) { lineCap = curContext.lineCap; curContext.lineCap = "butt" } } curContext.beginPath(); curContext.moveTo(x1 || 0, y1 || 0); curContext.lineTo(x2 || 0, y2 || 0); executeContextStroke(); if (drawCrisp) { if (x1 === x2 && lineWidth % 2 === 1) curContext.translate(-0.5, 0); else if (y1 === y2 && lineWidth % 2 === 1) curContext.translate(0, -0.5) ; if (lineWidth === 1) curContext.lineCap = lineCap } }; Drawing3D.prototype.line = function(x1, y1, z1, x2, y2, z2) { if (y2 === undef || z2 === undef) { z2 = 0; y2 = x2; x2 = z1; z1 = 0 } if (x1 === x2 && y1 === y2 && z1 === z2) { p.point(x1, y1, z1); return } var lineVerts = [x1, y1, z1, x2, y2, z2]; var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); if (lineWidth > 0 && doStroke) { curContext.useProgram(programObject2D); uniformMatrix("uModel2d", programObject2D, "uModel", false, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); uniformf("uColor2d", programObject2D, "uColor", strokeStyle); uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, lineBuff er); disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTexture Coord"); curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(lineVert s), curContext.STREAM_DRAW); curContext.drawArrays(curContext.LINES, 0, 2) } }; Drawing2D.prototype.bezier = function() { if (arguments.length !== 8) throw "You must use 8 parameters for bezier() in 2D mode"; p.beginShape(); p.vertex(arguments[0], arguments[1]); p.bezierVertex(arguments[2], arguments[3], arguments[4], arguments[5], arg uments[6], arguments[7]); p.endShape() }; Drawing3D.prototype.bezier = function() { if (arguments.length !== 12) throw "You must use 12 parameters for bezier( ) in 3D mode";

p.beginShape(); p.vertex(arguments[0], arguments[1], arguments[2]); p.bezierVertex(arguments[3], arguments[4], arguments[5], arguments[6], arg uments[7], arguments[8], arguments[9], arguments[10], arguments[11]); p.endShape() }; p.bezierDetail = function(detail) { bezDetail = detail }; p.bezierPoint = function(a, b, c, d, t) { return (1 - t) * (1 - t) * (1 - t) * a + 3 * (1 - t) * (1 - t) * t * b + 3 * (1 - t) * t * t * c + t * t * t * d }; p.bezierTangent = function(a, b, c, d, t) { return 3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b) }; p.curvePoint = function(a, b, c, d, t) { return 0.5 * (2 * b + (-a + c) * t + (2 * a - 5 * b + 4 * c - d) * t * t + (-a + 3 * b - 3 * c + d) * t * t * t) }; p.curveTangent = function(a, b, c, d, t) { return 0.5 * (-a + c + 2 * (2 * a - 5 * b + 4 * c - d) * t + 3 * (-a + 3 * b - 3 * c + d) * t * t) }; p.triangle = function(x1, y1, x2, y2, x3, y3) { p.beginShape(9); p.vertex(x1, y1, 0); p.vertex(x2, y2, 0); p.vertex(x3, y3, 0); p.endShape() }; p.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { p.beginShape(16); p.vertex(x1, y1, 0); p.vertex(x2, y2, 0); p.vertex(x3, y3, 0); p.vertex(x4, y4, 0); p.endShape() }; var roundedRect$2d = function(x, y, width, height, tl, tr, br, bl) { if (bl === undef) { tr = tl; br = tl; bl = tl } var halfWidth = width / 2, halfHeight = height / 2; if (tl > halfWidth || tl > halfHeight) tl = Math.min(halfWidth, halfHeight ); if (tr > halfWidth || tr > halfHeight) tr = Math.min(halfWidth, halfHeight ); if (br > halfWidth || br > halfHeight) br = Math.min(halfWidth, halfHeight ); if (bl > halfWidth || bl > halfHeight) bl = Math.min(halfWidth, halfHeight ); if (!doFill || doStroke) curContext.translate(0.5, 0.5); curContext.beginPath(); curContext.moveTo(x + tl, y); curContext.lineTo(x + width - tr, y);

curContext.quadraticCurveTo(x + width, y, x + width, y + tr); curContext.lineTo(x + width, y + height - br); curContext.quadraticCurveTo(x + width, y + height, x + width - br, y + hei ght); curContext.lineTo(x + bl, y + height); curContext.quadraticCurveTo(x, y + height, x, y + height - bl); curContext.lineTo(x, y + tl); curContext.quadraticCurveTo(x, y, x + tl, y); if (!doFill || doStroke) curContext.translate(-0.5, -0.5); executeContextFill(); executeContextStroke() }; Drawing2D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { if (!width && !height) return; if (curRectMode === 1) { width -= x; height -= y } else if (curRectMode === 2) { width *= 2; height *= 2; x -= width / 2; y -= height / 2 } else if (curRectMode === 3) { x -= width / 2; y -= height / 2 } x = Math.round(x); y = Math.round(y); width = Math.round(width); height = Math.round(height); if (tl !== undef) { roundedRect$2d(x, y, width, height, tl, tr, br, bl); return } if (doStroke && lineWidth % 2 === 1) curContext.translate(0.5, 0.5); curContext.beginPath(); curContext.rect(x, y, width, height); executeContextFill(); executeContextStroke(); if (doStroke && lineWidth % 2 === 1) curContext.translate(-0.5, -0.5) }; Drawing3D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { if (tl !== undef) throw "rect() with rounded corners is not supported in 3 D mode"; if (curRectMode === 1) { width -= x; height -= y } else if (curRectMode === 2) { width *= 2; height *= 2; x -= width / 2; y -= height / 2 } else if (curRectMode === 3) { x -= width / 2; y -= height / 2 } var model = new PMatrix3D; model.translate(x, y, 0); model.scale(width, height, 1); model.transpose();

var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); if (lineWidth > 0 && doStroke) { curContext.useProgram(programObject2D); uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array( )); uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); uniformf("uColor2d", programObject2D, "uColor", strokeStyle); uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, rectBuff er); disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTexture Coord"); curContext.drawArrays(curContext.LINE_LOOP, 0, rectVerts.length / 3) } if (doFill) { curContext.useProgram(programObject3D); uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array( )); uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); curContext.enable(curContext.POLYGON_OFFSET_FILL); curContext.polygonOffset(1, 1); uniformf("color3d", programObject3D, "uColor", fillStyle); if (lightCount > 0) { var v = new PMatrix3D; v.set(view); var m = new PMatrix3D; m.set(model); v.mult(m); var normalMatrix = new PMatrix3D; normalMatrix.set(v); normalMatrix.invert(); normalMatrix.transpose(); uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform ", false, normalMatrix.array()); vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, rectNo rmBuffer) } else disableVertexAttribPointer("normal3d", programObject3D, "aNormal" ); vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, rectBuffe r); curContext.drawArrays(curContext.TRIANGLE_FAN, 0, rectVerts.length / 3); curContext.disable(curContext.POLYGON_OFFSET_FILL) } }; Drawing2D.prototype.ellipse = function(x, y, width, height) { x = x || 0; y = y || 0; if (width <= 0 && height <= 0) return; if (curEllipseMode === 2) { width *= 2; height *= 2 } else if (curEllipseMode === 1) { width = width - x; height = height - y; x += width / 2; y += height / 2 } else if (curEllipseMode === 0) {

x += width / 2; y += height / 2 } if (width === height) { curContext.beginPath(); curContext.arc(x, y, width / 2, 0, executeContextFill(); executeContextStroke() } else { var w = width / 2, h = height / 2, C = 0.5522847498307933, c_x = C * w, c_y = C * h; p.beginShape(); p.vertex(x + w, y); p.bezierVertex(x + w, y - c_y, x + p.bezierVertex(x - c_x, y - h, x p.bezierVertex(x - w, y + c_y, x p.bezierVertex(x + c_x, y + h, x + p.endShape() }

6.283185307179586, false);

c_x, w, y c_x, w, y

y y +

- h, c_y, + h, c_y,

x, y x - w, x, y + x + w,

h); y); h); y);

}; Drawing3D.prototype.ellipse = function(x, y, x = x || 0; y = y || 0; if (width <= 0 && height <= 0) return; if (curEllipseMode === 2) { width *= 2; height *= 2 } else if (curEllipseMode === 1) { width = width - x; height = height - y; x += width / 2; y += height / 2 } else if (curEllipseMode === 0) { x += width / 2; y += height / 2 } var w = width / 2, h = height / 2, C = 0.5522847498307933, c_x = C * w, c_y = C * h; p.beginShape(); p.vertex(x + w, y); p.bezierVertex(x + w, y - c_y, 0, x + c_x, p.bezierVertex(x - c_x, y - h, 0, x - w, y p.bezierVertex(x - w, y + c_y, 0, x - c_x, p.bezierVertex(x + c_x, y + h, 0, x + w, y p.endShape(); if (doFill) { var xAv = 0, yAv = 0, i, j; for (i = 0; i < vertArray.length; i++) { xAv += vertArray[i][0]; yAv += vertArray[i][1] } xAv /= vertArray.length;

width, height) {

y y +

- h, c_y, + h, c_y,

0, 0, 0, 0,

x, y x - w, x, y + x + w,

h, y, h, y,

0); 0); 0); 0);

yAv /= vertArray.length; var vert = [], fillVertArray = [], colorVertArray = []; vert[0] = xAv; vert[1] = yAv; vert[2] = 0; vert[3] = 0; vert[4] = 0; vert[5] = fillStyle[0]; vert[6] = fillStyle[1]; vert[7] = fillStyle[2]; vert[8] = fillStyle[3]; vert[9] = strokeStyle[0]; vert[10] = strokeStyle[1]; vert[11] = strokeStyle[2]; vert[12] = strokeStyle[3]; vert[13] = normalX; vert[14] = normalY; vert[15] = normalZ; vertArray.unshift(vert); for (i = 0; i < vertArray.length; i++) { for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i][j]); for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i][j]) } fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray) } }; p.normal = function(nx, ny, nz) { if (arguments.length !== 3 || !(typeof nx === "number" && typeof ny === "n umber" && typeof nz === "number")) throw "normal() requires three numeric argume nts."; normalX = nx; normalY = ny; normalZ = nz; if (curShape !== 0) if (normalMode === 0) normalMode = 1; else if (normalMode === 1) normalMode = 2 }; p.save = function(file, img) { if (img !== undef) return window.open(img.toDataURL(), "_blank"); return window.open(p.externals.canvas.toDataURL(), "_blank") }; var saveNumber = 0; p.saveFrame = function(file) { if (file === undef) file = "screen-####.png"; var frameFilename = file.replace(/#+/, function(all) { var s = "" + saveNumber++; while (s.length < all.length) s = "0" + s; return s }); p.save(frameFilename) }; var utilityContext2d = document.createElement("canvas").getContext("2d"); var canvasDataCache = [undef, undef, undef]; function getCanvasData(obj, w, h) { var canvasData = canvasDataCache.shift(); if (canvasData === undef) { canvasData = {}; canvasData.canvas = document.createElement("canvas");

canvasData.context = canvasData.canvas.getContext("2d") } canvasDataCache.push(canvasData); var canvas = canvasData.canvas, context = canvasData.context, width = w || obj.width, height = h || obj.height; canvas.width = width; canvas.height = height; if (!obj) context.clearRect(0, 0, width, height); else if ("data" in obj) context.putImageData(obj, 0, 0); else { context.clearRect(0, 0, width, height); context.drawImage(obj, 0, 0, width, height) } return canvasData } function buildPixelsObject(pImage) { return { getLength: function(aImg) { return function() { if (aImg.isRemote) throw "Image is loaded remotely. Cannot get lengt h."; else return aImg.imageData.data.length ? aImg.imageData.data.length / 4 : 0 } }(pImage), getPixel: function(aImg) { return function(i) { var offset = i * 4, data = aImg.imageData.data; if (aImg.isRemote) throw "Image is loaded remotely. Cannot get pixel s."; return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 } }(pImage), setPixel: function(aImg) { return function(i, c) { var offset = i * 4, data = aImg.imageData.data; if (aImg.isRemote) throw "Image is loaded remotely. Cannot set pixel ."; data[offset + 0] = (c >> 16) & 255; data[offset + 1] = (c >> 8) & 255; data[offset + 2] = c & 255; data[offset + 3] = (c >> 24) & 255; aImg.__isDirty = true } }(pImage), toArray: function(aImg) { return function() { var arr = [], data = aImg.imageData.data, length = aImg.width * aImg.height; if (aImg.isRemote) throw "Image is loaded remotely. Cannot get pixel s."; for (var i = 0, offset = 0; i < length; i++, offset += 4) arr.push(( data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255);

return arr } }(pImage), set: function(aImg) { return function(arr) { var offset, data, c; if (this.isRemote) throw "Image is loaded remotely. Cannot set pixel s."; data = aImg.imageData.data; for (var i = 0, aL = arr.length; i < aL; i++) { c = arr[i]; offset = i * 4; data[offset + 0] = (c >> 16) & 255; data[offset + 1] = (c >> 8) & 255; data[offset + 2] = c & 255; data[offset + 3] = (c >> 24) & 255 } aImg.__isDirty = true } }(pImage) } } var PImage = function(aWidth, aHeight, aFormat) { this.__isDirty = false; if (aWidth instanceof HTMLImageElement) this.fromHTMLImageData(aWidth); else if (aHeight || aFormat) { this.width = aWidth || 1; this.height = aHeight || 1; var canvas = this.sourceImg = document.createElement("canvas"); canvas.width = this.width; canvas.height = this.height; var imageData = this.imageData = canvas.getContext("2d").createImageData (this.width, this.height); this.format = aFormat === 2 || aFormat === 4 ? aFormat : 1; if (this.format === 1) for (var i = 3, data = this.imageData.data, len = data.length; i < len; i += 4) data[i] = 255; this.__isDirty = true; this.updatePixels() } else { this.width = 0; this.height = 0; this.imageData = utilityContext2d.createImageData(1, 1); this.format = 2 } this.pixels = buildPixelsObject(this) }; PImage.prototype = { __isPImage: true, updatePixels: function() { var canvas = this.sourceImg; if (canvas && canvas instanceof HTMLCanvasElement && this.__isDirty) can vas.getContext("2d").putImageData(this.imageData, 0, 0); this.__isDirty = false }, fromHTMLImageData: function(htmlImg) { var canvasData = getCanvasData(htmlImg); try { var imageData = canvasData.context.getImageData(0, 0, htmlImg.width, h tmlImg.height); this.fromImageData(imageData)

} catch(e) { if (htmlImg.width && htmlImg.height) { this.isRemote = true; this.width = htmlImg.width; this.height = htmlImg.height } } this.sourceImg = htmlImg }, "get": function(x, y, w, h) { if (!arguments.length) return p.get(this); if (arguments.length === 2) return p.get(x, y, this); if (arguments.length === 4) return p.get(x, y, w, h, this) }, "set": function(x, y, c) { p.set(x, y, c, this); this.__isDirty = true }, blend: function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE ) { if (arguments.length === 9) p.blend(this, srcImg, x, y, width, height, d x, dy, dwidth, dheight, this); else if (arguments.length === 10) p.blend(srcImg, x, y, width, height, d x, dy, dwidth, dheight, MODE, this); delete this.sourceImg }, copy: function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) { if (arguments.length === 8) p.blend(this, srcImg, sx, sy, swidth, sheigh t, dx, dy, dwidth, 0, this); else if (arguments.length === 9) p.blend(srcImg, sx, sy, swidth, sheight , dx, dy, dwidth, dheight, 0, this); delete this.sourceImg }, filter: function(mode, param) { if (arguments.length === 2) p.filter(mode, param, this); else if (arguments.length === 1) p.filter(mode, null, this); delete this.sourceImg }, save: function(file) { p.save(file, this) }, resize: function(w, h) { if (this.isRemote) throw "Image is loaded remotely. Cannot resize."; if (this.width !== 0 || this.height !== 0) { if (w === 0 && h !== 0) w = Math.floor(this.width / this.height * h); else if (h === 0 && w !== 0) h = Math.floor(this.height / this.width * w); var canvas = getCanvasData(this.imageData).canvas; var imageData = getCanvasData(canvas, w, h).context.getImageData(0, 0, w, h); this.fromImageData(imageData) } }, mask: function(mask) { var obj = this.toImageData(), i, size; if (mask instanceof PImage || mask.__isPImage) if (mask.width === this.w idth && mask.height === this.height) { mask = mask.toImageData(); for (i = 2, size = this.width * this.height * 4; i < size; i += 4) obj

.data[i + 1] = mask.data[i] } else throw "mask must have the same dimensions as PImage."; else if (mask instanceof Array) if (this.width * this.height === mask.length) for (i = 0, size = mask.length; i < size; ++i) obj.data[i * 4 + 3] = mask[i]; else throw "mask array must be the same length as PImage pixels array."; this.fromImageData(obj) }, loadPixels: nop, toImageData: function() { if (this.isRemote) return this.sourceImg; if (!this.__isDirty) return this.imageData; var canvasData = getCanvasData(this.sourceImg); return canvasData.context.getImageData(0, 0, this.width, this.height) }, toDataURL: function() { if (this.isRemote) throw "Image is loaded remotely. Cannot create dataUR I."; var canvasData = getCanvasData(this.imageData); return canvasData.canvas.toDataURL() }, fromImageData: function(canvasImg) { var w = canvasImg.width, h = canvasImg.height, canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"); this.width = canvas.width = w; this.height = canvas.height = h; ctx.putImageData(canvasImg, 0, 0); this.format = 2; this.imageData = canvasImg; this.sourceImg = canvas } }; p.PImage = PImage; p.createImage = function(w, h, mode) { return new PImage(w, h, mode) }; p.loadImage = function(file, type, callback) { if (type) file = file + "." + type; var pimg; if (curSketch.imageCache.images[file]) { pimg = new PImage(curSketch.imageCache.images[file]); pimg.loaded = true; return pimg } pimg = new PImage; var img = document.createElement("img"); pimg.sourceImg = img; img.onload = function(aImage, aPImage, aCallback) { var image = aImage; var pimg = aPImage; var callback = aCallback; return function() { pimg.fromHTMLImageData(image); pimg.loaded = true; if (callback) callback() } }(img, pimg, callback); img.src = file;

return pimg }; p.requestImage = p.loadImage; function get$2(x, y) { var data; if (x >= p.width || x < 0 || y < 0 || y >= p.height) return 0; if (isContextReplaced) { var offset = ((0 | x) + p.width * (0 | y)) * 4; data = p.imageData.data; return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (da ta[offset + 1] & 255) << 8 | data[offset + 2] & 255 } data = p.toImageData(0 | x, 0 | y, 1, 1).data; return (data[3] & 255) << 24 | (data[0] & 255) << 16 | (data[1] & 255) << 8 | data[2] & 255 } function get$3(x, y, img) { if (img.isRemote) throw "Image is loaded remotely. Cannot get x,y."; var offset = y * img.width * 4 + x * 4, data = img.imageData.data; return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data [offset + 1] & 255) << 8 | data[offset + 2] & 255 } function get$4(x, y, w, h) { var c = new PImage(w, h, 2); c.fromImageData(p.toImageData(x, y, w, h)); return c } function get$5(x, y, w, h, img) { if (img.isRemote) throw "Image is loaded remotely. Cannot get x,y,w,h."; var c = new PImage(w, h, 2), cData = c.imageData.data, imgWidth = img.width, imgHeight = img.height, imgData = img.imageData.data; var startRow = Math.max(0, -y), startColumn = Math.max(0, -x), stopRow = Math.min(h, imgHeight - y), stopColumn = Math.min(w, imgWidth - x); for (var i = startRow; i < stopRow; ++i) { var sourceOffset = ((y + i) * imgWidth + (x + startColumn)) * 4; var targetOffset = (i * w + startColumn) * 4; for (var j = startColumn; j < stopColumn; ++j) { cData[targetOffset++] = imgData[sourceOffset++]; cData[targetOffset++] = imgData[sourceOffset++]; cData[targetOffset++] = imgData[sourceOffset++]; cData[targetOffset++] = imgData[sourceOffset++] } } c.__isDirty = true; return c } p.get = function(x, y, w, h, img) { if (img !== undefined) return get$5(x, y, w, h, img); if (h !== undefined) return get$4(x, y, w, h); if (w !== undefined) return get$3(x, y, w); if (y !== undefined) return get$2(x, y); if (x !== undefined) return get$5(0, 0, x.width, x.height, x); return get$4(0, 0, p.width, p.height)

}; p.createGraphics = function(w, h, render) { var pg = new Processing; pg.size(w, h, render); pg.background(0, 0); return pg }; function resetContext() { if (isContextReplaced) { curContext = originalContext; isContextReplaced = false; p.updatePixels() } } function SetPixelContextWrapper() { function wrapFunction(newContext, name) { function wrapper() { resetContext(); curContext[name].apply(curContext, arguments) } newContext[name] = wrapper } function wrapProperty(newContext, name) { function getter() { resetContext(); return curContext[name] } function setter(value) { resetContext(); curContext[name] = value } p.defineProperty(newContext, name, { get: getter, set: setter }) } for (var n in curContext) if (typeof curContext[n] === "function") wrapFun ction(this, n); else wrapProperty(this, n) } function replaceContext() { if (isContextReplaced) return; p.loadPixels(); if (proxyContext === null) { originalContext = curContext; proxyContext = new SetPixelContextWrapper } isContextReplaced = true; curContext = proxyContext; setPixelsCached = 0 } function set$3(x, y, c) { if (x < p.width && x >= 0 && y >= 0 && y < p.height) { replaceContext(); p.pixels.setPixel((0 | x) + p.width * (0 | y), c); if (++setPixelsCached > maxPixelsCached) resetContext() } }

function set$4(x, y, obj, img) { if (img.isRemote) throw "Image is loaded remotely. Cannot set x,y."; var c = p.color.toArray(obj); var offset = y * img.width * 4 + x * 4; var data = img.imageData.data; data[offset] = c[0]; data[offset + 1] = c[1]; data[offset + 2] = c[2]; data[offset + 3] = c[3] } p.set = function(x, y, obj, img) { var color, oldFill; if (arguments.length === 3) if (typeof obj === "number") set$3(x, y, obj); else { if (obj instanceof PImage || obj.__isPImage) p.image(obj, x, y) } else if (arguments.length === 4) set$4(x, y, obj, img) }; p.imageData = {}; p.pixels = { getLength: function() { return p.imageData.data.length ? p.imageData.data.length / 4 : 0 }, getPixel: function(i) { var offset = i * 4, data = p.imageData.data; return data[offset + 3] << 24 & 4278190080 | data[offset + 0] << 16 & 16 711680 | data[offset + 1] << 8 & 65280 | data[offset + 2] & 255 }, setPixel: function(i, c) { var offset = i * 4, data = p.imageData.data; data[offset + 0] = (c & 16711680) >>> 16; data[offset + 1] = (c & 65280) >>> 8; data[offset + 2] = c & 255; data[offset + 3] = (c & 4278190080) >>> 24 }, toArray: function() { var arr = [], length = p.imageData.width * p.imageData.height, data = p.imageData.data; for (var i = 0, offset = 0; i < length; i++, offset += 4) arr.push(data[ offset + 3] << 24 & 4278190080 | data[offset + 0] << 16 & 16711680 | data[offset + 1] << 8 & 65280 | data[offset + 2] & 255); return arr }, set: function(arr) { for (var i = 0, aL = arr.length; i < aL; i++) this.setPixel(i, arr[i]) } }; p.loadPixels = function() { p.imageData = drawing.$ensureContext().getImageData(0, 0, p.width, p.heigh t) }; p.updatePixels = function() { if (p.imageData) drawing.$ensureContext().putImageData(p.imageData, 0, 0) }; p.hint = function(which) { var curContext = drawing.$ensureContext(); if (which === 4) { curContext.disable(curContext.DEPTH_TEST);

curContext.depthMask(false); curContext.clear(curContext.DEPTH_BUFFER_BIT) } else if (which === -4) { curContext.enable(curContext.DEPTH_TEST); curContext.depthMask(true) } else if (which === -1 || which === 2) renderSmooth = true; else if (which === 1) renderSmooth = false }; var backgroundHelper = function(arg1, arg2, arg3, arg4) { var obj; if (arg1 instanceof PImage || arg1.__isPImage) { obj = arg1; if (!obj.loaded) throw "Error using image in background(): PImage not lo aded."; if (obj.width !== p.width || obj.height !== p.height) throw "Background image must be the same dimensions as the canvas."; } else obj = p.color(arg1, arg2, arg3, arg4); backgroundObj = obj }; Drawing2D.prototype.background = function(arg1, arg2, arg3, arg4) { if (arg1 !== undef) backgroundHelper(arg1, arg2, arg3, arg4); if (backgroundObj instanceof PImage || backgroundObj.__isPImage) { saveContext(); curContext.setTransform(1, 0, 0, 1, 0, 0); p.image(backgroundObj, 0, 0); restoreContext() } else { saveContext(); curContext.setTransform(1, 0, 0, 1, 0, 0); if (p.alpha(backgroundObj) !== colorModeA) curContext.clearRect(0, 0, p. width, p.height); curContext.fillStyle = p.color.toString(backgroundObj); curContext.fillRect(0, 0, p.width, p.height); isFillDirty = true; restoreContext() } }; Drawing3D.prototype.background = function(arg1, arg2, arg3, arg4) { if (arguments.length > 0) backgroundHelper(arg1, arg2, arg3, arg4); var c = p.color.toGLArray(backgroundObj); curContext.clearColor(c[0], c[1], c[2], c[3]); curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT ) }; Drawing2D.prototype.image = function(img, x, y, w, h) { x = Math.round(x); y = Math.round(y); if (img.width > 0) { var wid = w || img.width; var hgt = h || img.height; var bounds = imageModeConvert(x || 0, y || 0, w || img.width, h || img.h eight, arguments.length < 4); var fastImage = !!img.sourceImg && curTint === null; if (fastImage) { var htmlElement = img.sourceImg; if (img.__isDirty) img.updatePixels(); curContext.drawImage(htmlElement, 0, 0, htmlElement.width, htmlElement .height, bounds.x, bounds.y, bounds.w, bounds.h) } else { var obj = img.toImageData();

if (curTint !== null) { curTint(obj); img.__isDirty = true } curContext.drawImage(getCanvasData(obj).canvas, 0, 0, img.width, img.h eight, bounds.x, bounds.y, bounds.w, bounds.h) } } }; Drawing3D.prototype.image = function(img, x, y, w, h) { if (img.width > 0) { x = Math.round(x); y = Math.round(y); w = w || img.width; h = h || img.height; p.beginShape(p.QUADS); p.texture(img); p.vertex(x, y, 0, 0, 0); p.vertex(x, y + h, 0, 0, h); p.vertex(x + w, y + h, 0, w, h); p.vertex(x + w, y, 0, w, 0); p.endShape() } }; p.tint = function(a1, a2, a3, a4) { var tintColor = p.color(a1, a2, a3, a4); var r = p.red(tintColor) / colorModeX; var g = p.green(tintColor) / colorModeY; var b = p.blue(tintColor) / colorModeZ; var a = p.alpha(tintColor) / colorModeA; curTint = function(obj) { var data = obj.data, length = 4 * obj.width * obj.height; for (var i = 0; i < length;) { data[i++] *= r; data[i++] *= g; data[i++] *= b; data[i++] *= a } }; curTint3d = function(data) { for (var i = 0; i < data.length;) { data[i++] = r; data[i++] = g; data[i++] = b; data[i++] = a } } }; p.noTint = function() { curTint = null; curTint3d = null }; p.copy = function(src, sx, sy, sw, sh, dx, dy, dw, dh) { if (dh === undef) { dh = dw; dw = dy; dy = dx; dx = sh; sh = sw;

sw = sy; sy = sx; sx = src; src = p } p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, 0) }; p.blend = function(src, sx, sy, sw, sh, dx, dy, dw, dh, mode, pimgdest) { if (src.isRemote) throw "Image is loaded remotely. Cannot blend image."; if (mode === undef) { mode = dh; dh = dw; dw = dy; dy = dx; dx = sh; sh = sw; sw = sy; sy = sx; sx = src; src = p } var sx2 = sx + sw, sy2 = sy + sh, dx2 = dx + dw, dy2 = dy + dh, dest = pimgdest || p; if (pimgdest === undef || mode === undef) p.loadPixels(); src.loadPixels(); if (src === p && p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) p.blit_r esize(p.get(sx, sy, sx2 - sx, sy2 - sy), 0, 0, sx2 - sx - 1, sy2 - sy - 1, dest. imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); else p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); if (pimgdest === undef) p.updatePixels() }; var buildBlurKernel = function(r) { var radius = p.floor(r * 3.5), i, radiusi; radius = radius < 1 ? 1 : radius < 248 ? radius : 248; if (p.shared.blurRadius !== radius) { p.shared.blurRadius = radius; p.shared.blurKernelSize = 1 + (p.shared.blurRadius << 1); p.shared.blurKernel = new Float32Array(p.shared.blurKernelSize); var sharedBlurKernal = p.shared.blurKernel; var sharedBlurKernelSize = p.shared.blurKernelSize; var sharedBlurRadius = p.shared.blurRadius; for (i = 0; i < sharedBlurKernelSize; i++) sharedBlurKernal[i] = 0; var radiusiSquared = (radius - 1) * (radius - 1); for (i = 1; i < radius; i++) sharedBlurKernal[radius + i] = sharedBlurKe rnal[radiusi] = radiusiSquared; sharedBlurKernal[radius] = radius * radius } }; var blurARGB = function(r, aImg) { var sum, cr, cg, cb, ca, c, m; var read, ri, ym, ymi, bk0; var wh = aImg.pixels.getLength(); var r2 = new Float32Array(wh); var g2 = new Float32Array(wh); var b2 = new Float32Array(wh);

var a2 = new Float32Array(wh); var yi = 0; var x, y, i, offset; buildBlurKernel(r); var aImgHeight = aImg.height; var aImgWidth = aImg.width; var sharedBlurKernelSize = p.shared.blurKernelSize; var sharedBlurRadius = p.shared.blurRadius; var sharedBlurKernal = p.shared.blurKernel; var pix = aImg.imageData.data; for (y = 0; y < aImgHeight; y++) { for (x = 0; x < aImgWidth; x++) { cb = cg = cr = ca = sum = 0; read = x - sharedBlurRadius; if (read < 0) { bk0 = -read; read = 0 } else { if (read >= aImgWidth) break; bk0 = 0 } for (i = bk0; i < sharedBlurKernelSize; i++) { if (read >= aImgWidth) break; offset = (read + yi) * 4; m = sharedBlurKernal[i]; ca += m * pix[offset + 3]; cr += m * pix[offset]; cg += m * pix[offset + 1]; cb += m * pix[offset + 2]; sum += m; read++ } ri = yi + x; a2[ri] = ca / sum; r2[ri] = cr / sum; g2[ri] = cg / sum; b2[ri] = cb / sum } yi += aImgWidth } yi = 0; ym = -sharedBlurRadius; ymi = ym * aImgWidth; for (y = 0; y < aImgHeight; y++) { for (x = 0; x < aImgWidth; x++) { cb = cg = cr = ca = sum = 0; if (ym < 0) { bk0 = ri = -ym; read = x } else { if (ym >= aImgHeight) break; bk0 = 0; ri = ym; read = x + ymi } for (i = bk0; i < sharedBlurKernelSize; i++) { if (ri >= aImgHeight) break; m = sharedBlurKernal[i]; ca += m * a2[read]; cr += m * r2[read];

cg += m * g2[read]; cb += m * b2[read]; sum += m; ri++; read += aImgWidth } offset = (x + yi) * 4; pix[offset] = cr / sum; pix[offset + 1] = cg / sum; pix[offset + 2] = cb / sum; pix[offset + 3] = ca / sum } yi += aImgWidth; ymi += aImgWidth; ym++ } }; var dilate = function(isInverted, aImg) { var currIdx = 0; var maxIdx = aImg.pixels.getLength(); var out = new Int32Array(maxIdx); var currRowIdx, maxRowIdx, colOrig, colOut, currLum; var idxRight, idxLeft, idxUp, idxDown, colRight, colLeft, colUp, colDown, lumRight, lumLeft, lumUp, lumDown; if (!isInverted) while (currIdx < maxIdx) { currRowIdx = currIdx; maxRowIdx = currIdx + aImg.width; while (currIdx < maxRowIdx) { colOrig = colOut = aImg.pixels.getPixel(currIdx); idxLeft = currIdx - 1; idxRight = currIdx + 1; idxUp = currIdx - aImg.width; idxDown = currIdx + aImg.width; if (idxLeft < currRowIdx) idxLeft = currIdx; if (idxRight >= maxRowIdx) idxRight = currIdx; if (idxUp < 0) idxUp = 0; if (idxDown >= maxIdx) idxDown = currIdx; colUp = aImg.pixels.getPixel(idxUp); colLeft = aImg.pixels.getPixel(idxLeft); colDown = aImg.pixels.getPixel(idxDown); colRight = aImg.pixels.getPixel(idxRight); currLum = 77 * (colOrig >> 16 & 255) + 151 * (colOrig >> 8 & 255) + 28 * (colOrig & 255); lumLeft = 77 * (colLeft >> 16 & 255) + 151 * (colLeft >> 8 & 255) + 28 * (colLeft & 255); lumRight = 77 * (colRight >> 16 & 255) + 151 * (colRight >> 8 & 255) + 28 * (colRight & 255); lumUp = 77 * (colUp >> 16 & 255) + 151 * (colUp >> 8 & 255) + 28 * (co lUp & 255); lumDown = 77 * (colDown >> 16 & 255) + 151 * (colDown >> 8 & 255) + 28 * (colDown & 255); if (lumLeft > currLum) { colOut = colLeft; currLum = lumLeft } if (lumRight > currLum) { colOut = colRight; currLum = lumRight } if (lumUp > currLum) {

colOut = colUp; currLum = lumUp } if (lumDown > currLum) { colOut = colDown; currLum = lumDown } out[currIdx++] = colOut } } else while (currIdx < maxIdx) { currRowIdx = currIdx; maxRowIdx = currIdx + aImg.width; while (currIdx < maxRowIdx) { colOrig = colOut = aImg.pixels.getPixel(currIdx); idxLeft = currIdx - 1; idxRight = currIdx + 1; idxUp = currIdx - aImg.width; idxDown = currIdx + aImg.width; if (idxLeft < currRowIdx) idxLeft = currIdx; if (idxRight >= maxRowIdx) idxRight = currIdx; if (idxUp < 0) idxUp = 0; if (idxDown >= maxIdx) idxDown = currIdx; colUp = aImg.pixels.getPixel(idxUp); colLeft = aImg.pixels.getPixel(idxLeft); colDown = aImg.pixels.getPixel(idxDown); colRight = aImg.pixels.getPixel(idxRight); currLum = 77 * (colOrig >> 16 & 255) + 151 * (colOrig >> 8 & 255) + 28 * (colOrig & 255); lumLeft = 77 * (colLeft >> 16 & 255) + 151 * (colLeft >> 8 & 255) + 28 * (colLeft & 255); lumRight = 77 * (colRight >> 16 & 255) + 151 * (colRight >> 8 & 255) + 28 * (colRight & 255); lumUp = 77 * (colUp >> 16 & 255) + 151 * (colUp >> 8 & 255) + 28 * (co lUp & 255); lumDown = 77 * (colDown >> 16 & 255) + 151 * (colDown >> 8 & 255) + 28 * (colDown & 255); if (lumLeft < currLum) { colOut = colLeft; currLum = lumLeft } if (lumRight < currLum) { colOut = colRight; currLum = lumRight } if (lumUp < currLum) { colOut = colUp; currLum = lumUp } if (lumDown < currLum) { colOut = colDown; currLum = lumDown } out[currIdx++] = colOut } } aImg.pixels.set(out) }; p.filter = function(kind, param, aImg) { var img, col, lum, i; if (arguments.length === 3) {

aImg.loadPixels(); img = aImg } else { p.loadPixels(); img = p } if (param === undef) param = null; if (img.isRemote) throw "Image is loaded remotely. Cannot filter image."; var imglen = img.pixels.getLength(); switch (kind) { case 11: var radius = param || 1; blurARGB(radius, img); break; case 12: if (img.format === 4) { for (i = 0; i < imglen; i++) { col = 255 - img.pixels.getPixel(i); img.pixels.setPixel(i, 4278190080 | col << 16 | col << 8 | col) } img.format = 1 } else for (i = 0; i < imglen; i++) { col = img.pixels.getPixel(i); lum = 77 * (col >> 16 & 255) + 151 * (col >> 8 & 255) + 28 * (col & 25 5) >> 8; img.pixels.setPixel(i, col & 4278190080 | lum << 16 | lum << 8 | lum) } break; case 13: for (i = 0; i < imglen; i++) img.pixels.setPixel(i, img.pixels.getPixel( i) ^ 16777215); break; case 15: if (param === null) throw "Use filter(POSTERIZE, int levels) instead of filter(POSTERIZE)"; var levels = p.floor(param); if (levels < 2 || levels > 255) throw "Levels must be between 2 and 255 for filter(POSTERIZE, levels)"; var levels1 = levels - 1; for (i = 0; i < imglen; i++) { var rlevel = img.pixels.getPixel(i) >> 16 & 255; var glevel = img.pixels.getPixel(i) >> 8 & 255; var blevel = img.pixels.getPixel(i) & 255; rlevel = (rlevel * levels >> 8) * 255 / levels1; glevel = (glevel * levels >> 8) * 255 / levels1; blevel = (blevel * levels >> 8) * 255 / levels1; img.pixels.setPixel(i, 4278190080 & img.pixels.getPixel(i) | rlevel << 16 | glevel << 8 | blevel) } break; case 14: for (i = 0; i < imglen; i++) img.pixels.setPixel(i, img.pixels.getPixel( i) | 4278190080); img.format = 1; break; case 16: if (param === null) param = 0.5; if (param < 0 || param > 1) throw "Level must be between 0 and 1 for fil ter(THRESHOLD, level)"; var thresh = p.floor(param * 255);

for (i = 0; i < imglen; i++) { var max = p.max((img.pixels.getPixel(i) & 16711680) >> 16, p.max((img. pixels.getPixel(i) & 65280) >> 8, img.pixels.getPixel(i) & 255)); img.pixels.setPixel(i, img.pixels.getPixel(i) & 4278190080 | (max < th resh ? 0 : 16777215)) } break; case 17: dilate(true, img); break; case 18: dilate(false, img); break } img.updatePixels() }; p.shared = { fracU: 0, ifU: 0, fracV: 0, ifV: 0, u1: 0, u2: 0, v1: 0, v2: 0, sX: 0, sY: 0, iw: 0, iw1: 0, ih1: 0, ul: 0, ll: 0, ur: 0, lr: 0, cUL: 0, cLL: 0, cUR: 0, cLR: 0, srcXOffset: 0, srcYOffset: 0, r: 0, g: 0, b: 0, a: 0, srcBuffer: null, blurRadius: 0, blurKernelSize: 0, blurKernel: null }; p.intersect = function(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) { var sw = sx2 - sx1 + 1; var sh = sy2 - sy1 + 1; var dw = dx2 - dx1 + 1; var dh = dy2 - dy1 + 1; if (dx1 < sx1) { dw += dx1 - sx1; if (dw > sw) dw = sw } else { var w = sw + sx1 - dx1; if (dw > w) dw = w

} if (dy1 < sy1) { dh += dy1 - sy1; if (dh > sh) dh = sh } else { var h = sh + sy1 - dy1; if (dh > h) dh = h } return ! (dw <= 0 || dh <= 0) }; var blendFuncs = {}; blendFuncs[1] = p.modes.blend; blendFuncs[2] = p.modes.add; blendFuncs[4] = p.modes.subtract; blendFuncs[8] = p.modes.lightest; blendFuncs[16] = p.modes.darkest; blendFuncs[0] = p.modes.replace; blendFuncs[32] = p.modes.difference; blendFuncs[64] = p.modes.exclusion; blendFuncs[128] = p.modes.multiply; blendFuncs[256] = p.modes.screen; blendFuncs[512] = p.modes.overlay; blendFuncs[1024] = p.modes.hard_light; blendFuncs[2048] = p.modes.soft_light; blendFuncs[4096] = p.modes.dodge; blendFuncs[8192] = p.modes.burn; p.blit_resize = function(img, srcX1, srcY1, srcX2, srcY2, destPixels, screen W, screenH, destX1, destY1, destX2, destY2, mode) { var x, y; if (srcX1 < 0) srcX1 = 0; if (srcY1 < 0) srcY1 = 0; if (srcX2 >= img.width) srcX2 = img.width - 1; if (srcY2 >= img.height) srcY2 = img.height - 1; var srcW = srcX2 - srcX1; var srcH = srcY2 - srcY1; var destW = destX2 - destX1; var destH = destY2 - destY1; if (destW <= 0 || destH <= 0 || srcW <= 0 || srcH <= 0 || destX1 >= screen W || destY1 >= screenH || srcX1 >= img.width || srcY1 >= img.height) return; var dx = Math.floor(srcW / destW * 32768); var dy = Math.floor(srcH / destH * 32768); var pshared = p.shared; pshared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * 32768) ; pshared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * 32768) ; if (destX1 < 0) { destW += destX1; destX1 = 0 } if (destY1 < 0) { destH += destY1; destY1 = 0 } destW = Math.min(destW, screenW - destX1); destH = Math.min(destH, screenH - destY1); var destOffset = destY1 * screenW + destX1; var destColor; pshared.srcBuffer = img.imageData.data; pshared.iw = img.width;

pshared.iw1 = img.width - 1; pshared.ih1 = img.height - 1; var filterBilinear = p.filter_bilinear, filterNewScanline = p.filter_new_scanline, blendFunc = blendFuncs[mode], blendedColor, idx, cULoffset, cURoffset, cLLoffset, cLRoffset, ALPHA_MAS K = 4278190080, RED_MASK = 16711680, GREEN_MASK = 65280, BLUE_MASK = 255, PREC_MAXVAL = 32767, PRECISIONB = 15, PREC_RED_SHIFT = 1, PREC_ALPHA_SHIFT = 9, srcBuffer = pshared.srcBuffer, min = Math.min; for (y = 0; y < destH; y++) { pshared.sX = pshared.srcXOffset; pshared.fracV = pshared.srcYOffset & PREC_MAXVAL; pshared.ifV = PREC_MAXVAL - pshared.fracV; pshared.v1 = (pshared.srcYOffset >> PRECISIONB) * pshared.iw; pshared.v2 = min((pshared.srcYOffset >> PRECISIONB) + 1, pshared.ih1) * pshared.iw; for (x = 0; x < destW; x++) { idx = (destOffset + x) * 4; destColor = destPixels[idx + 3] << 24 & ALPHA_MASK | destPixels[idx] < < 16 & RED_MASK | destPixels[idx + 1] << 8 & GREEN_MASK | destPixels[idx + 2] & BLUE_MASK; pshared.fracU = pshared.sX & PREC_MAXVAL; pshared.ifU = PREC_MAXVAL - pshared.fracU; pshared.ul = pshared.ifU * pshared.ifV >> PRECISIONB; pshared.ll = pshared.ifU * pshared.fracV >> PRECISIONB; pshared.ur = pshared.fracU * pshared.ifV >> PRECISIONB; pshared.lr = pshared.fracU * pshared.fracV >> PRECISIONB; pshared.u1 = pshared.sX >> PRECISIONB; pshared.u2 = min(pshared.u1 + 1, pshared.iw1); cULoffset = (pshared.v1 + pshared.u1) * 4; cURoffset = (pshared.v1 + pshared.u2) * 4; cLLoffset = (pshared.v2 + pshared.u1) * 4; cLRoffset = (pshared.v2 + pshared.u2) * 4; pshared.cUL = srcBuffer[cULoffset + 3] << 24 & ALPHA_MASK | srcBuffer[ cULoffset] << 16 & RED_MASK | srcBuffer[cULoffset + 1] << 8 & GREEN_MASK | srcBu ffer[cULoffset + 2] & BLUE_MASK; pshared.cUR = srcBuffer[cURoffset + 3] << 24 & ALPHA_MASK | srcBuffer[ cURoffset] << 16 & RED_MASK | srcBuffer[cURoffset + 1] << 8 & GREEN_MASK | srcBu ffer[cURoffset + 2] & BLUE_MASK; pshared.cLL = srcBuffer[cLLoffset + 3] << 24 & ALPHA_MASK | srcBuffer[ cLLoffset] << 16 & RED_MASK | srcBuffer[cLLoffset + 1] << 8 & GREEN_MASK | srcBu ffer[cLLoffset + 2] & BLUE_MASK; pshared.cLR = srcBuffer[cLRoffset + 3] << 24 & ALPHA_MASK | srcBuffer[ cLRoffset] << 16 & RED_MASK | srcBuffer[cLRoffset + 1] << 8 & GREEN_MASK | srcBu ffer[cLRoffset + 2] & BLUE_MASK; pshared.r = pshared.ul * ((pshared.cUL & RED_MASK) >> 16) + pshared.ll * ((pshared.cLL & RED_MASK) >> 16) + pshared.ur * ((pshared.cUR & RED_MASK) >> 16) + pshared.lr * ((pshared.cLR & RED_MASK) >> 16) << PREC_RED_SHIFT & RED_MASK ; pshared.g = pshared.ul * (pshared.cUL & GREEN_MASK) + pshared.ll * (ps hared.cLL & GREEN_MASK) + pshared.ur * (pshared.cUR & GREEN_MASK) + pshared.lr * (pshared.cLR & GREEN_MASK) >>> PRECISIONB & GREEN_MASK; pshared.b = pshared.ul * (pshared.cUL & BLUE_MASK) + pshared.ll * (psh

ared.cLL & BLUE_MASK) + pshared.ur * (pshared.cUR & BLUE_MASK) + pshared.lr * (p shared.cLR & BLUE_MASK) >>> PRECISIONB; pshared.a = pshared.ul * ((pshared.cUL & ALPHA_MASK) >>> 24) + pshared .ll * ((pshared.cLL & ALPHA_MASK) >>> 24) + pshared.ur * ((pshared.cUR & ALPHA_M ASK) >>> 24) + pshared.lr * ((pshared.cLR & ALPHA_MASK) >>> 24) << PREC_ALPHA_SH IFT & ALPHA_MASK; blendedColor = blendFunc(destColor, pshared.a | pshared.r | pshared.g | pshared.b); destPixels[idx] = (blendedColor & RED_MASK) >>> 16; destPixels[idx + 1] = (blendedColor & GREEN_MASK) >>> 8; destPixels[idx + 2] = blendedColor & BLUE_MASK; destPixels[idx + 3] = (blendedColor & ALPHA_MASK) >>> 24; pshared.sX += dx } destOffset += screenW; pshared.srcYOffset += dy } }; p.loadFont = function(name, size) { if (name === undef) throw "font name required in loadFont."; if (name.indexOf(".svg") === -1) { if (size === undef) size = curTextFont.size; return PFont.get(name, size) } var font = p.loadGlyphs(name); return { name: name, css: "12px sans-serif", glyph: true, units_per_em: font.units_per_em, horiz_adv_x: 1 / font.units_per_em * font.horiz_adv_x, ascent: font.ascent, descent: font.descent, width: function(str) { var width = 0; var len = str.length; for (var i = 0; i < len; i++) try { width += parseFloat(p.glyphLook(p.glyphTable[name], str[i]).horiz_ad v_x) } catch(e) { Processing.debug(e) } return width / p.glyphTable[name].units_per_em } } }; p.createFont = function(name, size) { return p.loadFont(name, size) }; p.textFont = function(pfont, size) { if (size !== undef) { if (!pfont.glyph) pfont = PFont.get(pfont.name, size); curTextSize = size } curTextFont = pfont; curFontName = curTextFont.name; curTextAscent = curTextFont.ascent; curTextDescent = curTextFont.descent; curTextLeading = curTextFont.leading; var curContext = drawing.$ensureContext();

curContext.font = curTextFont.css }; p.textSize = function(size) { curTextFont = PFont.get(curFontName, size); curTextSize = size; curTextAscent = curTextFont.ascent; curTextDescent = curTextFont.descent; curTextLeading = curTextFont.leading; var curContext = drawing.$ensureContext(); curContext.font = curTextFont.css }; p.textAscent = function() { return curTextAscent }; p.textDescent = function() { return curTextDescent }; p.textLeading = function(leading) { curTextLeading = leading }; p.textAlign = function(xalign, yalign) { horizontalTextAlignment = xalign; verticalTextAlignment = yalign || 0 }; function toP5String(obj) { if (obj instanceof String) return obj; if (typeof obj === "number") { if (obj === (0 | obj)) return obj.toString(); return p.nf(obj, 0, 3) } if (obj === null || obj === undef) return ""; return obj.toString() } Drawing2D.prototype.textWidth = function(str) { var lines = toP5String(str).split(/\r?\n/g), width = 0; var i, linesCount = lines.length; curContext.font = curTextFont.css; for (i = 0; i < linesCount; ++i) width = Math.max(width, curTextFont.measu reTextWidth(lines[i])); return width | 0 }; Drawing3D.prototype.textWidth = function(str) { var lines = toP5String(str).split(/\r?\n/g), width = 0; var i, linesCount = lines.length; if (textcanvas === undef) textcanvas = document.createElement("canvas"); var textContext = textcanvas.getContext("2d"); textContext.font = curTextFont.css; for (i = 0; i < linesCount; ++i) width = Math.max(width, textContext.measu reText(lines[i]).width); return width | 0 }; p.glyphLook = function(font, chr) { try { switch (chr) { case "1": return font.one; case "2":

return font.two; case "3": return font.three; case "4": return font.four; case "5": return font.five; case "6": return font.six; case "7": return font.seven; case "8": return font.eight; case "9": return font.nine; case "0": return font.zero; case " ": return font.space; case "$": return font.dollar; case "!": return font.exclam; case '"': return font.quotedbl; case "#": return font.numbersign; case "%": return font.percent; case "&": return font.ampersand; case "'": return font.quotesingle; case "(": return font.parenleft; case ")": return font.parenright; case "*": return font.asterisk; case "+": return font.plus; case ",": return font.comma; case "-": return font.hyphen; case ".": return font.period; case "/": return font.slash; case "_": return font.underscore; case ":": return font.colon; case ";": return font.semicolon; case "<": return font.less; case "=": return font.equal; case ">":

return font.greater; case "?": return font.question; case "@": return font.at; case "[": return font.bracketleft; case "\\": return font.backslash; case "]": return font.bracketright; case "^": return font.asciicircum; case "`": return font.grave; case "{": return font.braceleft; case "|": return font.bar; case "}": return font.braceright; case "~": return font.asciitilde; default: return font[chr] } } catch(e) { Processing.debug(e) } }; Drawing2D.prototype.text$line = function(str, x, y, z, align) { var textWidth = 0, xOffset = 0; if (!curTextFont.glyph) { if (str && "fillText" in curContext) { if (isFillDirty) { curContext.fillStyle = p.color.toString(currentFillColor); isFillDirty = false } if (align === 39 || align === 3) { textWidth = curTextFont.measureTextWidth(str); if (align === 39) xOffset = -textWidth; else xOffset = -textWidth / 2 } curContext.fillText(str, x + xOffset, y) } } else { var font = p.glyphTable[curFontName]; saveContext(); curContext.translate(x, y + curTextSize); if (align === 39 || align === 3) { textWidth = font.width(str); if (align === 39) xOffset = -textWidth; else xOffset = -textWidth / 2 } var upem = font.units_per_em, newScale = 1 / upem * curTextSize; curContext.scale(newScale, newScale); for (var i = 0, len = str.length; i < len; i++) try { p.glyphLook(font, str[i]).draw()

} catch(e) { Processing.debug(e) } restoreContext() } }; Drawing3D.prototype.text$line = function(str, x, y, z, align) { if (textcanvas === undef) textcanvas = document.createElement("canvas"); var oldContext = curContext; curContext = textcanvas.getContext("2d"); curContext.font = curTextFont.css; var textWidth = curTextFont.measureTextWidth(str); textcanvas.width = textWidth; textcanvas.height = curTextSize; curContext = textcanvas.getContext("2d"); curContext.font = curTextFont.css; curContext.textBaseline = "top"; Drawing2D.prototype.text$line(str, 0, 0, 0, 37); var aspect = textcanvas.width / textcanvas.height; curContext = oldContext; curContext.bindTexture(curContext.TEXTURE_2D, textTex); curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContex t.RGBA, curContext.UNSIGNED_BYTE, textcanvas); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FIL TER, curContext.LINEAR); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FIL TER, curContext.LINEAR); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); var xOffset = 0; if (align === 39) xOffset = -textWidth; else if (align === 3) xOffset = -textWidth / 2; var model = new PMatrix3D; var scalefactor = curTextSize * 0.5; model.translate(x + xOffset - scalefactor / 2, y - scalefactor, z); model.scale(-aspect * scalefactor, -scalefactor, scalefactor); model.translate(-1, -1, -1); model.transpose(); var view = new PMatrix3D; view.scale(1, -1, 1); view.apply(modelView.array()); view.transpose(); curContext.useProgram(programObject2D); vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, textBuffer ); vertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord", 2 , textureBuffer); uniformi("uSampler2d", programObject2D, "uSampler", [0]); uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", true); uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()) ; uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); uniformf("uColor2d", programObject2D, "uColor", fillStyle); curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); curContext.drawElements(curContext.TRIANGLES, 6, curContext.UNSIGNED_SHORT , 0) };

function text$4(str, x, y, z) { var lines, linesCount; if (str.indexOf("\n") < 0) { lines = [str]; linesCount = 1 } else { lines = str.split(/\r?\n/g); linesCount = lines.length } var yOffset = 0; if (verticalTextAlignment === 101) yOffset = curTextAscent + curTextDescen t; else if (verticalTextAlignment === 3) yOffset = curTextAscent / 2 - (lines Count - 1) * curTextLeading / 2; else if (verticalTextAlignment === 102) yOffset = -(curTextDescent + (line sCount - 1) * curTextLeading); for (var i = 0; i < linesCount; ++i) { var line = lines[i]; drawing.text$line(line, x, y + yOffset, z, horizontalTextAlignment); yOffset += curTextLeading } } function text$6(str, x, y, width, height, z) { if (str.length === 0 || width === 0 || height === 0) return; if (curTextSize > height) return; var spaceMark = -1; var start = 0; var lineWidth = 0; var drawCommands = []; for (var charPos = 0, len = str.length; charPos < len; charPos++) { var currentChar = str[charPos]; var spaceChar = currentChar === " "; var letterWidth = curTextFont.measureTextWidth(currentChar); if (currentChar !== "\n" && lineWidth + letterWidth <= width) { if (spaceChar) spaceMark = charPos; lineWidth += letterWidth } else { if (spaceMark + 1 === start) if (charPos > 0) spaceMark = charPos; else return; if (currentChar === "\n") { drawCommands.push({ text: str.substring(start, charPos), width: lineWidth }); start = charPos + 1 } else { drawCommands.push({ text: str.substring(start, spaceMark + 1), width: lineWidth }); start = spaceMark + 1 } lineWidth = 0; charPos = start - 1 } } if (start < len) drawCommands.push({ text: str.substring(start), width: lineWidth });

var xOffset = 1, yOffset = curTextAscent; if (horizontalTextAlignment === 3) xOffset = width / 2; else if (horizontalTextAlignment === 39) xOffset = width; var linesCount = drawCommands.length, visibleLines = Math.min(linesCount, Math.floor(height / curTextLeading)) ; if (verticalTextAlignment === 101) yOffset = curTextAscent + curTextDescen t; else if (verticalTextAlignment === 3) yOffset = height / 2 - curTextLeadin g * (visibleLines / 2 - 1); else if (verticalTextAlignment === 102) yOffset = curTextDescent + curText Leading; var command, drawCommand, leading; for (command = 0; command < linesCount; command++) { leading = command * curTextLeading; if (yOffset + leading > height - curTextDescent) break; drawCommand = drawCommands[command]; drawing.text$line(drawCommand.text, x + xOffset, y + yOffset + leading, z, horizontalTextAlignment) } } p.text = function() { if (textMode === 5) return; if (arguments.length === 3) text$4(toP5String(arguments[0]), arguments[1], arguments[2], 0); else if (arguments.length === 4) text$4(toP5String(arguments[0]), argument s[1], arguments[2], arguments[3]); else if (arguments.length === 5) text$6(toP5String(arguments[0]), argument s[1], arguments[2], arguments[3], arguments[4], 0); else if (arguments.length === 6) text$6(toP5String(arguments[0]), argument s[1], arguments[2], arguments[3], arguments[4], arguments[5]) }; p.textMode = function(mode) { textMode = mode }; p.loadGlyphs = function(url) { var x, y, cx, cy, nx, ny, d, a, lastCom, lenC, horiz_adv_x, getXY = "[0-9\ \-]+", path; var regex = function(needle, hay) { var i = 0, results = [], latest, regexp = new RegExp(needle, "g"); latest = results[i] = regexp.exec(hay); while (latest) { i++; latest = results[i] = regexp.exec(hay) } return results }; var buildPath = function(d) { var c = regex("[A-Za-z][0-9\\- ]+|Z", d); var beforePathDraw = function() { saveContext(); return drawing.$ensureContext() }; var afterPathDraw = function() { executeContextFill(); executeContextStroke();

restoreContext() }; path = "return {draw:function(){var curContext=beforePathDraw();curConte xt.beginPath();"; x = 0; y = 0; cx = 0; cy = 0; nx = 0; ny = 0; d = 0; a = 0; lastCom = ""; lenC = c.length - 1; for (var j = 0; j < lenC; j++) { var com = c[j][0], xy = regex(getXY, com); switch (com[0]) { case "M": x = parseFloat(xy[0][0]); y = parseFloat(xy[1][0]); path += "curContext.moveTo(" + x + "," + -y + ");"; break; case "L": x = parseFloat(xy[0][0]); y = parseFloat(xy[1][0]); path += "curContext.lineTo(" + x + "," + -y + ");"; break; case "H": x = parseFloat(xy[0][0]); path += "curContext.lineTo(" + x + "," + -y + ");"; break; case "V": y = parseFloat(xy[0][0]); path += "curContext.lineTo(" + x + "," + -y + ");"; break; case "T": nx = parseFloat(xy[0][0]); ny = parseFloat(xy[1][0]); if (lastCom === "Q" || lastCom === "T") { d = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(cy - y, 2)); a = Math.PI + Math.atan2(cx - x, cy - y); cx = x + Math.sin(a) * d; cy = y + Math.cos(a) * d } else { cx = x; cy = y } path += "curContext.quadraticCurveTo(" + cx + "," + -cy + "," + nx + "," + -ny + ");"; x = nx; y = ny; break; case "Q": cx = parseFloat(xy[0][0]); cy = parseFloat(xy[1][0]); nx = parseFloat(xy[2][0]); ny = parseFloat(xy[3][0]); path += "curContext.quadraticCurveTo(" + cx + "," + -cy + "," + nx + "," + -ny + ");";

x = nx; y = ny; break; case "Z": path += "curContext.closePath();"; break } lastCom = com[0] } path += "afterPathDraw();"; path += "curContext.translate(" + horiz_adv_x + ",0);"; path += "}}"; return (new Function("beforePathDraw", "afterPathDraw", path))(beforePat hDraw, afterPathDraw) }; var parseSVGFont = function(svg) { var font = svg.getElementsByTagName("font"); p.glyphTable[url].horiz_adv_x = font[0].getAttribute("horiz-adv-x"); var font_face = svg.getElementsByTagName("font-face")[0]; p.glyphTable[url].units_per_em = parseFloat(font_face.getAttribute("unit s-per-em")); p.glyphTable[url].ascent = parseFloat(font_face.getAttribute("ascent")); p.glyphTable[url].descent = parseFloat(font_face.getAttribute("descent") ); var glyph = svg.getElementsByTagName("glyph"), len = glyph.length; for (var i = 0; i < len; i++) { var unicode = glyph[i].getAttribute("unicode"); var name = glyph[i].getAttribute("glyph-name"); horiz_adv_x = glyph[i].getAttribute("horiz-adv-x"); if (horiz_adv_x === null) horiz_adv_x = p.glyphTable[url].horiz_adv_x; d = glyph[i].getAttribute("d"); if (d !== undef) { path = buildPath(d); p.glyphTable[url][name] = { name: name, unicode: unicode, horiz_adv_x: horiz_adv_x, draw: path.draw } } } }; var loadXML = function() { var xmlDoc; try { xmlDoc = document.implementation.createDocument("", "", null) } catch(e_fx_op) { Processing.debug(e_fx_op.message); return } try { xmlDoc.async = false; xmlDoc.load(url); parseSVGFont(xmlDoc.getElementsByTagName("svg")[0]) } catch(e_sf_ch) { Processing.debug(e_sf_ch); try { var xmlhttp = new window.XMLHttpRequest; xmlhttp.open("GET", url, false);

xmlhttp.send(null); parseSVGFont(xmlhttp.responseXML.documentElement) } catch(e) { Processing.debug(e_sf_ch) } } }; p.glyphTable[url] = {}; loadXML(url); return p.glyphTable[url] }; p.param = function(name) { var attributeName = "data-processing-" + name; if (curElement.hasAttribute(attributeName)) return curElement.getAttribute (attributeName); for (var i = 0, len = curElement.childNodes.length; i < len; ++i) { var item = curElement.childNodes.item(i); if (item.nodeType !== 1 || item.tagName.toLowerCase() !== "param") conti nue; if (item.getAttribute("name") === name) return item.getAttribute("value" ) } if (curSketch.params.hasOwnProperty(name)) return curSketch.params[name]; return null }; function wireDimensionalFunctions(mode) { if (mode === "3D") drawing = new Drawing3D; else if (mode === "2D") drawing = new Drawing2D; else drawing = new DrawingPre; for (var i in DrawingPre.prototype) if (DrawingPre.prototype.hasOwnPropert y(i) && i.indexOf("$") < 0) p[i] = drawing[i]; drawing.$init() } function createDrawingPreFunction(name) { return function() { wireDimensionalFunctions("2D"); return drawing[name].apply(this, arguments) } } DrawingPre.prototype.translate = createDrawingPreFunction("translate"); DrawingPre.prototype.transform = createDrawingPreFunction("transform"); DrawingPre.prototype.scale = createDrawingPreFunction("scale"); DrawingPre.prototype.pushMatrix = createDrawingPreFunction("pushMatrix"); DrawingPre.prototype.popMatrix = createDrawingPreFunction("popMatrix"); DrawingPre.prototype.resetMatrix = createDrawingPreFunction("resetMatrix"); DrawingPre.prototype.applyMatrix = createDrawingPreFunction("applyMatrix"); DrawingPre.prototype.rotate = createDrawingPreFunction("rotate"); DrawingPre.prototype.rotateZ = createDrawingPreFunction("rotateZ"); DrawingPre.prototype.shearX = createDrawingPreFunction("shearX"); DrawingPre.prototype.shearY = createDrawingPreFunction("shearY"); DrawingPre.prototype.redraw = createDrawingPreFunction("redraw"); DrawingPre.prototype.toImageData = createDrawingPreFunction("toImageData"); DrawingPre.prototype.ambientLight = createDrawingPreFunction("ambientLight") ; DrawingPre.prototype.directionalLight = createDrawingPreFunction("directiona lLight"); DrawingPre.prototype.lightFalloff = createDrawingPreFunction("lightFalloff") ; DrawingPre.prototype.lightSpecular = createDrawingPreFunction("lightSpecular

"); DrawingPre.prototype.pointLight = createDrawingPreFunction("pointLight"); DrawingPre.prototype.noLights = createDrawingPreFunction("noLights"); DrawingPre.prototype.spotLight = createDrawingPreFunction("spotLight"); DrawingPre.prototype.beginCamera = createDrawingPreFunction("beginCamera"); DrawingPre.prototype.endCamera = createDrawingPreFunction("endCamera"); DrawingPre.prototype.frustum = createDrawingPreFunction("frustum"); DrawingPre.prototype.box = createDrawingPreFunction("box"); DrawingPre.prototype.sphere = createDrawingPreFunction("sphere"); DrawingPre.prototype.ambient = createDrawingPreFunction("ambient"); DrawingPre.prototype.emissive = createDrawingPreFunction("emissive"); DrawingPre.prototype.shininess = createDrawingPreFunction("shininess"); DrawingPre.prototype.specular = createDrawingPreFunction("specular"); DrawingPre.prototype.fill = createDrawingPreFunction("fill"); DrawingPre.prototype.stroke = createDrawingPreFunction("stroke"); DrawingPre.prototype.strokeWeight = createDrawingPreFunction("strokeWeight") ; DrawingPre.prototype.smooth = createDrawingPreFunction("smooth"); DrawingPre.prototype.noSmooth = createDrawingPreFunction("noSmooth"); DrawingPre.prototype.point = createDrawingPreFunction("point"); DrawingPre.prototype.vertex = createDrawingPreFunction("vertex"); DrawingPre.prototype.endShape = createDrawingPreFunction("endShape"); DrawingPre.prototype.bezierVertex = createDrawingPreFunction("bezierVertex") ; DrawingPre.prototype.curveVertex = createDrawingPreFunction("curveVertex"); DrawingPre.prototype.curve = createDrawingPreFunction("curve"); DrawingPre.prototype.line = createDrawingPreFunction("line"); DrawingPre.prototype.bezier = createDrawingPreFunction("bezier"); DrawingPre.prototype.rect = createDrawingPreFunction("rect"); DrawingPre.prototype.ellipse = createDrawingPreFunction("ellipse"); DrawingPre.prototype.background = createDrawingPreFunction("background"); DrawingPre.prototype.image = createDrawingPreFunction("image"); DrawingPre.prototype.textWidth = createDrawingPreFunction("textWidth"); DrawingPre.prototype.text$line = createDrawingPreFunction("text$line"); DrawingPre.prototype.$ensureContext = createDrawingPreFunction("$ensureConte xt"); DrawingPre.prototype.$newPMatrix = createDrawingPreFunction("$newPMatrix"); DrawingPre.prototype.size = function(aWidth, aHeight, aMode) { wireDimensionalFunctions(aMode === 2 ? "3D" : "2D"); p.size(aWidth, aHeight, aMode) }; DrawingPre.prototype.$init = nop; Drawing2D.prototype.$init = function() { p.size(p.width, p.height); curContext.lineCap = "round"; p.noSmooth(); p.disableContextMenu() }; Drawing3D.prototype.$init = function() { p.use3DContext = true; p.disableContextMenu() }; DrawingShared.prototype.$ensureContext = function() { return curContext }; function calculateOffset(curElement, event) { var element = curElement, offsetX = 0, offsetY = 0;

p.pmouseX = p.mouseX; p.pmouseY = p.mouseY; if (element.offsetParent) { do { offsetX += element.offsetLeft; offsetY += element.offsetTop } while ( !! (element = element.offsetParent)) } element = curElement; do { offsetX -= element.scrollLeft || 0; offsetY -= element.scrollTop || 0 } while ( !! (element = element.parentNode)); offsetX += stylePaddingLeft; offsetY += stylePaddingTop; offsetX += styleBorderLeft; offsetY += styleBorderTop; offsetX += window.pageXOffset; offsetY += window.pageYOffset; return { "X": offsetX, "Y": offsetY } } function updateMousePosition(curElement, event) { var offset = calculateOffset(curElement, event); p.mouseX = event.pageX - offset.X; p.mouseY = event.pageY - offset.Y } function addTouchEventOffset(t) { var offset = calculateOffset(t.changedTouches[0].target, t.changedTouches[ 0]), i; for (i = 0; i < t.touches.length; i++) { var touch = t.touches[i]; touch.offsetX = touch.pageX - offset.X; touch.offsetY = touch.pageY - offset.Y } for (i = 0; i < t.targetTouches.length; i++) { var targetTouch = t.targetTouches[i]; targetTouch.offsetX = targetTouch.pageX - offset.X; targetTouch.offsetY = targetTouch.pageY - offset.Y } for (i = 0; i < t.changedTouches.length; i++) { var changedTouch = t.changedTouches[i]; changedTouch.offsetX = changedTouch.pageX - offset.X; changedTouch.offsetY = changedTouch.pageY - offset.Y } return t } attachEventHandler(curElement, "touchstart", function(t) { curElement.setAttribute("style", "-webkit-user-select: none"); curElement.setAttribute("onclick", "void(0)"); curElement.setAttribute("style", "-webkit-tap-highlight-color:rgba(0,0,0,0 )"); for (var i = 0, ehl = eventHandlers.length; i < ehl; i++) { var type = eventHandlers[i].type; if (type === "mouseout" || type === "mousemove" || type === "mousedown" || type === "mouseup" || type === "DOMMouseScroll" || type === "mousewheel" || t ype === "touchstart") detachEventHandler(eventHandlers[i])

} if (p.touchStart !== undef || p.touchMove !== undef || p.touchEnd !== unde f || p.touchCancel !== undef) { attachEventHandler(curElement, "touchstart", function(t) { if (p.touchStart !== undef) { t = addTouchEventOffset(t); p.touchStart(t) } }); attachEventHandler(curElement, "touchmove", function(t) { if (p.touchMove !== undef) { t.preventDefault(); t = addTouchEventOffset(t); p.touchMove(t) } }); attachEventHandler(curElement, "touchend", function(t) { if (p.touchEnd !== undef) { t = addTouchEventOffset(t); p.touchEnd(t) } }); attachEventHandler(curElement, "touchcancel", function(t) { if (p.touchCancel !== undef) { t = addTouchEventOffset(t); p.touchCancel(t) } }) } else { attachEventHandler(curElement, "touchstart", function(e) { updateMousePosition(curElement, e.touches[0]); p.__mousePressed = true; p.mouseDragging = false; p.mouseButton = 37; if (typeof p.mousePressed === "function") p.mousePressed() }); attachEventHandler(curElement, "touchmove", function(e) { e.preventDefault(); updateMousePosition(curElement, e.touches[0]); if (typeof p.mouseMoved === "function" && !p.__mousePressed) p.mouseMo ved(); if (typeof p.mouseDragged === "function" && p.__mousePressed) { p.mouseDragged(); p.mouseDragging = true } }); attachEventHandler(curElement, "touchend", function(e) { p.__mousePressed = false; if (typeof p.mouseClicked === "function" && !p.mouseDragging) p.mouseC licked(); if (typeof p.mouseReleased === "function") p.mouseReleased() }) } curElement.dispatchEvent(t) }); (function() { var enabled = true, contextMenu = function(e) { e.preventDefault(); e.stopPropagation()

}; p.disableContextMenu = function() { if (!enabled) return; attachEventHandler(curElement, "contextmenu", contextMenu); enabled = false }; p.enableContextMenu = function() { if (enabled) return; detachEventHandler({ elem: curElement, type: "contextmenu", fn: contextMenu }); enabled = true } })(); attachEventHandler(curElement, "mousemove", function(e) { updateMousePosition(curElement, e); if (typeof p.mouseMoved === "function" && !p.__mousePressed) p.mouseMoved( ); if (typeof p.mouseDragged === "function" && p.__mousePressed) { p.mouseDragged(); p.mouseDragging = true } }); attachEventHandler(curElement, "mouseout", function(e) { if (typeof p.mouseOut === "function") p.mouseOut() }); attachEventHandler(curElement, "mouseover", function(e) { updateMousePosition(curElement, e); if (typeof p.mouseOver === "function") p.mouseOver() }); curElement.onmousedown = function() { curElement.focus(); return false }; attachEventHandler(curElement, "mousedown", function(e) { p.__mousePressed = true; p.mouseDragging = false; switch (e.which) { case 1: p.mouseButton = 37; break; case 2: p.mouseButton = 3; break; case 3: p.mouseButton = 39; break } if (typeof p.mousePressed === "function") p.mousePressed() }); attachEventHandler(curElement, "mouseup", function(e) { p.__mousePressed = false; if (typeof p.mouseClicked === "function" && !p.mouseDragging) p.mouseClick ed(); if (typeof p.mouseReleased === "function") p.mouseReleased() }); var mouseWheelHandler = function(e) { var delta = 0;

if (e.wheelDelta) { delta = e.wheelDelta / 120; if (window.opera) delta = -delta } else if (e.detail) delta = -e.detail / 3; p.mouseScroll = delta; if (delta && typeof p.mouseScrolled === "function") p.mouseScrolled() }; attachEventHandler(document, "DOMMouseScroll", mouseWheelHandler); attachEventHandler(document, "mousewheel", mouseWheelHandler); if (!curElement.getAttribute("tabindex")) curElement.setAttribute("tabindex" , 0); function getKeyCode(e) { var code = e.which || e.keyCode; switch (code) { case 13: return 10; case 91: case 93: case 224: return 157; case 57392: return 17; case 46: return 127; case 45: return 155 } return code } function getKeyChar(e) { var c = e.which || e.keyCode; var anyShiftPressed = e.shiftKey || e.ctrlKey || e.altKey || e.metaKey; switch (c) { case 13: c = anyShiftPressed ? 13 : 10; break; case 8: c = anyShiftPressed ? 127 : 8; break } return new Char(c) } function suppressKeyEvent(e) { if (typeof e.preventDefault === "function") e.preventDefault(); else if (typeof e.stopPropagation === "function") e.stopPropagation(); return false } function updateKeyPressed() { var ch; for (ch in pressedKeysMap) if (pressedKeysMap.hasOwnProperty(ch)) { p.__keyPressed = true; return } p.__keyPressed = false } function resetKeyPressed() { p.__keyPressed = false; pressedKeysMap = []; lastPressedKeyCode = null

} function simulateKeyTyped(code, c) { pressedKeysMap[code] = c; lastPressedKeyCode = null; p.key = c; p.keyCode = code; p.keyPressed(); p.keyCode = 0; p.keyTyped(); updateKeyPressed() } function handleKeydown(e) { var code = getKeyCode(e); if (code === 127) { simulateKeyTyped(code, new Char(127)); return } if (codedKeys.indexOf(code) < 0) { lastPressedKeyCode = code; return } var c = new Char(65535); p.key = c; p.keyCode = code; pressedKeysMap[code] = c; p.keyPressed(); lastPressedKeyCode = null; updateKeyPressed(); return suppressKeyEvent(e) } function handleKeypress(e) { if (lastPressedKeyCode === null) return; var code = lastPressedKeyCode, c = getKeyChar(e); simulateKeyTyped(code, c); return suppressKeyEvent(e) } function handleKeyup(e) { var code = getKeyCode(e), c = pressedKeysMap[code]; if (c === undef) return; p.key = c; p.keyCode = code; p.keyReleased(); delete pressedKeysMap[code]; updateKeyPressed() } if (!pgraphicsMode) { if (aCode instanceof Processing.Sketch) curSketch = aCode; else if (typeof aCode === "function") curSketch = new Processing.Sketch(aC ode); else if (!aCode) curSketch = new Processing.Sketch(function() {}); else curSketch = Processing.compile(aCode); p.externals.sketch = curSketch; wireDimensionalFunctions(); curElement.onfocus = function() { p.focused = true }; curElement.onblur = function() { p.focused = false;

if (!curSketch.options.globalKeyEvents) resetKeyPressed() }; if (curSketch.options.pauseOnBlur) { attachEventHandler(window, "focus", function() { if (doLoop) p.loop() }); attachEventHandler(window, "blur", function() { if (doLoop && loopStarted) { p.noLoop(); doLoop = true } resetKeyPressed() }) } var keyTrigger = curSketch.options.globalKeyEvents ? window : curElement; attachEventHandler(keyTrigger, "keydown", handleKeydown); attachEventHandler(keyTrigger, "keypress", handleKeypress); attachEventHandler(keyTrigger, "keyup", handleKeyup); for (var i in Processing.lib) if (Processing.lib.hasOwnProperty(i)) if (Pr ocessing.lib[i].hasOwnProperty("attach")) Processing.lib[i].attach(p); else if (Processing.lib[i] instanceof Function) Processing.lib[i].call(thi s); var retryInterval = 100; var executeSketch = function(processing) { if (! (curSketch.imageCache.pending || PFont.preloading.pending(retryInt erval))) { if (window.opera) { var link, element, operaCache = curSketch.imageCache.operaCache; for (link in operaCache) if (operaCache.hasOwnProperty(link)) { element = operaCache[link]; if (element !== null) document.body.removeChild(element); delete operaCache[link] } } curSketch.attach(processing, defaultScope); curSketch.onLoad(processing); if (processing.setup) { processing.setup(); processing.resetMatrix(); curSketch.onSetup() } resetContext(); if (processing.draw) if (!doLoop) processing.redraw(); else processing.loop() } else window.setTimeout(function() { executeSketch(processing) }, retryInterval) }; addInstance(this); executeSketch(p) } else { curSketch = new Processing.Sketch; wireDimensionalFunctions(); p.size = function(w, h, render) { if (render && render === 2) wireDimensionalFunctions("3D"); else wireDimensionalFunctions("2D"); p.size(w, h, render) } }

}; Processing.debug = debug; Processing.prototype = defaultScope; function getGlobalMembers() { var names = ["abs", "acos", "alpha", "ambient", "ambientLight", "append", "applyMatrix", "arc", "arrayCopy", "asin", "atan", "atan2", "background", "beginCamera", "beginDraw", "beginShape", "bezier", "bezierDetail", "bezierPoint ", "bezierTangent", "bezierVertex", "binary", "blend", "blendColor", "blit_resiz e", "blue", "box", "breakShape", "brightness", "camera", "ceil", "Character", "c olor", "colorMode", "concat", "constrain", "copy", "cos", "createFont", "createG raphics", "createImage", "cursor", "curve", "curveDetail", "curvePoint", "curveT angent", "curveTightness", "curveVertex", "day", "degrees", "directionalLight", "disableContextMenu", "dist", "draw", "ellipse", "ellipseMode", "emissive" , "enableContextMenu", "endCamera", "endDraw", "endShape", "exit", "exp", "expan d", "externals", "fill", "filter", "floor", "focused", "frameCount", "frameRate" , "frustum", "get", "glyphLook", "glyphTable", "green", "height", "hex", "hint", "hour", "hue", "image", "imageMode", "intersect", "join", "key", "keyCode", "ke yPressed", "keyReleased", "keyTyped", "lerp", "lerpColor", "lightFalloff", "ligh ts", "lightSpecular", "line", "link", "loadBytes", "loadFont", "loadGlyphs", "loadImage", "loadPixels", "loadShape", "loadXML", "loadStrings", "log", " loop", "mag", "map", "match", "matchAll", "max", "millis", "min", "minute", "mix ", "modelX", "modelY", "modelZ", "modes", "month", "mouseButton", "mouseClicked" , "mouseDragged", "mouseMoved", "mouseOut", "mouseOver", "mousePressed", "mouseR eleased", "mouseScroll", "mouseScrolled", "mouseX", "mouseY", "name", "nf", "nfc ", "nfp", "nfs", "noCursor", "noFill", "noise", "noiseDetail", "noiseSeed", "noL ights", "noLoop", "norm", "normal", "noSmooth", "noStroke", "noTint", "ortho", "param", "parseBoolean", "parseByte", "parseChar", "parseFloat", "parseInt ", "peg", "perspective", "PImage", "pixels", "PMatrix2D", "PMatrix3D", "PMatrixS tack", "pmouseX", "pmouseY", "point", "pointLight", "popMatrix", "popStyle", "po w", "print", "printCamera", "println", "printMatrix", "printProjection", "PShape ", "PShapeSVG", "pushMatrix", "pushStyle", "quad", "radians", "random", "Random" , "randomSeed", "rect", "rectMode", "red", "redraw", "requestImage", "resetMatri x", "reverse", "rotate", "rotateX", "rotateY", "rotateZ", "round", "saturation", "save", "saveFrame", "saveStrings", "scale", "screenX", "screenY", "screen Z", "second", "set", "setup", "shape", "shapeMode", "shared", "shearX", "shearY" , "shininess", "shorten", "sin", "size", "smooth", "sort", "specular", "sphere", "sphereDetail", "splice", "split", "splitTokens", "spotLight", "sq", "sqrt", "s tatus", "str", "stroke", "strokeCap", "strokeJoin", "strokeWeight", "subset", "t an", "text", "textAlign", "textAscent", "textDescent", "textFont", "textLeading" , "textMode", "textSize", "texture", "textureMode", "textWidth", "tint", "toImag eData", "touchCancel", "touchEnd", "touchMove", "touchStart", "translate", "transf orm", "triangle", "trim", "unbinary", "unhex", "updatePixels", "use3DContext", " vertex", "width", "XMLElement", "XML", "year", "__contains", "__equals", "__equa lsIgnoreCase", "__frameRate", "__hashCode", "__int_cast", "__instanceof", "__key Pressed", "__mousePressed", "__printStackTrace", "__replace", "__replaceAll", "_ _replaceFirst", "__toCharArray", "__split", "__codePointAt", "__startsWith", "__ endsWith", "__matches"]; var members = {}; var i, l; for (i = 0, l = names.length; i < l; ++i) members[names[i]] = null; for (var lib in Processing.lib) if (Processing.lib.hasOwnProperty(lib)) if ( Processing.lib[lib].exports) { var exportedNames = Processing.lib[lib].exports; for (i = 0, l = exportedNames.length; i < l; ++i) members[exportedNames[i] ] = null } return members }

function parseProcessing(code) { var globalMembers = getGlobalMembers(); function splitToAtoms(code) { var atoms = []; var items = code.split(/([\{\[\(\)\]\}])/); var result = items[0]; var stack = []; for (var i = 1; i < items.length; i += 2) { var item = items[i]; if (item === "[" || item === "{" || item === "(") { stack.push(result); result = item } else if (item === "]" || item === "}" || item === ")") { var kind = item === "}" ? "A" : item === ")" ? "B" : "C"; var index = atoms.length; atoms.push(result + item); result = stack.pop() + '"' + kind + (index + 1) + '"' } result += items[i + 1] } atoms.unshift(result); return atoms } function injectStrings(code, strings) { return code.replace(/'(\d+)'/g, function(all, index) { var val = strings[index]; if (val.charAt(0) === "/") return val; return /^'((?:[^'\\\n])|(?:\\.[0-9A-Fa-f]*))'$/.test(val) ? "(new $p.Cha racter(" + val + "))" : val }) } function trimSpaces(string) { var m1 = /^\s*/.exec(string), result; if (m1[0].length === string.length) result = { left: m1[0], middle: "", right: "" }; else { var m2 = /\s*$/.exec(string); result = { left: m1[0], middle: string.substring(m1[0].length, m2.index), right: m2[0] } } result.untrim = function(t) { return this.left + t + this.right }; return result } function trim(string) { return string.replace(/^\s+/, "").replace(/\s+$/, "") } function appendToLookupTable(table, array) { for (var i = 0, l = array.length; i < l; ++i) table[array[i]] = null; return table }

function isLookupTableEmpty(table) { for (var i in table) if (table.hasOwnProperty(i)) return false; return true } function getAtomIndex(templ) { return templ.substring(2, templ.length - 1) } var codeWoExtraCr = code.replace(/\r\n?|\n\r/g, "\n"); var strings = []; var codeWoStrings = codeWoExtraCr.replace(/("(?:[^"\\\n]|\\.)*")|('(?:[^'\\\ n]|\\.)*')|(([\[\(=|&!\^:?]\s*)(\/(?![*\/])(?:[^\/\\\n]|\\.)*\/[gim]*)\b)|(\/\/[ ^\n]*\n)|(\/\*(?:(?!\*\/)(?:.|\n))*\*\/)/g, function(all, quoted, aposed, regexC tx, prefix, regex, singleComment, comment) { var index; if (quoted || aposed) { index = strings.length; strings.push(all); return "'" + index + "'" } if (regexCtx) { index = strings.length; strings.push(regex); return prefix + "'" + index + "'" } return comment !== "" ? " " : "\n" }); codeWoStrings = codeWoStrings.replace(/__x([0-9A-F]{4})/g, function(all, hex Code) { return "__x005F_x" + hexCode }); codeWoStrings = codeWoStrings.replace(/\$/g, "__x0024"); var genericsWereRemoved; var codeWoGenerics = codeWoStrings; var replaceFunc = function(all, before, types, after) { if ( !! before || !!after) return all; genericsWereRemoved = true; return "" }; do { genericsWereRemoved = false; codeWoGenerics = codeWoGenerics.replace(/([<]?)<\s*((?:\?|[A-Za-z_$][\w$]* \b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][ \w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?(?:\s*,\s*(?:\?|[A-Za-z_$][\w$]*\b(?:\s* \.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b( ?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?)*)\s*>([=]?)/g, replaceFunc) } while (genericsWereRemoved); var atoms = splitToAtoms(codeWoGenerics); var replaceContext; var declaredClasses = {}, currentClassId, classIdSeed = 0; function addAtom(text, type) { var lastIndex = atoms.length; atoms.push(text); return '"' + type + lastIndex + '"' } function generateClassId() { return "class" + ++classIdSeed } function appendClass(class_, classId, scopeId) {

class_.classId = classId; class_.scopeId = scopeId; declaredClasses[classId] = class_ } var transformClassBody, transformInterfaceBody, transformStatementsBlock, tr ansformStatements, transformMain, transformExpression; var classesRegex = /\b((?:(?:public|private|final|protected|static|abstract) \s+)*)(class|interface)\s+([A-Za-z_$][\w$]*\b)(\s+extends\s+[A-Za-z_$][\w$]*\b(? :\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\ w$]*\b)*\b)*)?(\s+implements\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)* (?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?\s*("A\d+")/g; var methodsRegex = /\b((?:(?:public|private|final|protected|static|abstract| synchronized)\s+)*)((?!(?:else|new|return|throw|function|public|private|protecte d)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z _$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$] *\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+"|; )/g; var fieldTest = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?: else|new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s* "C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*(?:"C\d+"\s*)*([=,]|$)/; var cstrsRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s +)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Zaz_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\ s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+")/g; var attrAndTypeRegex = /^((?:(?:public|private|final|protected|static)\s+)*) ((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\ s*"C\d+")*)\s*/; var functionsRegex = /\bfunction(?:\s+([A-Za-z_$][\w$]*))?\s*("B\d+")\s*("A\ d+")/g; function extractClassesAndMethods(code) { var s = code; s = s.replace(classesRegex, function(all) { return addAtom(all, "E") }); s = s.replace(methodsRegex, function(all) { return addAtom(all, "D") }); s = s.replace(functionsRegex, function(all) { return addAtom(all, "H") }); return s } function extractConstructors(code, className) { var result = code.replace(cstrsRegex, function(all, attr, name, params, th rows_, body) { if (name !== className) return all; return addAtom(all, "G") }); return result } function AstParam(name) { this.name = name } AstParam.prototype.toString = function() { return this.name }; function AstParams(params, methodArgsParam) { this.params = params;

this.methodArgsParam = methodArgsParam } AstParams.prototype.getNames = function() { var names = []; for (var i = 0, l = this.params.length; i < l; ++i) names.push(this.params [i].name); return names }; AstParams.prototype.prependMethodArgs = function(body) { if (!this.methodArgsParam) return body; return "{\nvar " + this.methodArgsParam.name + " = Array.prototype.slice.c all(arguments, " + this.params.length + ");\n" + body.substring(1) }; AstParams.prototype.toString = function() { if (this.params.length === 0) return "()"; var result = "("; for (var i = 0, l = this.params.length; i < l; ++i) result += this.params[ i] + ", "; return result.substring(0, result.length - 2) + ")" }; function transformParams(params) { var paramsWoPars = trim(params.substring(1, params.length - 1)); var result = [], methodArgsParam = null; if (paramsWoPars !== "") { var paramList = paramsWoPars.split(","); for (var i = 0; i < paramList.length; ++i) { var param = /\b([A-Za-z_$][\w$]*\b)(\s*"[ABC][\d]*")*\s*$/.exec(paramL ist[i]); if (i === paramList.length - 1 && paramList[i].indexOf("...") >= 0) { methodArgsParam = new AstParam(param[1]); break } result.push(new AstParam(param[1])) } } return new AstParams(result, methodArgsParam) } function preExpressionTransform(expr) { var s = expr; s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*) (?:\s*"C\d+")+\s*("A\d+")/g, function(all, type, init) { return init }); s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*) (?:\s*"B\d+")\s*("A\d+")/g, function(all, type, init) { return addAtom(all, "F") }); s = s.replace(functionsRegex, function(all) { return addAtom(all, "H") }); s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*) \s*("C\d+"(?:\s*"C\d+")*)/g, function(all, type, index) { var args = index.replace(/"C(\d+)"/g, function(all, j) { return atoms[j] }).replace(/\[\s*\]/g, "[null]").replace(/\s*\]\s*\[\s*/g, ", "); var arrayInitializer = "{" + args.substring(1, args.length - 1) + "}"; var createArrayArgs = "('" + type + "', " + addAtom(arrayInitializer, "A ") + ")";

return "$p.createJavaArray" + addAtom(createArrayArgs, "B") }); s = s.replace(/(\.\s*length)\s*"B\d+"/g, "$1"); s = s.replace(/#([0-9A-Fa-f]{6})\b/g, function(all, digits) { return "0xFF" + digits }); s = s.replace(/"B(\d+)"(\s*(?:[\w$']|"B))/g, function(all, index, next) { var atom = atoms[index]; if (!/^\(\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\s*(?:"C\d+ "\s*)*\)$/.test(atom)) return all; if (/^\(\s*int\s*\)$/.test(atom)) return "(int)" + next; var indexParts = atom.split(/"C(\d+)"/g); if (indexParts.length > 1) if (!/^\[\s*\]$/.test(atoms[indexParts[1]])) return all; return "" + next }); s = s.replace(/\(int\)([^,\]\)\}\?\:\*\+\-\/\^\|\%\&\~<\>\=]+)/g, function (all, arg) { var trimmed = trimSpaces(arg); return trimmed.untrim("__int_cast(" + trimmed.middle + ")") }); s = s.replace(/\bsuper(\s*"B\d+")/g, "$$superCstr$1").replace(/\bsuper(\s* \.)/g, "$$super$1"); s = s.replace(/\b0+((\d*)(?:\.[\d*])?(?:[eE][\-\+]?\d+)?[fF]?)\b/, functio n(all, numberWo0, intPart) { if (numberWo0 === intPart) return all; return intPart === "" ? "0" + numberWo0 : numberWo0 }); s = s.replace(/\b(\.?\d+\.?)[fF]\b/g, "$1"); s = s.replace(/([^\s])%([^=\s])/g, "$1 % $2"); s = s.replace(/\b(frameRate|keyPressed|mousePressed)\b(?!\s*"B)/g, "__$1") ; s = s.replace(/\b(boolean|byte|char|float|int)\s*"B/g, function(all, name) { return "parse" + name.substring(0, 1).toUpperCase() + name.substring(1) + '"B' }); s = s.replace(/\bpixels\b\s*(("C(\d+)")|\.length)?(\s*=(?!=)([^,\]\)\}]+)) ?/g, function(all, indexOrLength, index, atomIndex, equalsPart, rightSide) { if (index) { var atom = atoms[atomIndex]; if (equalsPart) return "pixels.setPixel" + addAtom("(" + atom.substrin g(1, atom.length - 1) + "," + rightSide + ")", "B"); return "pixels.getPixel" + addAtom("(" + atom.substring(1, atom.length - 1) + ")", "B") } if (indexOrLength) return "pixels.getLength" + addAtom("()", "B"); if (equalsPart) return "pixels.set" + addAtom("(" + rightSide + ")", "B" ); return "pixels.toArray" + addAtom("()", "B") }); var repeatJavaReplacement; function replacePrototypeMethods(all, subject, method, atomIndex) { var atom = atoms[atomIndex]; repeatJavaReplacement = true; var trimmed = trimSpaces(atom.substring(1, atom.length - 1)); return "__" + method + (trimmed.middle === "" ? addAtom("(" + subject.re place(/\.\s*$/, "") + ")", "B") : addAtom("(" + subject.replace(/\.\s*$/, "") + "," + trimmed.middle + ")", "B"))

} do { repeatJavaReplacement = false; s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*\.\s*(?: [A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*\.\s*)*)(replace|replaceAll|replaceFirst|con tains|equals|equalsIgnoreCase|hashCode|toCharArray|printStackTrace|split|startsW ith|endsWith|codePointAt|matches)\s*"B(\d+)"/g, replacePrototypeMethods) } while (repeatJavaReplacement); function replaceInstanceof(all, subject, type) { repeatJavaReplacement = true; return "__instanceof" + addAtom("(" + subject + ", " + type + ")", "B") } do { repeatJavaReplacement = false; s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*(?:\.\s* [A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*)*)instanceof\s+([A-Za-z_$][\w$]*\s*(?:\.\s* [A-Za-z_$][\w$]*)*)/g, replaceInstanceof) } while (repeatJavaReplacement); s = s.replace(/\bthis(\s*"B\d+")/g, "$$constr$1"); return s } function AstInlineClass(baseInterfaceName, body) { this.baseInterfaceName = baseInterfaceName; this.body = body; body.owner = this } AstInlineClass.prototype.toString = function() { return "new (" + this.body + ")" }; function transformInlineClass(class_) { var m = (new RegExp(/\bnew\s*([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*) *)\s*"B\d+"\s*"A(\d+)"/)).exec(class_); var oldClassId = currentClassId, newClassId = generateClassId(); currentClassId = newClassId; var uniqueClassName = m[1] + "$" + newClassId; var inlineClass = new AstInlineClass(uniqueClassName, transformClassBody(a toms[m[2]], uniqueClassName, "", "implements " + m[1])); appendClass(inlineClass, newClassId, oldClassId); currentClassId = oldClassId; return inlineClass } function AstFunction(name, params, body) { this.name = name; this.params = params; this.body = body } AstFunction.prototype.toString = function() { var oldContext = replaceContext; var names = appendToLookupTable({ "this": null }, this.params.getNames()); replaceContext = function(subject) { return names.hasOwnProperty(subject.name) ? subject.name : oldContext(su bject) };

var result = "function"; if (this.name) result += " " + this.name; var body = this.params.prependMethodArgs(this.body.toString()); result += this.params + " " + body; replaceContext = oldContext; return result }; function transformFunction(class_) { var m = (new RegExp(/\b([A-Za-z_$][\w$]*)\s*"B(\d+)"\s*"A(\d+)"/)).exec(cl ass_); return new AstFunction(m[1] !== "function" ? m[1] : null, transformParams( atoms[m[2]]), transformStatementsBlock(atoms[m[3]])) } function AstInlineObject(members) { this.members = members } AstInlineObject.prototype.toString = function() { var oldContext = replaceContext; replaceContext = function(subject) { return subject.name === "this" ? "this" : oldContext(subject) }; var result = ""; for (var i = 0, l = this.members.length; i < l; ++i) { if (this.members[i].label) result += this.members[i].label + ": "; result += this.members[i].value.toString() + ", " } replaceContext = oldContext; return result.substring(0, result.length - 2) }; function transformInlineObject(obj) { var members = obj.split(","); for (var i = 0; i < members.length; ++i) { var label = members[i].indexOf(":"); if (label < 0) members[i] = { value: transformExpression(members[i]) }; else members[i] = { label: trim(members[i].substring(0, label)), value: transformExpression(trim(members[i].substring(label + 1))) } } return new AstInlineObject(members) } function expandExpression(expr) { if (expr.charAt(0) === "(" || expr.charAt(0) === "[") return expr.charAt(0 ) + expandExpression(expr.substring(1, expr.length - 1)) + expr.charAt(expr.leng th - 1); if (expr.charAt(0) === "{") { if (/^\{\s*(?:[A-Za-z_$][\w$]*|'\d+')\s*:/.test(expr)) return "{" + addA tom(expr.substring(1, expr.length - 1), "I") + "}"; return "[" + expandExpression(expr.substring(1, expr.length - 1)) + "]" } var trimmed = trimSpaces(expr); var result = preExpressionTransform(trimmed.middle); result = result.replace(/"[ABC](\d+)"/g, function(all, index) { return expandExpression(atoms[index]) });

return trimmed.untrim(result) } function replaceContextInVars(expr) { return expr.replace(/(\.\s*)?((?:\b[A-Za-z_]|\$)[\w$]*)(\s*\.\s*([A-Za-z_$ ][\w$]*)(\s*\()?)?/g, function(all, memberAccessSign, identifier, suffix, subMem ber, callSign) { if (memberAccessSign) return all; var subject = { name: identifier, member: subMember, callSign: !!callSign }; return replaceContext(subject) + (suffix === undef ? "" : suffix) }) } function AstExpression(expr, transforms) { this.expr = expr; this.transforms = transforms } AstExpression.prototype.toString = function() { var transforms = this.transforms; var expr = replaceContextInVars(this.expr); return expr.replace(/"!(\d+)"/g, function(all, index) { return transforms[index].toString() }) }; transformExpression = function(expr) { var transforms = []; var s = expandExpression(expr); s = s.replace(/"H(\d+)"/g, function(all, index) { transforms.push(transformFunction(atoms[index])); return '"!' + (transforms.length - 1) + '"' }); s = s.replace(/"F(\d+)"/g, function(all, index) { transforms.push(transformInlineClass(atoms[index])); return '"!' + (transforms.length - 1) + '"' }); s = s.replace(/"I(\d+)"/g, function(all, index) { transforms.push(transformInlineObject(atoms[index])); return '"!' + (transforms.length - 1) + '"' }); return new AstExpression(s, transforms) }; function AstVarDefinition(name, value, isDefault) { this.name = name; this.value = value; this.isDefault = isDefault } AstVarDefinition.prototype.toString = function() { return this.name + " = " + this.value }; function transformVarDefinition(def, defaultTypeValue) { var eqIndex = def.indexOf("="); var name, value, isDefault; if (eqIndex < 0) { name = def; value = defaultTypeValue; isDefault = true

} else { name = def.substring(0, eqIndex); value = transformExpression(def.substring(eqIndex + 1)); isDefault = false } return new AstVarDefinition(trim(name.replace(/(\s*"C\d+")+/g, "")), value , isDefault) } function getDefaultValueForType(type) { if (type === "int" || type === "float") return "0"; if (type === "boolean") return "false"; if (type === "color") return "0x00000000"; return "null" } function AstVar(definitions, varType) { this.definitions = definitions; this.varType = varType } AstVar.prototype.getNames = function() { var names = []; for (var i = 0, l = this.definitions.length; i < l; ++i) names.push(this.d efinitions[i].name); return names }; AstVar.prototype.toString = function() { return "var " + this.definitions.join(",") }; function AstStatement(expression) { this.expression = expression } AstStatement.prototype.toString = function() { return this.expression.toString() }; function transformStatement(statement) { if (fieldTest.test(statement)) { var attrAndType = attrAndTypeRegex.exec(statement); var definitions = statement.substring(attrAndType[0].length).split(","); var defaultTypeValue = getDefaultValueForType(attrAndType[2]); for (var i = 0; i < definitions.length; ++i) definitions[i] = transformV arDefinition(definitions[i], defaultTypeValue); return new AstVar(definitions, attrAndType[2]) } return new AstStatement(transformExpression(statement)) } function AstForExpression(initStatement, condition, step) { this.initStatement = initStatement; this.condition = condition; this.step = step } AstForExpression.prototype.toString = function() { return "(" + this.initStatement + "; " + this.condition + "; " + this.step + ")" }; function AstForInExpression(initStatement, container) { this.initStatement = initStatement; this.container = container }

AstForInExpression.prototype.toString = function() { var init = this.initStatement.toString(); if (init.indexOf("=") >= 0) init = init.substring(0, init.indexOf("=")); return "(" + init + " in " + this.container + ")" }; function AstForEachExpression(initStatement, container) { this.initStatement = initStatement; this.container = container } AstForEachExpression.iteratorId = 0; AstForEachExpression.prototype.toString = function() { var init = this.initStatement.toString(); var iterator = "$it" + AstForEachExpression.iteratorId++; var variableName = init.replace(/^\s*var\s*/, "").split("=")[0]; var initIteratorAndVariable = "var " + iterator + " = new $p.ObjectIterato r(" + this.container + "), " + variableName + " = void(0)"; var nextIterationCondition = iterator + ".hasNext() && ((" + variableName + " = " + iterator + ".next()) || true)"; return "(" + initIteratorAndVariable + "; " + nextIterationCondition + ";) " }; function transformForExpression(expr) { var content; if (/\bin\b/.test(expr)) { content = expr.substring(1, expr.length - 1).split(/\bin\b/g); return new AstForInExpression(transformStatement(trim(content[0])), tran sformExpression(content[1])) } if (expr.indexOf(":") >= 0 && expr.indexOf(";") < 0) { content = expr.substring(1, expr.length - 1).split(":"); return new AstForEachExpression(transformStatement(trim(content[0])), tr ansformExpression(content[1])) } content = expr.substring(1, expr.length - 1).split(";"); return new AstForExpression(transformStatement(trim(content[0])), transfor mExpression(content[1]), transformExpression(content[2])) } function sortByWeight(array) { array.sort(function(a, b) { return b.weight - a.weight }) } function AstInnerInterface(name, body, isStatic) { this.name = name; this.body = body; this.isStatic = isStatic; body.owner = this } AstInnerInterface.prototype.toString = function() { return "" + this.body }; function AstInnerClass(name, body, isStatic) { this.name = name; this.body = body; this.isStatic = isStatic; body.owner = this

} AstInnerClass.prototype.toString = function() { return "" + this.body }; function transformInnerClass(class_) { var m = classesRegex.exec(class_); classesRegex.lastIndex = 0; var isStatic = m[1].indexOf("static") >= 0; var body = atoms[getAtomIndex(m[6])], innerClass; var oldClassId = currentClassId, newClassId = generateClassId(); currentClassId = newClassId; if (m[2] === "interface") innerClass = new AstInnerInterface(m[3], transfo rmInterfaceBody(body, m[3], m[4]), isStatic); else innerClass = new AstInnerClass(m[3], transformClassBody(body, m[3], m [4], m[5]), isStatic); appendClass(innerClass, newClassId, oldClassId); currentClassId = oldClassId; return innerClass } function AstClassMethod(name, params, body, isStatic) { this.name = name; this.params = params; this.body = body; this.isStatic = isStatic } AstClassMethod.prototype.toString = function() { var paramNames = appendToLookupTable({}, this.params.getNames()); var oldContext = replaceContext; replaceContext = function(subject) { return paramNames.hasOwnProperty(subject.name) ? subject.name : oldConte xt(subject) }; var body = this.params.prependMethodArgs(this.body.toString()); var result = "function " + this.methodId + this.params + " " + body + "\n" ; replaceContext = oldContext; return result }; function transformClassMethod(method) { var m = methodsRegex.exec(method); methodsRegex.lastIndex = 0; var isStatic = m[1].indexOf("static") >= 0; var body = m[6] !== ";" ? atoms[getAtomIndex(m[6])] : "{}"; return new AstClassMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]) , transformStatementsBlock(body), isStatic) } function AstClassField(definitions, fieldType, isStatic) { this.definitions = definitions; this.fieldType = fieldType; this.isStatic = isStatic } AstClassField.prototype.getNames = function() { var names = []; for (var i = 0, l = this.definitions.length; i < l; ++i) names.push(this.d efinitions[i].name);

return names }; AstClassField.prototype.toString = function() { var thisPrefix = replaceContext({ name: "[this]" }); if (this.isStatic) { var className = this.owner.name; var staticDeclarations = []; for (var i = 0, l = this.definitions.length; i < l; ++i) { var definition = this.definitions[i]; var name = definition.name, staticName = className + "." + name; var declaration = "if(" + staticName + " === void(0)) {\n" + " " + sta ticName + " = " + definition.value + "; }\n" + "$p.defineProperty(" + thisPrefix + ", " + "'" + name + "', { get: function(){return " + staticName + ";}, " + "s et: function(val){" + staticName + " = val;} });\n"; staticDeclarations.push(declaration) } return staticDeclarations.join("") } return thisPrefix + "." + this.definitions.join("; " + thisPrefix + ".") }; function transformClassField(statement) { var attrAndType = attrAndTypeRegex.exec(statement); var isStatic = attrAndType[1].indexOf("static") >= 0; var definitions = statement.substring(attrAndType[0].length).split(/,\s*/g ); var defaultTypeValue = getDefaultValueForType(attrAndType[2]); for (var i = 0; i < definitions.length; ++i) definitions[i] = transformVar Definition(definitions[i], defaultTypeValue); return new AstClassField(definitions, attrAndType[2], isStatic) } function AstConstructor(params, body) { this.params = params; this.body = body } AstConstructor.prototype.toString = function() { var paramNames = appendToLookupTable({}, this.params.getNames()); var oldContext = replaceContext; replaceContext = function(subject) { return paramNames.hasOwnProperty(subject.name) ? subject.name : oldConte xt(subject) }; var prefix = "function $constr_" + this.params.params.length + this.params .toString(); var body = this.params.prependMethodArgs(this.body.toString()); if (!/\$(superCstr|constr)\b/.test(body)) body = "{\n$superCstr();\n" + bo dy.substring(1); replaceContext = oldContext; return prefix + body + "\n" }; function transformConstructor(cstr) { var m = (new RegExp(/"B(\d+)"\s*"A(\d+)"/)).exec(cstr); var params = transformParams(atoms[m[1]]); return new AstConstructor(params, transformStatementsBlock(atoms[m[2]])) }

function AstInterfaceBody(name, interfacesNames, methodsNames, fields, inner Classes, misc) { var i, l; this.name = name; this.interfacesNames = interfacesNames; this.methodsNames = methodsNames; this.fields = fields; this.innerClasses = innerClasses; this.misc = misc; for (i = 0, l = fields.length; i < l; ++i) fields[i].owner = this } AstInterfaceBody.prototype.getMembers = function(classFields, classMethods, classInners) { if (this.owner.base) this.owner.base.body.getMembers(classFields, classMet hods, classInners); var i, j, l, m; for (i = 0, l = this.fields.length; i < l; ++i) { var fieldNames = this.fields[i].getNames(); for (j = 0, m = fieldNames.length; j < m; ++j) classFields[fieldNames[j] ] = this.fields[i] } for (i = 0, l = this.methodsNames.length; i < l; ++i) { var methodName = this.methodsNames[i]; classMethods[methodName] = true } for (i = 0, l = this.innerClasses.length; i < l; ++i) { var innerClass = this.innerClasses[i]; classInners[innerClass.name] = innerClass } }; AstInterfaceBody.prototype.toString = function() { function getScopeLevel(p) { var i = 0; while (p) { ++i; p = p.scope } return i } var scopeLevel = getScopeLevel(this.owner); var className = this.name; var staticDefinitions = ""; var metadata = ""; var thisClassFields = {}, thisClassMethods = {}, thisClassInners = {}; this.getMembers(thisClassFields, thisClassMethods, thisClassInners); var i, l, j, m; if (this.owner.interfaces) { var resolvedInterfaces = [], resolvedInterface; for (i = 0, l = this.interfacesNames.length; i < l; ++i) { if (!this.owner.interfaces[i]) continue; resolvedInterface = replaceContext({ name: this.interfacesNames[i] }); resolvedInterfaces.push(resolvedInterface); staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n" }

metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n" } metadata += className + ".$isInterface = true;\n"; metadata += className + ".$methods = ['" + this.methodsNames.join("', '") + "'];\n"; sortByWeight(this.innerClasses); for (i = 0, l = this.innerClasses.length; i < l; ++i) { var innerClass = this.innerClasses[i]; if (innerClass.isStatic) staticDefinitions += className + "." + innerCla ss.name + " = " + innerClass + ";\n" } for (i = 0, l = this.fields.length; i < l; ++i) { var field = this.fields[i]; if (field.isStatic) staticDefinitions += className + "." + field.definit ions.join(";\n" + className + ".") + ";\n" } return "(function() {\n" + "function " + className + "() { throw 'Unable t o create the interface'; }\n" + staticDefinitions + metadata + "return " + class Name + ";\n" + "})()" }; transformInterfaceBody = function(body, name, baseInterfaces) { var declarations = body.substring(1, body.length - 1); declarations = extractClassesAndMethods(declarations); declarations = extractConstructors(declarations, name); var methodsNames = [], classes = []; declarations = declarations.replace(/"([DE])(\d+)"/g, function(all, type, index) { if (type === "D") methodsNames.push(index); else if (type === "E") classes.push(index); return "" }); var fields = declarations.split(/;(?:\s*;)*/g); var baseInterfaceNames; var i, l; if (baseInterfaces !== undef) baseInterfaceNames = baseInterfaces.replace( /^\s*extends\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); for (i = 0, l = methodsNames.length; i < l; ++i) { var method = transformClassMethod(atoms[methodsNames[i]]); methodsNames[i] = method.name } for (i = 0, l = fields.length - 1; i < l; ++i) { var field = trimSpaces(fields[i]); fields[i] = transformClassField(field.middle) } var tail = fields.pop(); for (i = 0, l = classes.length; i < l; ++i) classes[i] = transformInnerCla ss(atoms[classes[i]]); return new AstInterfaceBody(name, baseInterfaceNames, methodsNames, fields , classes, { tail: tail }) }; function AstClassBody(name, baseClassName, interfacesNames, functions, metho ds, fields, cstrs, innerClasses, misc) { var i, l; this.name = name; this.baseClassName = baseClassName;

this.interfacesNames = interfacesNames; this.functions = functions; this.methods = methods; this.fields = fields; this.cstrs = cstrs; this.innerClasses = innerClasses; this.misc = misc; for (i = 0, l = fields.length; i < l; ++i) fields[i].owner = this } AstClassBody.prototype.getMembers = function(classFields, classMethods, clas sInners) { if (this.owner.base) this.owner.base.body.getMembers(classFields, classMet hods, classInners); var i, j, l, m; for (i = 0, l = this.fields.length; i < l; ++i) { var fieldNames = this.fields[i].getNames(); for (j = 0, m = fieldNames.length; j < m; ++j) classFields[fieldNames[j] ] = this.fields[i] } for (i = 0, l = this.methods.length; i < l; ++i) { var method = this.methods[i]; classMethods[method.name] = method } for (i = 0, l = this.innerClasses.length; i < l; ++i) { var innerClass = this.innerClasses[i]; classInners[innerClass.name] = innerClass } }; AstClassBody.prototype.toString = function() { function getScopeLevel(p) { var i = 0; while (p) { ++i; p = p.scope } return i } var scopeLevel = getScopeLevel(this.owner); var selfId = "$this_" + scopeLevel; var className = this.name; var result = "var " + selfId + " = this;\n"; var staticDefinitions = ""; var metadata = ""; var thisClassFields = {}, thisClassMethods = {}, thisClassInners = {}; this.getMembers(thisClassFields, thisClassMethods, thisClassInners); var oldContext = replaceContext; replaceContext = function(subject) { var name = subject.name; if (name === "this") return subject.callSign || !subject.member ? selfId + ".$self" : selfId; if (thisClassFields.hasOwnProperty(name)) return thisClassFields[name].i sStatic ? className + "." + name : selfId + "." + name; if (thisClassInners.hasOwnProperty(name)) return selfId + "." + name; if (thisClassMethods.hasOwnProperty(name)) return thisClassMethods[name] .isStatic ? className + "." + name : selfId + ".$self." + name; return oldContext(subject) }; var resolvedBaseClassName;

if (this.baseClassName) { resolvedBaseClassName = oldContext({ name: this.baseClassName }); result += "var $super = { $upcast: " + selfId + " };\n"; result += "function $superCstr(){" + resolvedBaseClassName + ".apply($su per,arguments);if(!('$self' in $super)) $p.extendClassChain($super)}\n"; metadata += className + ".$base = " + resolvedBaseClassName + ";\n" } else result += "function $superCstr(){$p.extendClassChain(" + selfId + " )}\n"; if (this.owner.base) staticDefinitions += "$p.extendStaticMembers(" + clas sName + ", " + resolvedBaseClassName + ");\n"; var i, l, j, m; if (this.owner.interfaces) { var resolvedInterfaces = [], resolvedInterface; for (i = 0, l = this.interfacesNames.length; i < l; ++i) { if (!this.owner.interfaces[i]) continue; resolvedInterface = oldContext({ name: this.interfacesNames[i] }); resolvedInterfaces.push(resolvedInterface); staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n" } metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n" } if (this.functions.length > 0) result += this.functions.join("\n") + "\n"; sortByWeight(this.innerClasses); for (i = 0, l = this.innerClasses.length; i < l; ++i) { var innerClass = this.innerClasses[i]; if (innerClass.isStatic) { staticDefinitions += className + "." + innerClass.name + " = " + inner Class + ";\n"; result += selfId + "." + innerClass.name + " = " + className + "." + i nnerClass.name + ";\n" } else result += selfId + "." + innerClass.name + " = " + innerClass + " ;\n" } for (i = 0, l = this.fields.length; i < l; ++i) { var field = this.fields[i]; if (field.isStatic) { staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n"; for (j = 0, m = field.definitions.length; j < m; ++j) { var fieldName = field.definitions[j].name, staticName = className + "." + fieldName; result += "$p.defineProperty(" + selfId + ", '" + fieldName + "', {" + "get: function(){return " + staticName + "}, " + "set: function(val){" + stat icName + " = val}});\n" } } else result += selfId + "." + field.definitions.join(";\n" + selfId + ".") + ";\n" } var methodOverloads = {}; for (i = 0, l = this.methods.length; i < l; ++i) { var method = this.methods[i]; var overload = methodOverloads[method.name]; var methodId = method.name + "$" + method.params.params.length;

var hasMethodArgs = !!method.params.methodArgsParam; if (overload) { ++overload; methodId += "_" + overload } else overload = 1; method.methodId = methodId; methodOverloads[method.name] = overload; if (method.isStatic) { staticDefinitions += method; staticDefinitions += "$p.addMethod(" + className + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n"; result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + met hodId + ", " + hasMethodArgs + ");\n" } else { result += method; result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + met hodId + ", " + hasMethodArgs + ");\n" } } result += trim(this.misc.tail); if (this.cstrs.length > 0) result += this.cstrs.join("\n") + "\n"; result += "function $constr() {\n"; var cstrsIfs = []; for (i = 0, l = this.cstrs.length; i < l; ++i) { var paramsLength = this.cstrs[i].params.params.length; var methodArgsPresent = !!this.cstrs[i].params.methodArgsParam; cstrsIfs.push("if(arguments.length " + (methodArgsPresent ? ">=" : "===" ) + " " + paramsLength + ") { " + "$constr_" + paramsLength + ".apply(" + selfId + ", arguments); }") } if (cstrsIfs.length > 0) result += cstrsIfs.join(" else ") + " else "; result += "$superCstr();\n}\n"; result += "$constr.apply(null, arguments);\n"; replaceContext = oldContext; return "(function() {\n" + "function " + className + "() {\n" + result + " }\n" + staticDefinitions + metadata + "return " + className + ";\n" + "})()" }; transformClassBody = function(body, name, baseName, interfaces) { var declarations = body.substring(1, body.length - 1); declarations = extractClassesAndMethods(declarations); declarations = extractConstructors(declarations, name); var methods = [], classes = [], cstrs = [], functions = []; declarations = declarations.replace(/"([DEGH])(\d+)"/g, function(all, type , index) { if (type === "D") methods.push(index); else if (type === "E") classes.push(index); else if (type === "H") functions.push(index); else cstrs.push(index); return "" }); var fields = declarations.replace(/^(?:\s*;)+/, "").split(/;(?:\s*;)*/g); var baseClassName, interfacesNames; var i; if (baseName !== undef) baseClassName = baseName.replace(/^\s*extends\s+([ A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*$/g, "$1"); if (interfaces !== undef) interfacesNames = interfaces.replace(/^\s*implem ents\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g);

for (i = 0; i < functions.length; ++i) functions[i] = transformFunction(at oms[functions[i]]); for (i = 0; i < methods.length; ++i) methods[i] = transformClassMethod(ato ms[methods[i]]); for (i = 0; i < fields.length - 1; ++i) { var field = trimSpaces(fields[i]); fields[i] = transformClassField(field.middle) } var tail = fields.pop(); for (i = 0; i < cstrs.length; ++i) cstrs[i] = transformConstructor(atoms[c strs[i]]); for (i = 0; i < classes.length; ++i) classes[i] = transformInnerClass(atom s[classes[i]]); return new AstClassBody(name, baseClassName, interfacesNames, functions, m ethods, fields, cstrs, classes, { tail: tail }) }; function AstInterface(name, body) { this.name = name; this.body = body; body.owner = this } AstInterface.prototype.toString = function() { return "var " + this.name + " = " + this.body + ";\n" + "$p." + this.name + " = " + this.name + ";\n" }; function AstClass(name, body) { this.name = name; this.body = body; body.owner = this } AstClass.prototype.toString = function() { return "var " + this.name + " = " + this.body + ";\n" + "$p." + this.name + " = " + this.name + ";\n" }; function transformGlobalClass(class_) { var m = classesRegex.exec(class_); classesRegex.lastIndex = 0; var body = atoms[getAtomIndex(m[6])]; var oldClassId = currentClassId, newClassId = generateClassId(); currentClassId = newClassId; var globalClass; if (m[2] === "interface") globalClass = new AstInterface(m[3], transformIn terfaceBody(body, m[3], m[4])); else globalClass = new AstClass(m[3], transformClassBody(body, m[3], m[4], m[5])); appendClass(globalClass, newClassId, oldClassId); currentClassId = oldClassId; return globalClass } function AstMethod(name, params, body) { this.name = name; this.params = params; this.body = body }

AstMethod.prototype.toString = function() { var paramNames = appendToLookupTable({}, this.params.getNames()); var oldContext = replaceContext; replaceContext = function(subject) { return paramNames.hasOwnProperty(subject.name) ? subject.name : oldConte xt(subject) }; var body = this.params.prependMethodArgs(this.body.toString()); var result = "function " + this.name + this.params + " " + body + "\n" + " $p." + this.name + " = " + this.name + ";"; replaceContext = oldContext; return result }; function transformGlobalMethod(method) { var m = methodsRegex.exec(method); var result = methodsRegex.lastIndex = 0; return new AstMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), tra nsformStatementsBlock(atoms[getAtomIndex(m[6])])) } function preStatementsTransform(statements) { var s = statements; s = s.replace(/\b(catch\s*"B\d+"\s*"A\d+")(\s*catch\s*"B\d+"\s*"A\d+")+/g, "$1"); return s } function AstForStatement(argument, misc) { this.argument = argument; this.misc = misc } AstForStatement.prototype.toString = function() { return this.misc.prefix + this.argument.toString() }; function AstCatchStatement(argument, misc) { this.argument = argument; this.misc = misc } AstCatchStatement.prototype.toString = function() { return this.misc.prefix + this.argument.toString() }; function AstPrefixStatement(name, argument, misc) { this.name = name; this.argument = argument; this.misc = misc } AstPrefixStatement.prototype.toString = function() { var result = this.misc.prefix; if (this.argument !== undef) result += this.argument.toString(); return result }; function AstSwitchCase(expr) { this.expr = expr } AstSwitchCase.prototype.toString = function() { return "case " + this.expr + ":" };

function AstLabel(label) { this.label = label } AstLabel.prototype.toString = function() { return this.label }; transformStatements = function(statements, transformMethod, transformClass) { var nextStatement = new RegExp(/\b(catch|for|if|switch|while|with)\s*"B(\d +)"|\b(do|else|finally|return|throw|try|break|continue)\b|("[ADEH](\d+)")|\b(cas e)\s+([^:]+):|\b([A-Za-z_$][\w$]*\s*:)|(;)/g); var res = []; statements = preStatementsTransform(statements); var lastIndex = 0, m, space; while ((m = nextStatement.exec(statements)) !== null) { if (m[1] !== undef) { var i = statements.lastIndexOf('"B', nextStatement.lastIndex); var statementsPrefix = statements.substring(lastIndex, i); if (m[1] === "for") res.push(new AstForStatement(transformForExpressio n(atoms[m[2]]), { prefix: statementsPrefix })); else if (m[1] === "catch") res.push(new AstCatchStatement(transformPar ams(atoms[m[2]]), { prefix: statementsPrefix })); else res.push(new AstPrefixStatement(m[1], transformExpression(atoms[m [2]]), { prefix: statementsPrefix })) } else if (m[3] !== undef) res.push(new AstPrefixStatement(m[3], undef, { prefix: statements.substring(lastIndex, nextStatement.lastIndex) })); else if (m[4] !== undef) { space = statements.substring(lastIndex, nextStatement.lastIndex - m[4] .length); if (trim(space).length !== 0) continue; res.push(space); var kind = m[4].charAt(1), atomIndex = m[5]; if (kind === "D") res.push(transformMethod(atoms[atomIndex])); else if (kind === "E") res.push(transformClass(atoms[atomIndex])); else if (kind === "H") res.push(transformFunction(atoms[atomIndex])); else res.push(transformStatementsBlock(atoms[atomIndex])) } else if (m[6] !== undef) res.push(new AstSwitchCase(transformExpressio n(trim(m[7])))); else if (m[8] !== undef) { space = statements.substring(lastIndex, nextStatement.lastIndex - m[8] .length); if (trim(space).length !== 0) continue; res.push(new AstLabel(statements.substring(lastIndex, nextStatement.la stIndex))) } else { var statement = trimSpaces(statements.substring(lastIndex, nextStateme nt.lastIndex - 1)); res.push(statement.left); res.push(transformStatement(statement.middle));

res.push(statement.right + ";") } lastIndex = nextStatement.lastIndex } var statementsTail = trimSpaces(statements.substring(lastIndex)); res.push(statementsTail.left); if (statementsTail.middle !== "") { res.push(transformStatement(statementsTail.middle)); res.push(";" + statementsTail.right) } return res }; function getLocalNames(statements) { var localNames = []; for (var i = 0, l = statements.length; i < l; ++i) { var statement = statements[i]; if (statement instanceof AstVar) localNames = localNames.concat(statemen t.getNames()); else if (statement instanceof AstForStatement && statement.argument.init Statement instanceof AstVar) localNames = localNames.concat(statement.argument.i nitStatement.getNames()); else if (statement instanceof AstInnerInterface || statement instanceof AstInnerClass || statement instanceof AstInterface || statement instanceof AstCl ass || statement instanceof AstMethod || statement instanceof AstFunction) local Names.push(statement.name) } return appendToLookupTable({}, localNames) } function AstStatementsBlock(statements) { this.statements = statements } AstStatementsBlock.prototype.toString = function() { var localNames = getLocalNames(this.statements); var oldContext = replaceContext; if (!isLookupTableEmpty(localNames)) replaceContext = function(subject) { return localNames.hasOwnProperty(subject.name) ? subject.name : oldConte xt(subject) }; var result = "{\n" + this.statements.join("") + "\n}"; replaceContext = oldContext; return result }; transformStatementsBlock = function(block) { var content = trimSpaces(block.substring(1, block.length - 1)); return new AstStatementsBlock(transformStatements(content.middle)) }; function AstRoot(statements) { this.statements = statements } AstRoot.prototype.toString = function() { var classes = [], otherStatements = [], statement; for (var i = 0, len = this.statements.length; i < len; ++i) { statement = this.statements[i]; if (statement instanceof AstClass || statement instanceof AstInterface) classes.push(statement);

else otherStatements.push(statement) } sortByWeight(classes); var localNames = getLocalNames(this.statements); replaceContext = function(subject) { var name = subject.name; if (localNames.hasOwnProperty(name)) return name; if (globalMembers.hasOwnProperty(name) || PConstants.hasOwnProperty(name ) || defaultScope.hasOwnProperty(name)) return "$p." + name; return name }; var result = "// this code was autogenerated from PJS\n" + "(function($p) {\n" + classes.join("") + "\n" + otherStatements.join("") + "\n})"; replaceContext = null; return result }; transformMain = function() { var statements = extractClassesAndMethods(atoms[0]); statements = statements.replace(/\bimport\s+[^;]+;/g, ""); return new AstRoot(transformStatements(statements, transformGlobalMethod, transformGlobalClass)) }; function generateMetadata(ast) { var globalScope = {}; var id, class_; for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { class_ = declaredClasses[id]; var scopeId = class_.scopeId, name = class_.name; if (scopeId) { var scope = declaredClasses[scopeId]; class_.scope = scope; if (scope.inScope === undef) scope.inScope = {}; scope.inScope[name] = class_ } else globalScope[name] = class_ } function findInScopes(class_, name) { var parts = name.split("."); var currentScope = class_.scope, found; while (currentScope) { if (currentScope.hasOwnProperty(parts[0])) { found = currentScope[parts[0]]; break } currentScope = currentScope.scope } if (found === undef) found = globalScope[parts[0]]; for (var i = 1, l = parts.length; i < l && found; ++i) found = found.inS cope[parts[i]]; return found } for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { class_ = declaredClasses[id]; var baseClassName = class_.body.baseClassName; if (baseClassName) { var parent = findInScopes(class_, baseClassName); if (parent) { class_.base = parent;

if (!parent.derived) parent.derived = []; parent.derived.push(class_) } } var interfacesNames = class_.body.interfacesNames, interfaces = [], i, l; if (interfacesNames && interfacesNames.length > 0) { for (i = 0, l = interfacesNames.length; i < l; ++i) { var interface_ = findInScopes(class_, interfacesNames[i]); interfaces.push(interface_); if (!interface_) continue; if (!interface_.derived) interface_.derived = []; interface_.derived.push(class_) } if (interfaces.length > 0) class_.interfaces = interfaces } } } function setWeight(ast) { var queue = [], tocheck = {}; var id, scopeId, class_; for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { class_ = declaredClasses[id]; if (!class_.inScope && !class_.derived) { queue.push(id); class_.weight = 0 } else { var dependsOn = []; if (class_.inScope) for (scopeId in class_.inScope) if (class_.inScope .hasOwnProperty(scopeId)) dependsOn.push(class_.inScope[scopeId]); if (class_.derived) dependsOn = dependsOn.concat(class_.derived); tocheck[id] = dependsOn } } function removeDependentAndCheck(targetId, from) { var dependsOn = tocheck[targetId]; if (!dependsOn) return false; var i = dependsOn.indexOf(from); if (i < 0) return false; dependsOn.splice(i, 1); if (dependsOn.length > 0) return false; delete tocheck[targetId]; return true } while (queue.length > 0) { id = queue.shift(); class_ = declaredClasses[id]; if (class_.scopeId && removeDependentAndCheck(class_.scopeId, class_)) { queue.push(class_.scopeId); declaredClasses[class_.scopeId].weight = class_.weight + 1 } if (class_.base && removeDependentAndCheck(class_.base.classId, class_)) { queue.push(class_.base.classId); class_.base.weight = class_.weight + 1 } if (class_.interfaces) { var i, l;

for (i = 0, l = class_.interfaces.length; i < l; ++i) { if (!class_.interfaces[i] || !removeDependentAndCheck(class_.interfa ces[i].classId, class_)) continue; queue.push(class_.interfaces[i].classId); class_.interfaces[i].weight = class_.weight + 1 } } } } var transformed = transformMain(); generateMetadata(transformed); setWeight(transformed); var redendered = transformed.toString(); redendered = redendered.replace(/\s*\n(?:[\t ]*\n)+/g, "\n\n"); redendered = redendered.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { return String.fromCharCode(parseInt(hexCode, 16)) }); return injectStrings(redendered, strings) } function preprocessCode(aCode, sketch) { var dm = (new RegExp(/\/\*\s*@pjs\s+((?:[^\*]|\*+[^\*\/])*)\*\//g)).exec(aCo de); if (dm && dm.length === 2) { var jsonItems = [], directives = dm.splice(1, 2)[0].replace(/\{([\s\S]*?)\}/g, function() { return function(all, item) { jsonItems.push(item); return "{" + (jsonItems.length - 1) + "}" } }()).replace("\n", "").replace("\r", "").split(";"); var clean = function(s) { return s.replace(/^\s*["']?/, "").replace(/["']?\s*$/, "") }; for (var i = 0, dl = directives.length; i < dl; i++) { var pair = directives[i].split("="); if (pair && pair.length === 2) { var key = clean(pair[0]), value = clean(pair[1]), list = []; if (key === "preload") { list = value.split(","); for (var j = 0, jl = list.length; j < jl; j++) { var imageName = clean(list[j]); sketch.imageCache.add(imageName) } } else if (key === "font") { list = value.split(","); for (var x = 0, xl = list.length; x < xl; x++) { var fontName = clean(list[x]), index = /^\{(\d*?)\}$/.exec(fontName); PFont.preloading.add(index ? JSON.parse("{" + jsonItems[index[1]] + "}") : fontName) } } else if (key === "pauseOnBlur") sketch.options.pauseOnBlur = value = == "true"; else if (key === "globalKeyEvents") sketch.options.globalKeyEvents = v alue === "true"; else if (key.substring(0, 6) === "param-") sketch.params[key.substring

(6)] = value; else sketch.options[key] = value } } } return aCode } Processing.compile = function(pdeCode) { var sketch = new Processing.Sketch; var code = preprocessCode(pdeCode, sketch); var compiledPde = parseProcessing(code); sketch.sourceCode = compiledPde; return sketch }; var tinylogLite = function() { var tinylogLite = {}, undef = "undefined", func = "function", False = !1, True = !0, logLimit = 512, log = "log"; if (typeof tinylog !== undef && typeof tinylog[log] === func) tinylogLite[lo g] = tinylog[log]; else if (typeof document !== undef && !document.fake)(function() { var doc = document, $div = "div", $style = "style", $title = "title", containerStyles = { zIndex: 1E4, position: "fixed", bottom: "0px", width: "100%", height: "15%", fontFamily: "sans-serif", color: "#ccc", backgroundColor: "black" }, outputStyles = { position: "relative", fontFamily: "monospace", overflow: "auto", height: "100%", paddingTop: "5px" }, resizerStyles = { height: "5px", marginTop: "-5px", cursor: "n-resize", backgroundColor: "darkgrey" }, closeButtonStyles = { position: "absolute", top: "5px", right: "20px", color: "#111", MozBorderRadius: "4px", webkitBorderRadius: "4px", borderRadius: "4px",

cursor: "pointer", fontWeight: "normal", textAlign: "center", padding: "3px 5px", backgroundColor: "#333", fontSize: "12px" }, entryStyles = { minHeight: "16px" }, entryTextStyles = { fontSize: "12px", margin: "0 8px 0 8px", maxWidth: "100%", whiteSpace: "pre-wrap", overflow: "auto" }, view = doc.defaultView, docElem = doc.documentElement, docElemStyle = docElem[$style], setStyles = function() { var i = arguments.length, elemStyle, styles, style; while (i--) { styles = arguments[i--]; elemStyle = arguments[i][$style]; for (style in styles) if (styles.hasOwnProperty(style)) elemStyle[styl e] = styles[style] } }, observer = function(obj, event, handler) { if (obj.addEventListener) obj.addEventListener(event, handler, False); else if (obj.attachEvent) obj.attachEvent("on" + event, handler); return [obj, event, handler] }, unobserve = function(obj, event, handler) { if (obj.removeEventListener) obj.removeEventListener(event, handler, Fal se); else if (obj.detachEvent) obj.detachEvent("on" + event, handler) }, clearChildren = function(node) { var children = node.childNodes, child = children.length; while (child--) node.removeChild(children.item(0)) }, append = function(to, elem) { return to.appendChild(elem) }, createElement = function(localName) { return doc.createElement(localName) }, createTextNode = function(text) { return doc.createTextNode(text) }, createLog = tinylogLite[log] = function(message) { var uninit, originalPadding = docElemStyle.paddingBottom, container = createElement($div), containerStyle = container[$style], resizer = append(container, createElement($div)), output = append(container, createElement($div)),

closeButton = append(container, createElement($div)), resizingLog = False, previousHeight = False, previousScrollTop = False, messages = 0, updateSafetyMargin = function() { docElemStyle.paddingBottom = container.clientHeight + "px" }, setContainerHeight = function(height) { var viewHeight = view.innerHeight, resizerHeight = resizer.clientHeight; if (height < 0) height = 0; else if (height + resizerHeight > viewHeight) height = viewHeight - re sizerHeight; containerStyle.height = height / viewHeight * 100 + "%"; updateSafetyMargin() }, observers = [observer(doc, "mousemove", function(evt) { if (resizingLog) { setContainerHeight(view.innerHeight - evt.clientY); output.scrollTop = previousScrollTop } }), observer(doc, "mouseup", function() { if (resizingLog) resizingLog = previousScrollTop = False }), observer(resizer, "dblclick", function(evt) { evt.preventDefault(); if (previousHeight) { setContainerHeight(previousHeight); previousHeight = False } else { previousHeight = container.clientHeight; containerStyle.height = "0px" } }), observer(resizer, "mousedown", function(evt) { evt.preventDefault(); resizingLog = True; previousScrollTop = output.scrollTop }), observer(resizer, "contextmenu", function() { resizingLog = False }), observer(closeButton, "click", function() { uninit() })]; uninit = function() { var i = observers.length; while (i--) unobserve.apply(tinylogLite, observers[i]); docElem.removeChild(container); docElemStyle.paddingBottom = originalPadding; clearChildren(output); clearChildren(container); tinylogLite[log] = createLog }; setStyles(container, containerStyles, output, outputStyles, resizer, res izerStyles, closeButton, closeButtonStyles); closeButton[$title] = "Close Log"; append(closeButton, createTextNode("\u2716")); resizer[$title] = "Double-click to toggle log minimization"; docElem.insertBefore(container, docElem.firstChild); tinylogLite[log] = function(message) { if (messages === logLimit) output.removeChild(output.firstChild); else messages++;

var entry = append(output, createElement($div)), entryText = append(entry, createElement($div)); entry[$title] = (new Date).toLocaleTimeString(); setStyles(entry, entryStyles, entryText, entryTextStyles); append(entryText, createTextNode(message)); output.scrollTop = output.scrollHeight }; tinylogLite[log](message); updateSafetyMargin() } })(); else if (typeof print === func) tinylogLite[log] = print; return tinylogLite }(); Processing.logger = tinylogLite; Processing.version = "1.4.1"; Processing.lib = {}; Processing.registerLibrary = function(name, desc) { Processing.lib[name] = desc; if (desc.hasOwnProperty("init")) desc.init(defaultScope) }; Processing.instances = processingInstances; Processing.getInstanceById = function(name) { return processingInstances[processingInstanceIds[name]] }; Processing.Sketch = function(attachFunction) { this.attachFunction = attachFunction; this.options = { pauseOnBlur: false, globalKeyEvents: false }; this.onLoad = nop; this.onSetup = nop; this.onPause = nop; this.onLoop = nop; this.onFrameStart = nop; this.onFrameEnd = nop; this.onExit = nop; this.params = {}; this.imageCache = { pending: 0, images: {}, operaCache: {}, add: function(href, img) { if (this.images[href]) return; if (!isDOMPresent) this.images[href] = null; if (!img) { img = new Image; img.onload = function(owner) { return function() { owner.pending-} }(this); this.pending++; img.src = href } this.images[href] = img; if (window.opera) { var div = document.createElement("div"); div.appendChild(img);

div.style.position = "absolute"; div.style.opacity = 0; div.style.width = "1px"; div.style.height = "1px"; if (!this.operaCache[href]) { document.body.appendChild(div); this.operaCache[href] = div } } } }; this.sourceCode = undefined; this.attach = function(processing) { if (typeof this.attachFunction === "function") this.attachFunction(process ing); else if (this.sourceCode) { var func = (new Function("return (" + this.sourceCode + ");"))(); func(processing); this.attachFunction = func } else throw "Unable to attach sketch to the processing instance"; }; this.toString = function() { var i; var code = "((function(Sketch) {\n"; code += "var sketch = new Sketch(\n" + this.sourceCode + ");\n"; for (i in this.options) if (this.options.hasOwnProperty(i)) { var value = this.options[i]; code += "sketch.options." + i + " = " + (typeof value === "string" ? '"' + value + '"' : "" + value) + ";\n" } for (i in this.imageCache) if (this.options.hasOwnProperty(i)) code += 'sk etch.imageCache.add("' + i + '");\n'; code += "return sketch;\n})(Processing.Sketch))"; return code } }; var loadSketchFromSources = function(canvas, sources) { var code = [], errors = [], sourcesCount = sources.length, loaded = 0; function ajaxAsync(url, callback) { var xhr = new XMLHttpRequest; xhr.onreadystatechange = function() { if (xhr.readyState === 4) { var error; if (xhr.status !== 200 && xhr.status !== 0) error = "Invalid XHR statu s " + xhr.status; else if (xhr.responseText === "") if ("withCredentials" in new XMLHttp Request && (new XMLHttpRequest).withCredentials === false && window.location.pro tocol === "file:") error = "XMLHttpRequest failure, possibly due to a same-origi n policy violation. You can try loading this page in another browser, or load it from http://localhost using a local webserver. See the Processing.js README for a more detailed explanation of this problem and solutions."; else error = "File is empty."; callback(xhr.responseText, error) } }; xhr.open("GET", url, true);

if (xhr.overrideMimeType) xhr.overrideMimeType("application/json"); xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT") ; xhr.send(null) } function loadBlock(index, filename) { function callback(block, error) { code[index] = block; ++loaded; if (error) errors.push(filename + " ==> " + error); if (loaded === sourcesCount) if (errors.length === 0) try { return new Processing(canvas, code.join("\n")) } catch(e) { throw "Processing.js: Unable to execute pjs sketch: " + e; } else throw "Processing.js: Unable to load pjs sketch files: " + errors .join("\n"); } if (filename.charAt(0) === "#") { var scriptElement = document.getElementById(filename.substring(1)); if (scriptElement) callback(scriptElement.text || scriptElement.textCont ent); else callback("", "Unable to load pjs sketch: element with id '" + filen ame.substring(1) + "' was not found"); return } ajaxAsync(filename, callback) } for (var i = 0; i < sourcesCount; ++i) loadBlock(i, sources[i]) }; var init = function() { document.removeEventListener("DOMContentLoaded", init, false); processingInstances = []; var canvas = document.getElementsByTagName("canvas"), filenames; for (var i = 0, l = canvas.length; i < l; i++) { var processingSources = canvas[i].getAttribute("data-processing-sources"); if (processingSources === null) { processingSources = canvas[i].getAttribute("data-src"); if (processingSources === null) processingSources = canvas[i].getAttribu te("datasrc") } if (processingSources) { filenames = processingSources.split(/\s+/g); for (var j = 0; j < filenames.length;) if (filenames[j]) j++; else filenames.splice(j, 1); loadSketchFromSources(canvas[i], filenames) } } var s, last, source, instance, nodelist = document.getElementsByTagName("scr ipt"), scripts = []; for (s = nodelist.length - 1; s >= 0; s--) scripts.push(nodelist[s]); for (s = 0, last = scripts.length; s < last; s++) { var script = scripts[s]; if (!script.getAttribute) continue; var type = script.getAttribute("type"); if (type && (type.toLowerCase() === "text/processing" || type.toLowerCase( ) === "application/processing")) { var target = script.getAttribute("data-processing-target"); canvas = undef;

if (target) canvas = document.getElementById(target); else { var nextSibling = script.nextSibling; while (nextSibling && nextSibling.nodeType !== 1) nextSibling = nextSi bling.nextSibling; if (nextSibling && nextSibling.nodeName.toLowerCase() === "canvas") ca nvas = nextSibling } if (canvas) { if (script.getAttribute("src")) { filenames = script.getAttribute("src").split(/\s+/); loadSketchFromSources(canvas, filenames); continue } source = script.textContent || script.text; instance = new Processing(canvas, source) } } } }; Processing.reload = function() { if (processingInstances.length > 0) for (var i = processingInstances.length - 1; i >= 0; i--) if (processingInstances[i]) processingInstances[i].exit(); init() }; Processing.loadSketchFromSources = loadSketchFromSources; Processing.disableInit = function() { if (isDOMPresent) document.removeEventListener("DOMContentLoaded", init, fal se) }; if (isDOMPresent) { window["Processing"] = Processing; document.addEventListener("DOMContentLoaded", init, false) } else this.Processing = Processing })(window, window.document, Math);

Вам также может понравиться