Difference between revisions of "User:Dhhodgin"
(→Releases) |
(→About Me) |
||
(30 intermediate revisions by the same user not shown) | |||
Line 19: | Line 19: | ||
== About Me == | == About Me == | ||
− | I'm a | + | I'm a 7th Semester BSD student taking DPS901. Working part time on an ASP.NET c# application. |
==Technical Qualifications== | ==Technical Qualifications== | ||
Line 31: | Line 31: | ||
*XHTML/CSS | *XHTML/CSS | ||
*JavaScript | *JavaScript | ||
+ | *Processing | ||
== FSOSS Research Paper == | == FSOSS Research Paper == | ||
Line 41: | Line 42: | ||
0.1 - [http://dhodgin.wordpress.com/2009/10/29/release-0-1-for-my-processing-js-work/ Full Details] shorten(), expand(), nfs(), unhex(), bug fixes on nf() and fill()<br/> | 0.1 - [http://dhodgin.wordpress.com/2009/10/29/release-0-1-for-my-processing-js-work/ Full Details] shorten(), expand(), nfs(), unhex(), bug fixes on nf() and fill()<br/> | ||
0.2 - [http://dhodgin.wordpress.com/2009/11/19/processing-js-0-2-release/ Full Details] nfc(), exp(), log(), map(), asin(), acos(), atan(), tan()<br/> | 0.2 - [http://dhodgin.wordpress.com/2009/11/19/processing-js-0-2-release/ Full Details] nfc(), exp(), log(), map(), asin(), acos(), atan(), tan()<br/> | ||
− | 0.3 - | + | 0.3 - [http://dhodgin.wordpress.com/2009/12/15/my-great-white-vs-killer-whale-0-3-patch/ Full Details] blendColor(), blend(), copy(), filter()<br/> |
=== Contributions === | === Contributions === | ||
Line 47: | Line 48: | ||
* Created the template for processing.js tests | * Created the template for processing.js tests | ||
* Organized 0.1 release code table and project test table areas. | * Organized 0.1 release code table and project test table areas. | ||
+ | * Wrote GIT tutorial on adding code to GIT from a fresh fork [http://dhodgin.wordpress.com/2009/11/20/a-guide-to-git-for-the-processing-js-community-6-easy-steps/ tutorial] | ||
* Helped Al get Lighthouse setup and got invites sent out to everyone to better prepare for 0.2 release code and bug tracking | * Helped Al get Lighthouse setup and got invites sent out to everyone to better prepare for 0.2 release code and bug tracking | ||
+ | * Wrote tutorial on lighthouse, and ticket state explanations [https://processing-js.lighthouseapp.com/projects/41284-processingjs/messages messages] | ||
+ | * Helped with triage on lighthouse tickets | ||
+ | * Helped Anna with PImage copy math which will ultimately be used in my 0.3 copy() code | ||
− | === code | + | |
− | Here is a list of code blocks I have written for the processing.js project | + | |
− | ==== nfc() | + | === Week 1 stuff === |
+ | * Create Zenit Wiki (done) | ||
+ | * Create Blog ([http://dhodgin.wordpress.com done]) | ||
+ | * Blog on introductory readings (done) | ||
+ | * Listen in on a [[Overview_of_Mozilla_Communication#Weekly_Calls | Weekly Call]] (done) | ||
+ | * Update wiki (done) | ||
+ | |||
+ | === Week 2 stuff === | ||
+ | * Create MDC account (done) | ||
+ | * join Mozilla Fennec mailing list (done) | ||
+ | * week 2 lab (done) | ||
+ | * watch learning to be at the festival and blog about it (done) | ||
+ | |||
+ | === Week 3 stuff === | ||
+ | * watch online lectures about build system by Paul Reed (done) | ||
+ | * build Firefox at school on Linux (fedora) (done) | ||
+ | * build Firefox minefield at home on windows 7 (done) | ||
+ | * choose subject for project and write project plan on blog (done) | ||
+ | |||
+ | === Week 4 stuff === | ||
+ | * spend time searching through MXR and familiarizing myself with it (done) | ||
+ | * lab, working with patches (to do) | ||
+ | |||
+ | === Week 5 stuff === | ||
+ | * create Bugzilla account (done) | ||
+ | * Find 3+ bugs related to your project, and add them to your project wiki page ([http://zenit.senecac.on.ca/wiki/index.php/Fennec_and_@font-face done]) | ||
+ | * CC yourself on two bugs that relate to your project 517086 476478 (done) | ||
+ | * Watch a user in Bugzilla for the week and blog about the experience (blassey) (done) | ||
+ | * Be working on your 0.1 release. Ask for help if you're stuck (done) | ||
+ | * Register for FSOSS or join as a volunteer. (done) | ||
+ | |||
+ | === Week 6 stuff === | ||
+ | * work on [http://dhodgin.wordpress.com/2009/10/29/release-0-1-for-my-processing-js-work/ 0.1 release] (done) | ||
+ | |||
+ | === Week 7 stuff === | ||
+ | * Firefox tab ordering lab | ||
+ | * Watch [http://www.youtube.com/watch?v=hQVTIJBZook JavaScript online talk] (done) | ||
+ | |||
+ | === Week 8 stuff === | ||
+ | * Release 0.2 ([http://dhodgin.wordpress.com/2009/11/19/processing-js-0-2-release/ done]) | ||
+ | |||
+ | === Week 9 stuff === | ||
+ | * tba | ||
+ | |||
+ | ==DPS911 Projects== | ||
+ | [[http://zenit.senecac.on.ca/wiki/index.php/Processing.js Processing.js]] - Active project<br /> | ||
+ | |||
+ | === Releases === | ||
+ | 0.4 - [http://dhodgin.wordpress.com/2010/01/25/0-4-and-triage-for-processing-js/ Full Details] Triage and peer-review of outstanding 0.2 and 0.3 code<br/> | ||
+ | 0.5 - [http://dhodgin.wordpress.com/2010/02/06/0-5-processing-js-release-contribution/ Full Details] Review of binary() and sort(), rewrote hex(), trim(), some code efficiency cleanup<br /> | ||
+ | 0.6 - wip <br /> | ||
+ | |||
+ | |||
+ | |||
+ | === Weekly stuff === | ||
+ | * Update Wiki | ||
+ | * Prepare for 0.4 release | ||
+ | * schedule demos for Dave in weeks 3, 7, and 10 for 0.4, 0.6, and 0.8 releases. | ||
+ | * Demo 1 - Feb 4 (completed) | ||
+ | |||
+ | == Code Blocks == | ||
+ | Here is a list of code blocks I have written for the processing.js project<br /> | ||
+ | === trim() === | ||
+ | Trim leading and trailing whitespace from strings as well as tab characters, newlines, and nbsp characters<br/> | ||
+ | Commit [http://github.com/dhodgin/processing-js/commit/e7f258eec8f566a0da39c23f964280637e8e2a4b trim() commit]<br /> | ||
+ | Test available [http://matrix.senecac.on.ca/~dhhodgin/dps911/examples/seneca/trim/trimtest.htm here]<br /> | ||
+ | p.trim = function( str ) { | ||
+ | var newstr; | ||
+ | if (typeof str === "object") { | ||
+ | // if str is an array recursivly loop through each element | ||
+ | // and drill down into multiple arrays trimming whitespace | ||
+ | newstr = new Array(0); | ||
+ | for (var i = 0; i < str.length; i++) { | ||
+ | newstr[i] = p.trim(str[i]); | ||
+ | } | ||
+ | } else { | ||
+ | // if str is not an array then remove all whitespace, tabs, and returns | ||
+ | newstr = str.replace(/^\s*/,'').replace(/\s*$/,'').replace(/\r*$/,''); | ||
+ | } | ||
+ | return newstr; | ||
+ | }; | ||
+ | === decimalToHex() === | ||
+ | A helper function used with hex to convert a number passed in to hex and add any specified padding | ||
+ | |||
+ | var decimalToHex = function decimalToHex(d, padding) { | ||
+ | //if there is no padding value added, default padding to 8 else go into while statement. | ||
+ | padding = typeof(padding) === "undefined" || padding === null ? padding = 8 : padding; | ||
+ | if (d < 0) { | ||
+ | d = 0xFFFFFFFF + d + 1; | ||
+ | } | ||
+ | var hex = Number(d).toString(16).toUpperCase(); | ||
+ | while (hex.length < padding) { | ||
+ | hex = "0" + hex; | ||
+ | } | ||
+ | if (hex.length >= padding){ | ||
+ | hex = hex.substring(hex.length - padding, hex.length); | ||
+ | } | ||
+ | return hex; | ||
+ | }; | ||
+ | |||
+ | === hex() === | ||
+ | hex(x, y) function for processing. x is a byte, char, int, or color. y is the length of the string to return.<br /> | ||
+ | Commit [http://github.com/dhodgin/processing-js/commit/d51adccc9acfeb4fa286366c98e06a33ad296524 hex() commit]<br /> | ||
+ | Test available [http://matrix.senecac.on.ca/~dhhodgin/dps911/hextest.htm here]<br /> | ||
+ | <br /> | ||
+ | // note: since we cannot keep track of byte, char, and int types by default the returned string is 8 chars long | ||
+ | // if no 2nd argument is passed. closest compromise we can use to match java implementation Feb 5 2010 | ||
+ | // also the char parser has issues with chars that are not digits or letters IE: !@#$%^&* | ||
+ | p.hex = function hex(value, len) { | ||
+ | var hexstring = ""; | ||
+ | var patternRGBa = /^rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3})(,\d?\.?\d*)?\)$/i; //match rgba(20,20,20,0) or rgba(20,20,20) | ||
+ | if (arguments.length === 1) { | ||
+ | hexstring = hex(value, 8); | ||
+ | } else { | ||
+ | if (patternRGBa.test(value)) { | ||
+ | // its a color | ||
+ | hexstring = decimalToHex(p.rgbaToInt(value),len); | ||
+ | } else { | ||
+ | // its a byte, char, or int | ||
+ | hexstring = decimalToHex(value, len); | ||
+ | } | ||
+ | } | ||
+ | return hexstring; | ||
+ | }; | ||
+ | |||
+ | === copy() === | ||
+ | p.copy = function copy(src, sx, sy, sw, sh, dx, dy, dw, dh) { | ||
+ | if(arguments.length==8){ | ||
+ | p.copy(this, src, sx, sy, sw, sh, dx, dy, dw); | ||
+ | } | ||
+ | p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, p.REPLACE); | ||
+ | }; | ||
+ | |||
+ | === blend() === | ||
+ | p.blend = function blend(src, sx, sy, sw, sh, dx, dy, dw, dh, mode){ | ||
+ | if(arguments.length==9){ | ||
+ | p.blend(this, src, sx, sy, sw, sh, dx, dy, dw, dh); | ||
+ | } else if (arguments.length==10){ | ||
+ | var sx2 = sx + sw; | ||
+ | var sy2 = sy + sh; | ||
+ | var dx2 = dx + dw; | ||
+ | var dy2 = dy + dh; | ||
+ | p.loadPixels(); | ||
+ | if (src == this) { | ||
+ | if (p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) { | ||
+ | p.blit_resize(p.get(sx, sy, sx2 - sx, sy2 - sy), // 4 argument get doesnt exist i think | ||
+ | 0, 0, sx2 - sx - 1, sy2 - sy - 1, | ||
+ | pixels, width, height, dx, dy, dx2, dy2, mode); | ||
+ | } else { | ||
+ | // same as below, except skip the loadPixels() because it'd be redundant | ||
+ | p.blit_resize(src, sx, sy, sx2, sy2, pixels, width, height, dx, dy, dx2, dy2, mode); | ||
+ | } | ||
+ | } else { | ||
+ | src.loadPixels(); | ||
+ | p.blit_resize(src, sx, sy, sx2, sy2, pixels, width, height, dx, dy, dx2, dy2, mode); | ||
+ | } | ||
+ | p.updatePixels(); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | === blit_resize() === | ||
+ | blit_resize is a helper function for image manipulation used with blend() and copy() | ||
+ | |||
+ | /** | ||
+ | * Internal blitter/resizer/copier from toxi. | ||
+ | * Uses bilinear filtering if smooth() has been enabled | ||
+ | * 'mode' determines the blending mode used in the process. | ||
+ | * ported from JAVA version | ||
+ | */ | ||
+ | p.blit_resize = function blit_resize(img, srcX1, srcY1, srcX2, srcY2, destPixels, screenW, screenH, | ||
+ | destX1, destY1, destX2, destY2, mode) { | ||
+ | if (srcX1 < 0) srcX1 = 0; | ||
+ | if (srcY1 < 0) srcY1 = 0; | ||
+ | if (srcX2 >= img.width) srcX2 = img.width - 1; | ||
+ | if (srcY2 >= img.height) srcY2 = img.height - 1; | ||
+ | var srcW = srcX2 - srcX1; | ||
+ | var srcH = srcY2 - srcY1; | ||
+ | var destW = destX2 - destX1; | ||
+ | var destH = destY2 - destY1; | ||
+ | var smooth = true; // may as well go with the smoothing these days | ||
+ | if (!smooth) { | ||
+ | srcW++; srcH++; | ||
+ | } | ||
+ | if (destW <= 0 || destH <= 0 || | ||
+ | srcW <= 0 || srcH <= 0 || | ||
+ | destX1 >= screenW || destY1 >= screenH || | ||
+ | srcX1 >= img.width || srcY1 >= img.height) { | ||
+ | return; | ||
+ | } | ||
+ | var dx = Math.floor(srcW / destW * p.PRECISIONF); | ||
+ | var dy = Math.floor(srcH / destH * p.PRECISIONF); | ||
+ | p.shared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * p.PRECISIONF); | ||
+ | p.shared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * p.PRECISIONF); | ||
+ | if (destX1 < 0) { | ||
+ | destW += destX1; | ||
+ | destX1 = 0; | ||
+ | } | ||
+ | if (destY1 < 0) { | ||
+ | destH += destY1; | ||
+ | destY1 = 0; | ||
+ | } | ||
+ | destW = Math.min(destW, screenW - destX1); | ||
+ | destH = Math.min(destH, screenH - destY1); | ||
+ | var destOffset = destY1 * screenW + destX1; | ||
+ | p.shared.srcBuffer = img.pixels; | ||
+ | if (smooth) { | ||
+ | // use bilinear filtering | ||
+ | p.shared.iw = img.width; | ||
+ | p.shared.iw1 = img.width - 1; | ||
+ | p.shared.ih1 = img.height - 1; | ||
+ | switch (mode) { | ||
+ | case p.BLEND: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_blend(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | p.shared.srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.ADD: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_add_pin(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.SUBTRACT: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_sub_pin(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.LIGHTEST: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_lightest(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.DARKEST: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_darkest(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.REPLACE: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = p.filter_bilinear(); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.DIFFERENCE: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_difference(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.EXCLUSION: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_exclusion(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.MULTIPLY: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_multiply(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.SCREEN: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_screen(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.OVERLAY: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_overlay(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.HARD_LIGHT: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_hard_light(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.SOFT_LIGHT: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_soft_light(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | // davbol - proposed 2007-01-09 | ||
+ | case p.DODGE: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_dodge(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.BURN: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | p.filter_new_scanline(); | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_burn(destPixels[destOffset + x], p.filter_bilinear()); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | } else { | ||
+ | // nearest neighbour scaling (++fast!) | ||
+ | switch (mode) { | ||
+ | case p.BLEND: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | // davbol - renamed old blend_multiply to blend_blend | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_blend(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.ADD: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_add_pin(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.SUBTRACT: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_sub_pin(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.LIGHTEST: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_lightest(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.DARKEST: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_darkest(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.REPLACE: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = srcBuffer[sY + (sX >> p.PRECISIONB)]; | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.DIFFERENCE: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_difference(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.EXCLUSION: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_exclusion(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.MULTIPLY: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_multiply(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.SCREEN: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_screen(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.OVERLAY: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_overlay(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.HARD_LIGHT: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_hard_light(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.SOFT_LIGHT: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_soft_light(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | // davbol - proposed 2007-01-09 | ||
+ | case p.DODGE: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_dodge(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | case p.BURN: | ||
+ | for (var y = 0; y < destH; y++) { | ||
+ | sX = srcXOffset; | ||
+ | sY = (srcYOffset >> p.PRECISIONB) * img.width; | ||
+ | for (var x = 0; x < destW; x++) { | ||
+ | destPixels[destOffset + x] = | ||
+ | p.modes.blend_burn(destPixels[destOffset + x], | ||
+ | srcBuffer[sY + (sX >> p.PRECISIONB)]); | ||
+ | sX += dx; | ||
+ | } | ||
+ | destOffset += screenW; | ||
+ | srcYOffset += dy; | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | === blend() helper functions=== | ||
+ | |||
+ | // shared variables for blit_resize(), filter_new_scanline(), filter_bilinear() | ||
+ | // change this in the future | ||
+ | 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 | ||
+ | }; | ||
+ | p.intersect = function intersect(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) { | ||
+ | var sw = sx2 - sx1 + 1; | ||
+ | var sh = sy2 - sy1 + 1; | ||
+ | var dw = dx2 - dx1 + 1; | ||
+ | var dh = dy2 - dy1 + 1; | ||
+ | if (dx1 < sx1) { | ||
+ | dw += dx1 - sx1; | ||
+ | if (dw > sw) { | ||
+ | dw = sw; | ||
+ | } | ||
+ | } else { | ||
+ | var w = sw + sx1 - dx1; | ||
+ | if (dw > w) { | ||
+ | dw = w; | ||
+ | } | ||
+ | } | ||
+ | if (dy1 < sy1) { | ||
+ | dh += dy1 - sy1; | ||
+ | if (dh > sh) { | ||
+ | dh = sh; | ||
+ | } | ||
+ | } else { | ||
+ | var h = sh + sy1 - dy1; | ||
+ | if (dh > h) { | ||
+ | dh = h; | ||
+ | } | ||
+ | } | ||
+ | return !(dw <= 0 || dh <= 0); | ||
+ | }; | ||
+ | p.filter_new_scanline = function filter_new_scanline() { | ||
+ | p.shared.sX = p.shared.srcXOffset; | ||
+ | p.shared.fracV = p.shared.srcYOffset & p.PREC_MAXVAL; | ||
+ | p.shared.ifV = p.PREC_MAXVAL - p.shared.fracV; | ||
+ | p.shared.v1 = (p.shared.srcYOffset >> p.PRECISIONB) * p.shared.iw; | ||
+ | p.shared.v2 = Math.min((p.shared.srcYOffset >> p.PRECISIONB) + 1, p.shared.ih1) * p.shared.iw; | ||
+ | }; | ||
+ | p.filter_bilinear = function filter_bilinear() { | ||
+ | p.shared.fracU = p.shared.sX & p.PREC_MAXVAL; | ||
+ | p.shared.ifU = p.PREC_MAXVAL - p.shared.fracU; | ||
+ | p.shared.ul = (p.shared.ifU * p.shared.ifV) >> p.PRECISIONB; | ||
+ | p.shared.ll = (p.shared.ifU * p.shared.fracV) >> p.PRECISIONB; | ||
+ | p.shared.ur = (p.shared.fracU * p.shared.ifV) >> p.PRECISIONB; | ||
+ | p.shared.lr = (p.shared.fracU * p.shared.fracV) >> p.PRECISIONB; | ||
+ | p.shared.u1 = (p.shared.sX >> p.PRECISIONB); | ||
+ | p.shared.u2 = Math.min(p.shared.u1 + 1, p.shared.iw1); | ||
+ | // get color values of the 4 neighbouring texels | ||
+ | p.shared.cUL = p.shared.srcBuffer[p.shared.v1 + p.shared.u1]; | ||
+ | p.shared.cUR = p.shared.srcBuffer[p.shared.v1 + p.shared.u2]; | ||
+ | p.shared.cLL = p.shared.srcBuffer[p.shared.v2 + p.shared.u1]; | ||
+ | p.shared.cLR = p.shared.srcBuffer[p.shared.v2 + p.shared.u2]; | ||
+ | p.shared.r = ((p.shared.ul*((p.shared.cUL&p.RED_MASK)>>16) + p.shared.ll*((p.shared.cLL&p.RED_MASK)>>16) + | ||
+ | p.shared.ur*((p.shared.cUR&p.RED_MASK)>>16) + p.shared.lr*((p.shared.cLR&p.RED_MASK)>>16)) | ||
+ | << p.PREC_RED_SHIFT) & p.RED_MASK; | ||
+ | p.shared.g = ((p.shared.ul*(p.shared.cUL&p.GREEN_MASK) + p.shared.ll*(p.shared.cLL&p.GREEN_MASK) + | ||
+ | p.shared.ur*(p.shared.cUR&p.GREEN_MASK) + p.shared.lr*(p.shared.cLR&p.GREEN_MASK)) | ||
+ | >>> p.PRECISIONB) & p.GREEN_MASK; | ||
+ | p.shared.b = (p.shared.ul*(p.shared.cUL&p.BLUE_MASK) + p.shared.ll*(p.shared.cLL&p.BLUE_MASK) + | ||
+ | p.shared.ur*(p.shared.cUR&p.BLUE_MASK) + p.shared.lr*(p.shared.cLR&p.BLUE_MASK)) | ||
+ | >>> p.PRECISIONB; | ||
+ | p.shared.a = ((p.shared.ul*((p.shared.cUL&p.ALPHA_MASK)>>>24) + p.shared.ll*((p.shared.cLL&p.ALPHA_MASK)>>>24) + | ||
+ | p.shared.ur*((p.shared.cUR&p.ALPHA_MASK)>>>24) + p.shared.lr*((p.shared.cLR&p.ALPHA_MASK)>>>24)) | ||
+ | << p.PREC_ALPHA_SHIFT) & p.ALPHA_MASK; | ||
+ | return p.shared.a | p.shared.r | p.shared.g | p.shared.b; | ||
+ | }; | ||
+ | |||
+ | === CONSTANTS ADDED === | ||
+ | p.ALPHA_MASK = 0xff000000; | ||
+ | p.RED_MASK = 0x00ff0000; | ||
+ | p.GREEN_MASK = 0x0000ff00; | ||
+ | p.BLUE_MASK = 0x000000ff; | ||
+ | p.REPLACE = 0; | ||
+ | p.BLEND = 1 << 0; | ||
+ | p.ADD = 1 << 1; | ||
+ | p.SUBTRACT = 1 << 2; | ||
+ | p.LIGHTEST = 1 << 3; | ||
+ | p.DARKEST = 1 << 4; | ||
+ | p.DIFFERENCE = 1 << 5; | ||
+ | p.EXCLUSION = 1 << 6; | ||
+ | p.MULTIPLY = 1 << 7; | ||
+ | p.SCREEN = 1 << 8; | ||
+ | p.OVERLAY = 1 << 9; | ||
+ | p.HARD_LIGHT = 1 << 10; | ||
+ | p.SOFT_LIGHT = 1 << 11; | ||
+ | p.DODGE = 1 << 12; | ||
+ | p.BURN = 1 << 13; | ||
+ | // fixed point precision is limited to 15 bits!! | ||
+ | p.PRECISIONB = 15; | ||
+ | p.PRECISIONF = 1 << p.PRECISIONB; | ||
+ | p.PREC_MAXVAL = p.PRECISIONF-1; | ||
+ | p.PREC_ALPHA_SHIFT= 24-p.PRECISIONB; | ||
+ | p.PREC_RED_SHIFT = 16-p.PRECISIONB; | ||
+ | |||
+ | === blendColor() === | ||
+ | p.blendColor = function(c1, c2, mode){ | ||
+ | var color = 0; | ||
+ | switch(mode){ | ||
+ | case p.REPLACE : color = p.modes.replace(c1, c2); break; | ||
+ | case p.BLEND : color = p.modes.blend(c1, c2); break; | ||
+ | case p.ADD : color = p.modes.add(c1, c2); break; | ||
+ | case p.SUBTRACT : color = p.modes.subtract(c1, c2); break; | ||
+ | case p.LIGHTEST : color = p.modes.lightest(c1, c2); break; | ||
+ | case p.DARKEST : color = p.modes.darkest(c1, c2); break; | ||
+ | case p.DIFFERENCE : color = p.modes.difference(c1, c2); break; | ||
+ | case p.EXCLUSION : color = p.modes.exclusion(c1, c2); break; | ||
+ | case p.MULTIPLY : color = p.modes.multiply(c1, c2); break; | ||
+ | case p.SCREEN : color = p.modes.screen(c1, c2); break; | ||
+ | case p.HARD_LIGHT : color = p.modes.hard_light(c1, c2); break; | ||
+ | case p.SOFT_LIGHT : color = p.modes.soft_light(c1, c2); break; | ||
+ | case p.OVERLAY : color = p.modes.overlay(c1, c2); break; | ||
+ | case p.DODGE : color = p.modes.dodge(c1, c2); break; | ||
+ | case p.BURN : color = p.modes.burn(c1, c2); break; | ||
+ | } | ||
+ | return color; | ||
+ | } | ||
+ | === blendColor() helper functions === | ||
+ | // helper functions for internal blending modes | ||
+ | // convert rgba color strings to integer | ||
+ | p.rgbaToInt = function(color){ | ||
+ | var rgbaAry = /\(([^\)]+)\)/.exec(color).slice(1,2)[0].split(','); | ||
+ | return (rgbaAry[3] << 24) | (rgbaAry[0] << 16) | (rgbaAry[1] << 8) | (rgbaAry[2]); | ||
+ | } | ||
+ | p.mix = function(a, b, f) { | ||
+ | return a + (((b - a) * f) >> 8); | ||
+ | } | ||
+ | p.peg = function(n) { | ||
+ | return (n < 0) ? 0 : ((n > 255) ? 255 : n); | ||
+ | } | ||
+ | === blendColor() blending modes === | ||
+ | // blending modes | ||
+ | p.modes = { | ||
+ | replace: function(a, b){ | ||
+ | return p.rgbaToInt(b); | ||
+ | }, | ||
+ | blend: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | p.mix(c1 & p.RED_MASK, c2 & p.RED_MASK, f) & p.RED_MASK | | ||
+ | p.mix(c1 & p.GREEN_MASK, c2 & p.GREEN_MASK, f) & p.GREEN_MASK | | ||
+ | p.mix(c1 & p.BLUE_MASK, c2 & p.BLUE_MASK, f)); | ||
+ | }, | ||
+ | add: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | Math.min(((c1 & p.RED_MASK) + | ||
+ | ((c2 & p.RED_MASK) >> 8) * f), p.RED_MASK) & p.RED_MASK | | ||
+ | Math.min(((c1 & p.GREEN_MASK) + | ||
+ | ((c2 & p.GREEN_MASK) >> 8) * f), p.GREEN_MASK) & p.GREEN_MASK | | ||
+ | Math.min((c1 & p.BLUE_MASK) + | ||
+ | (((c2 & p.BLUE_MASK) * f) >> 8), p.BLUE_MASK)); | ||
+ | }, | ||
+ | subtract: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | Math.max(((c1 & p.RED_MASK) - ((c2 & p.RED_MASK) >> 8) * f), | ||
+ | p.GREEN_MASK) & p.RED_MASK | | ||
+ | Math.max(((c1 & p.GREEN_MASK) - ((c2 & p.GREEN_MASK) >> 8) * f), | ||
+ | p.BLUE_MASK) & p.GREEN_MASK | | ||
+ | Math.max((c1 & p.BLUE_MASK) - (((c2 & p.BLUE_MASK) * f) >> 8), 0)); | ||
+ | }, | ||
+ | lightest: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | Math.max(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f) & p.RED_MASK | | ||
+ | Math.max(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f) & p.GREEN_MASK | | ||
+ | Math.max(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8)); | ||
+ | }, | ||
+ | darkest: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | p.mix(c1 & p.RED_MASK, | ||
+ | Math.min(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f), f) & p.RED_MASK | | ||
+ | p.mix(c1 & p.GREEN_MASK, | ||
+ | Math.min(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f), f) & p.GREEN_MASK | | ||
+ | p.mix(c1 & p.BLUE_MASK, | ||
+ | Math.min(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8), f)); | ||
+ | }, | ||
+ | difference: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = (ar > br) ? (ar-br) : (br-ar); | ||
+ | var cg = (ag > bg) ? (ag-bg) : (bg-ag); | ||
+ | var cb = (ab > bb) ? (ab-bb) : (bb-ab); | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | exclusion: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = ar + br - ((ar * br) >> 7); | ||
+ | var cg = ag + bg - ((ag * bg) >> 7); | ||
+ | var cb = ab + bb - ((ab * bb) >> 7); | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | multiply: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = (ar * br) >> 8; | ||
+ | var cg = (ag * bg) >> 8; | ||
+ | var cb = (ab * bb) >> 8; | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | screen: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = 255 - (((255 - ar) * (255 - br)) >> 8); | ||
+ | var cg = 255 - (((255 - ag) * (255 - bg)) >> 8); | ||
+ | var cb = 255 - (((255 - ab) * (255 - bb)) >> 8); | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | hard_light: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = (br < 128) ? ((ar*br)>>7) : (255-(((255-ar)*(255-br))>>7)); | ||
+ | var cg = (bg < 128) ? ((ag*bg)>>7) : (255-(((255-ag)*(255-bg))>>7)); | ||
+ | var cb = (bb < 128) ? ((ab*bb)>>7) : (255-(((255-ab)*(255-bb))>>7)); | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | soft_light: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = ((ar*br)>>7) + ((ar*ar)>>8) - ((ar*ar*br)>>15); | ||
+ | var cg = ((ag*bg)>>7) + ((ag*ag)>>8) - ((ag*ag*bg)>>15); | ||
+ | var cb = ((ab*bb)>>7) + ((ab*ab)>>8) - ((ab*ab*bb)>>15); | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | overlay: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = (ar < 128) ? ((ar*br)>>7) : (255-(((255-ar)*(255-br))>>7)); | ||
+ | var cg = (ag < 128) ? ((ag*bg)>>7) : (255-(((255-ag)*(255-bg))>>7)); | ||
+ | var cb = (ab < 128) ? ((ab*bb)>>7) : (255-(((255-ab)*(255-bb))>>7)); | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | dodge: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = (br==255) ? 255 : p.peg((ar << 8) / (255 - br)); // division requires pre-peg()-ing | ||
+ | var cg = (bg==255) ? 255 : p.peg((ag << 8) / (255 - bg)); // " | ||
+ | var cb = (bb==255) ? 255 : p.peg((ab << 8) / (255 - bb)); // " | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | }, | ||
+ | burn: function(a, b){ | ||
+ | var c1 = p.rgbaToInt(a); | ||
+ | var c2 = p.rgbaToInt(b); | ||
+ | var f = (c2 & p.ALPHA_MASK) >>> 24; | ||
+ | var ar = (c1 & p.RED_MASK) >> 16; | ||
+ | var ag = (c1 & p.GREEN_MASK) >> 8; | ||
+ | var ab = (c1 & p.BLUE_MASK); | ||
+ | var br = (c2 & p.RED_MASK) >> 16; | ||
+ | var bg = (c2 & p.GREEN_MASK) >> 8; | ||
+ | var bb = (c2 & p.BLUE_MASK); | ||
+ | // formula: | ||
+ | var cr = (br==0) ? 0 : 255 - p.peg(((255 - ar) << 8) / br); // division requires pre-peg()-ing | ||
+ | var cg = (bg==0) ? 0 : 255 - p.peg(((255 - ag) << 8) / bg); // " | ||
+ | var cb = (bb==0) ? 0 : 255 - p.peg(((255 - ab) << 8) / bb); // " | ||
+ | // alpha blend (this portion will always be the same) | ||
+ | return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | | ||
+ | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | | ||
+ | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | | ||
+ | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); | ||
+ | } | ||
+ | }; | ||
+ | === screen === | ||
+ | p.screen = { | ||
+ | width:screen.width, | ||
+ | height:screen.height | ||
+ | } | ||
+ | === log() === | ||
+ | p.log = function( num ) { | ||
+ | return Math.log(num > 0 ? num : 0); | ||
+ | } | ||
+ | === exp() === | ||
+ | p.exp = function( num ){ | ||
+ | return Math.exp(num > 0 ? num : 0); | ||
+ | } | ||
+ | === asin() === | ||
+ | p.asin = function( num ){ | ||
+ | return Math.asin(num); | ||
+ | } | ||
+ | === acos() === | ||
+ | p.acos = function( num ){ | ||
+ | return Math.acos(num); | ||
+ | } | ||
+ | === atan() === | ||
+ | p.atan = function( num ){ | ||
+ | return Math.atan(num); | ||
+ | } | ||
+ | === tan() === | ||
+ | p.tan = function( num ){ | ||
+ | return Math.tan(num); | ||
+ | } | ||
+ | === map() === | ||
+ | p.map = function( value, low1, high1, low2, high2 ){ | ||
+ | return (((value-low1)/(high1-low1))*(high2-low2))+low2; | ||
+ | } | ||
+ | === nfc() === | ||
Specification for nfc() in processing [http://processing.org/reference/nfc_.html here].<br /> | Specification for nfc() in processing [http://processing.org/reference/nfc_.html here].<br /> | ||
nfc() is a function used to format numbers with commas every 3rd digit and optionally how many decimal places to show right of the decimal place. It accepts int, int[], float, and float[] types and returns either a single string or array of strings depending on the input. | nfc() is a function used to format numbers with commas every 3rd digit and optionally how many decimal places to show right of the decimal place. It accepts int, int[], float, and float[] types and returns either a single string or array of strings depending on the input. | ||
Line 87: | Line 1,110: | ||
Example of this function and test is [http://matrix.senecac.on.ca/~dhhodgin/dps909/nfc_test.htm here].<br /> | Example of this function and test is [http://matrix.senecac.on.ca/~dhhodgin/dps909/nfc_test.htm here].<br /> | ||
'''Known issues:''' None. | '''Known issues:''' None. | ||
− | + | === shorten() === | |
Specification for shorten() in processing [http://processing.org/reference/shorten_.html here].<br /> | Specification for shorten() in processing [http://processing.org/reference/shorten_.html here].<br /> | ||
Arrays in JS have no type, the elements in them can contain any type and do not all have to match. Arrays are also passed by reference which means a reference to the object is passed in not the entire object. so my code creates a new array and then copies the passed in array first and then pops one element off the new array and the newary object is returned. This is built to accept a processing type of String, int, boolean, char, byte, and float. Support for arrays of objects will be added in 0.2. | Arrays in JS have no type, the elements in them can contain any type and do not all have to match. Arrays are also passed by reference which means a reference to the object is passed in not the entire object. so my code creates a new array and then copies the passed in array first and then pops one element off the new array and the newary object is returned. This is built to accept a processing type of String, int, boolean, char, byte, and float. Support for arrays of objects will be added in 0.2. | ||
Line 104: | Line 1,127: | ||
'''Known issues:''' This has not been tested with arrays of objects. I'm assuming it will copy object elements in an array by reference and not produce a proper deep copy. I plan to fix this by 0.2. (confirmed, needs deep copy support for arrays of objects). | '''Known issues:''' This has not been tested with arrays of objects. I'm assuming it will copy object elements in an array by reference and not produce a proper deep copy. I plan to fix this by 0.2. (confirmed, needs deep copy support for arrays of objects). | ||
− | + | === expand() === | |
Specification for expand() in processing [http://processing.org/reference/expand_.html here].<br /> | Specification for expand() in processing [http://processing.org/reference/expand_.html here].<br /> | ||
Expand takes an array as its argument and returns a copy of the array with its length doubled. There is an optional 2nd parameter to specify the new size of the array as well. | Expand takes an array as its argument and returns a copy of the array with its length doubled. There is an optional 2nd parameter to specify the new size of the array as well. | ||
Line 127: | Line 1,150: | ||
'''Known issues:''' Not yet tested with arrays of objects. | '''Known issues:''' Not yet tested with arrays of objects. | ||
− | + | === unhex() === | |
Specification for unhex() in processing [http://processing.org/reference/unhex_.html here].<br /> | Specification for unhex() in processing [http://processing.org/reference/unhex_.html here].<br /> | ||
unhex takes a string representing a 8 digit hex code as its only argument and returns an int representation of the string. JavaScript supports 64 bit floats as var's so it took a little number crunching to make it output an exact replication of the Java implementation with signed int's. | unhex takes a string representing a 8 digit hex code as its only argument and returns an int representation of the string. JavaScript supports 64 bit floats as var's so it took a little number crunching to make it output an exact replication of the Java implementation with signed int's. | ||
Line 177: | Line 1,200: | ||
'''Known issues:''' None. | '''Known issues:''' None. | ||
− | + | === nfs() === | |
Specification for nfs() in processing [http://processing.org/reference/nfs_.html here].<br /> | Specification for nfs() in processing [http://processing.org/reference/nfs_.html here].<br /> | ||
nfs() is a function used to format numbers as strings with padding of 0's on either the left or right of the decimal place. It accepts int, int[], float, and float[] types and returns either a single string or array of strings depending on the input. | nfs() is a function used to format numbers as strings with padding of 0's on either the left or right of the decimal place. It accepts int, int[], float, and float[] types and returns either a single string or array of strings depending on the input. | ||
Line 227: | Line 1,250: | ||
Example of this function and test is [http://matrix.senecac.on.ca/~dhhodgin/dps909/nfs_test.htm here].<br /> | Example of this function and test is [http://matrix.senecac.on.ca/~dhhodgin/dps909/nfs_test.htm here].<br /> | ||
'''Known issues:''' None. | '''Known issues:''' None. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |
Latest revision as of 07:10, 30 September 2010
Contents
- 1 Contact Information
- 2 About Me
- 3 Technical Qualifications
- 4 FSOSS Research Paper
- 5 DPS909 Projects
- 6 DPS911 Projects
- 7 Code Blocks
- 7.1 trim()
- 7.2 decimalToHex()
- 7.3 hex()
- 7.4 copy()
- 7.5 blend()
- 7.6 blit_resize()
- 7.7 blend() helper functions
- 7.8 CONSTANTS ADDED
- 7.9 blendColor()
- 7.10 blendColor() helper functions
- 7.11 blendColor() blending modes
- 7.12 screen
- 7.13 log()
- 7.14 exp()
- 7.15 asin()
- 7.16 acos()
- 7.17 atan()
- 7.18 tan()
- 7.19 map()
- 7.20 nfc()
- 7.21 shorten()
- 7.22 expand()
- 7.23 unhex()
- 7.24 nfs()
Contact Information
Name | Daniel Hodgin |
dhhodgin [AT] learn [DOT] senecac [DOT] on [DOT] ca | |
Email2 | hodgin.daniel [AT] gmail [DOT] com |
IRC | dhodgin |
BLOG | blog |
About Me
I'm a 7th Semester BSD student taking DPS901. Working part time on an ASP.NET c# application.
Technical Qualifications
Programming Languages
- C
- C++
- C#
- Java
- PHP/PERL
- SQL
- XHTML/CSS
- JavaScript
- Processing
FSOSS Research Paper
DPS909 Projects
[Processing.js] - Active project
[Fennec and @font-face] - on hold
Releases
0.1 - Full Details shorten(), expand(), nfs(), unhex(), bug fixes on nf() and fill()
0.2 - Full Details nfc(), exp(), log(), map(), asin(), acos(), atan(), tan()
0.3 - Full Details blendColor(), blend(), copy(), filter()
Contributions
- Wrote shorten() to help out Andor with his workload.
- Created the template for processing.js tests
- Organized 0.1 release code table and project test table areas.
- Wrote GIT tutorial on adding code to GIT from a fresh fork tutorial
- Helped Al get Lighthouse setup and got invites sent out to everyone to better prepare for 0.2 release code and bug tracking
- Wrote tutorial on lighthouse, and ticket state explanations messages
- Helped with triage on lighthouse tickets
- Helped Anna with PImage copy math which will ultimately be used in my 0.3 copy() code
Week 1 stuff
- Create Zenit Wiki (done)
- Create Blog (done)
- Blog on introductory readings (done)
- Listen in on a Weekly Call (done)
- Update wiki (done)
Week 2 stuff
- Create MDC account (done)
- join Mozilla Fennec mailing list (done)
- week 2 lab (done)
- watch learning to be at the festival and blog about it (done)
Week 3 stuff
- watch online lectures about build system by Paul Reed (done)
- build Firefox at school on Linux (fedora) (done)
- build Firefox minefield at home on windows 7 (done)
- choose subject for project and write project plan on blog (done)
Week 4 stuff
- spend time searching through MXR and familiarizing myself with it (done)
- lab, working with patches (to do)
Week 5 stuff
- create Bugzilla account (done)
- Find 3+ bugs related to your project, and add them to your project wiki page (done)
- CC yourself on two bugs that relate to your project 517086 476478 (done)
- Watch a user in Bugzilla for the week and blog about the experience (blassey) (done)
- Be working on your 0.1 release. Ask for help if you're stuck (done)
- Register for FSOSS or join as a volunteer. (done)
Week 6 stuff
- work on 0.1 release (done)
Week 7 stuff
- Firefox tab ordering lab
- Watch JavaScript online talk (done)
Week 8 stuff
- Release 0.2 (done)
Week 9 stuff
- tba
DPS911 Projects
[Processing.js] - Active project
Releases
0.4 - Full Details Triage and peer-review of outstanding 0.2 and 0.3 code
0.5 - Full Details Review of binary() and sort(), rewrote hex(), trim(), some code efficiency cleanup
0.6 - wip
Weekly stuff
- Update Wiki
- Prepare for 0.4 release
- schedule demos for Dave in weeks 3, 7, and 10 for 0.4, 0.6, and 0.8 releases.
- Demo 1 - Feb 4 (completed)
Code Blocks
Here is a list of code blocks I have written for the processing.js project
trim()
Trim leading and trailing whitespace from strings as well as tab characters, newlines, and nbsp characters
Commit trim() commit
Test available here
p.trim = function( str ) { var newstr; if (typeof str === "object") { // if str is an array recursivly loop through each element // and drill down into multiple arrays trimming whitespace newstr = new Array(0); for (var i = 0; i < str.length; i++) { newstr[i] = p.trim(str[i]); } } else { // if str is not an array then remove all whitespace, tabs, and returns newstr = str.replace(/^\s*/,).replace(/\s*$/,).replace(/\r*$/,); } return newstr; };
decimalToHex()
A helper function used with hex to convert a number passed in to hex and add any specified padding
var decimalToHex = function decimalToHex(d, padding) { //if there is no padding value added, default padding to 8 else go into while statement. padding = typeof(padding) === "undefined" || padding === null ? padding = 8 : padding; if (d < 0) { d = 0xFFFFFFFF + d + 1; } var hex = Number(d).toString(16).toUpperCase(); while (hex.length < padding) { hex = "0" + hex; } if (hex.length >= padding){ hex = hex.substring(hex.length - padding, hex.length); } return hex; };
hex()
hex(x, y) function for processing. x is a byte, char, int, or color. y is the length of the string to return.
Commit hex() commit
Test available here
// note: since we cannot keep track of byte, char, and int types by default the returned string is 8 chars long // if no 2nd argument is passed. closest compromise we can use to match java implementation Feb 5 2010 // also the char parser has issues with chars that are not digits or letters IE: !@#$%^&* p.hex = function hex(value, len) { var hexstring = ""; var patternRGBa = /^rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3})(,\d?\.?\d*)?\)$/i; //match rgba(20,20,20,0) or rgba(20,20,20) if (arguments.length === 1) { hexstring = hex(value, 8); } else { if (patternRGBa.test(value)) { // its a color hexstring = decimalToHex(p.rgbaToInt(value),len); } else { // its a byte, char, or int hexstring = decimalToHex(value, len); } } return hexstring; };
copy()
p.copy = function copy(src, sx, sy, sw, sh, dx, dy, dw, dh) { if(arguments.length==8){ p.copy(this, src, sx, sy, sw, sh, dx, dy, dw); } p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, p.REPLACE); };
blend()
p.blend = function blend(src, sx, sy, sw, sh, dx, dy, dw, dh, mode){ if(arguments.length==9){ p.blend(this, src, sx, sy, sw, sh, dx, dy, dw, dh); } else if (arguments.length==10){ var sx2 = sx + sw; var sy2 = sy + sh; var dx2 = dx + dw; var dy2 = dy + dh; p.loadPixels(); if (src == this) { if (p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) { p.blit_resize(p.get(sx, sy, sx2 - sx, sy2 - sy), // 4 argument get doesnt exist i think 0, 0, sx2 - sx - 1, sy2 - sy - 1, pixels, width, height, dx, dy, dx2, dy2, mode); } else { // same as below, except skip the loadPixels() because it'd be redundant p.blit_resize(src, sx, sy, sx2, sy2, pixels, width, height, dx, dy, dx2, dy2, mode); } } else { src.loadPixels(); p.blit_resize(src, sx, sy, sx2, sy2, pixels, width, height, dx, dy, dx2, dy2, mode); } p.updatePixels(); } };
blit_resize()
blit_resize is a helper function for image manipulation used with blend() and copy()
/** * Internal blitter/resizer/copier from toxi. * Uses bilinear filtering if smooth() has been enabled * 'mode' determines the blending mode used in the process. * ported from JAVA version */ p.blit_resize = function blit_resize(img, srcX1, srcY1, srcX2, srcY2, destPixels, screenW, screenH, destX1, destY1, destX2, destY2, mode) { if (srcX1 < 0) srcX1 = 0; if (srcY1 < 0) srcY1 = 0; if (srcX2 >= img.width) srcX2 = img.width - 1; if (srcY2 >= img.height) srcY2 = img.height - 1; var srcW = srcX2 - srcX1; var srcH = srcY2 - srcY1; var destW = destX2 - destX1; var destH = destY2 - destY1; var smooth = true; // may as well go with the smoothing these days if (!smooth) { srcW++; srcH++; } if (destW <= 0 || destH <= 0 || srcW <= 0 || srcH <= 0 || destX1 >= screenW || destY1 >= screenH || srcX1 >= img.width || srcY1 >= img.height) { return; } var dx = Math.floor(srcW / destW * p.PRECISIONF); var dy = Math.floor(srcH / destH * p.PRECISIONF); p.shared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * p.PRECISIONF); p.shared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * p.PRECISIONF); if (destX1 < 0) { destW += destX1; destX1 = 0; } if (destY1 < 0) { destH += destY1; destY1 = 0; } destW = Math.min(destW, screenW - destX1); destH = Math.min(destH, screenH - destY1); var destOffset = destY1 * screenW + destX1; p.shared.srcBuffer = img.pixels; if (smooth) { // use bilinear filtering p.shared.iw = img.width; p.shared.iw1 = img.width - 1; p.shared.ih1 = img.height - 1; switch (mode) { case p.BLEND: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_blend(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; p.shared.srcYOffset += dy; } break; case p.ADD: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_add_pin(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.SUBTRACT: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_sub_pin(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.LIGHTEST: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_lightest(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.DARKEST: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_darkest(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.REPLACE: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.filter_bilinear(); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.DIFFERENCE: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_difference(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.EXCLUSION: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_exclusion(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.MULTIPLY: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_multiply(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.SCREEN: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_screen(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.OVERLAY: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_overlay(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.HARD_LIGHT: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_hard_light(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.SOFT_LIGHT: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_soft_light(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; // davbol - proposed 2007-01-09 case p.DODGE: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_dodge(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.BURN: for (var y = 0; y < destH; y++) { p.filter_new_scanline(); for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_burn(destPixels[destOffset + x], p.filter_bilinear()); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; } } else { // nearest neighbour scaling (++fast!) switch (mode) { case p.BLEND: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { // davbol - renamed old blend_multiply to blend_blend destPixels[destOffset + x] = p.modes.blend_blend(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.ADD: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_add_pin(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.SUBTRACT: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_sub_pin(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.LIGHTEST: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_lightest(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.DARKEST: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_darkest(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.REPLACE: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = srcBuffer[sY + (sX >> p.PRECISIONB)]; sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.DIFFERENCE: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_difference(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.EXCLUSION: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_exclusion(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.MULTIPLY: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_multiply(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.SCREEN: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_screen(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.OVERLAY: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_overlay(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.HARD_LIGHT: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_hard_light(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.SOFT_LIGHT: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_soft_light(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; // davbol - proposed 2007-01-09 case p.DODGE: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_dodge(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; case p.BURN: for (var y = 0; y < destH; y++) { sX = srcXOffset; sY = (srcYOffset >> p.PRECISIONB) * img.width; for (var x = 0; x < destW; x++) { destPixels[destOffset + x] = p.modes.blend_burn(destPixels[destOffset + x], srcBuffer[sY + (sX >> p.PRECISIONB)]); sX += dx; } destOffset += screenW; srcYOffset += dy; } break; } } };
blend() helper functions
// shared variables for blit_resize(), filter_new_scanline(), filter_bilinear() // change this in the future 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 }; p.intersect = function intersect(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) { var sw = sx2 - sx1 + 1; var sh = sy2 - sy1 + 1; var dw = dx2 - dx1 + 1; var dh = dy2 - dy1 + 1; if (dx1 < sx1) { dw += dx1 - sx1; if (dw > sw) { dw = sw; } } else { var w = sw + sx1 - dx1; if (dw > w) { dw = w; } } if (dy1 < sy1) { dh += dy1 - sy1; if (dh > sh) { dh = sh; } } else { var h = sh + sy1 - dy1; if (dh > h) { dh = h; } } return !(dw <= 0 || dh <= 0); }; p.filter_new_scanline = function filter_new_scanline() { p.shared.sX = p.shared.srcXOffset; p.shared.fracV = p.shared.srcYOffset & p.PREC_MAXVAL; p.shared.ifV = p.PREC_MAXVAL - p.shared.fracV; p.shared.v1 = (p.shared.srcYOffset >> p.PRECISIONB) * p.shared.iw; p.shared.v2 = Math.min((p.shared.srcYOffset >> p.PRECISIONB) + 1, p.shared.ih1) * p.shared.iw; }; p.filter_bilinear = function filter_bilinear() { p.shared.fracU = p.shared.sX & p.PREC_MAXVAL; p.shared.ifU = p.PREC_MAXVAL - p.shared.fracU; p.shared.ul = (p.shared.ifU * p.shared.ifV) >> p.PRECISIONB; p.shared.ll = (p.shared.ifU * p.shared.fracV) >> p.PRECISIONB; p.shared.ur = (p.shared.fracU * p.shared.ifV) >> p.PRECISIONB; p.shared.lr = (p.shared.fracU * p.shared.fracV) >> p.PRECISIONB; p.shared.u1 = (p.shared.sX >> p.PRECISIONB); p.shared.u2 = Math.min(p.shared.u1 + 1, p.shared.iw1); // get color values of the 4 neighbouring texels p.shared.cUL = p.shared.srcBuffer[p.shared.v1 + p.shared.u1]; p.shared.cUR = p.shared.srcBuffer[p.shared.v1 + p.shared.u2]; p.shared.cLL = p.shared.srcBuffer[p.shared.v2 + p.shared.u1]; p.shared.cLR = p.shared.srcBuffer[p.shared.v2 + p.shared.u2]; p.shared.r = ((p.shared.ul*((p.shared.cUL&p.RED_MASK)>>16) + p.shared.ll*((p.shared.cLL&p.RED_MASK)>>16) + p.shared.ur*((p.shared.cUR&p.RED_MASK)>>16) + p.shared.lr*((p.shared.cLR&p.RED_MASK)>>16)) << p.PREC_RED_SHIFT) & p.RED_MASK; p.shared.g = ((p.shared.ul*(p.shared.cUL&p.GREEN_MASK) + p.shared.ll*(p.shared.cLL&p.GREEN_MASK) + p.shared.ur*(p.shared.cUR&p.GREEN_MASK) + p.shared.lr*(p.shared.cLR&p.GREEN_MASK)) >>> p.PRECISIONB) & p.GREEN_MASK; p.shared.b = (p.shared.ul*(p.shared.cUL&p.BLUE_MASK) + p.shared.ll*(p.shared.cLL&p.BLUE_MASK) + p.shared.ur*(p.shared.cUR&p.BLUE_MASK) + p.shared.lr*(p.shared.cLR&p.BLUE_MASK)) >>> p.PRECISIONB; p.shared.a = ((p.shared.ul*((p.shared.cUL&p.ALPHA_MASK)>>>24) + p.shared.ll*((p.shared.cLL&p.ALPHA_MASK)>>>24) + p.shared.ur*((p.shared.cUR&p.ALPHA_MASK)>>>24) + p.shared.lr*((p.shared.cLR&p.ALPHA_MASK)>>>24)) << p.PREC_ALPHA_SHIFT) & p.ALPHA_MASK; return p.shared.a | p.shared.r | p.shared.g | p.shared.b; };
CONSTANTS ADDED
p.ALPHA_MASK = 0xff000000; p.RED_MASK = 0x00ff0000; p.GREEN_MASK = 0x0000ff00; p.BLUE_MASK = 0x000000ff; p.REPLACE = 0; p.BLEND = 1 << 0; p.ADD = 1 << 1; p.SUBTRACT = 1 << 2; p.LIGHTEST = 1 << 3; p.DARKEST = 1 << 4; p.DIFFERENCE = 1 << 5; p.EXCLUSION = 1 << 6; p.MULTIPLY = 1 << 7; p.SCREEN = 1 << 8; p.OVERLAY = 1 << 9; p.HARD_LIGHT = 1 << 10; p.SOFT_LIGHT = 1 << 11; p.DODGE = 1 << 12; p.BURN = 1 << 13; // fixed point precision is limited to 15 bits!! p.PRECISIONB = 15; p.PRECISIONF = 1 << p.PRECISIONB; p.PREC_MAXVAL = p.PRECISIONF-1; p.PREC_ALPHA_SHIFT= 24-p.PRECISIONB; p.PREC_RED_SHIFT = 16-p.PRECISIONB;
blendColor()
p.blendColor = function(c1, c2, mode){ var color = 0; switch(mode){ case p.REPLACE : color = p.modes.replace(c1, c2); break; case p.BLEND : color = p.modes.blend(c1, c2); break; case p.ADD : color = p.modes.add(c1, c2); break; case p.SUBTRACT : color = p.modes.subtract(c1, c2); break; case p.LIGHTEST : color = p.modes.lightest(c1, c2); break; case p.DARKEST : color = p.modes.darkest(c1, c2); break; case p.DIFFERENCE : color = p.modes.difference(c1, c2); break; case p.EXCLUSION : color = p.modes.exclusion(c1, c2); break; case p.MULTIPLY : color = p.modes.multiply(c1, c2); break; case p.SCREEN : color = p.modes.screen(c1, c2); break; case p.HARD_LIGHT : color = p.modes.hard_light(c1, c2); break; case p.SOFT_LIGHT : color = p.modes.soft_light(c1, c2); break; case p.OVERLAY : color = p.modes.overlay(c1, c2); break; case p.DODGE : color = p.modes.dodge(c1, c2); break; case p.BURN : color = p.modes.burn(c1, c2); break; } return color; }
blendColor() helper functions
// helper functions for internal blending modes // convert rgba color strings to integer p.rgbaToInt = function(color){ var rgbaAry = /\(([^\)]+)\)/.exec(color).slice(1,2)[0].split(','); return (rgbaAry[3] << 24) | (rgbaAry[0] << 16) | (rgbaAry[1] << 8) | (rgbaAry[2]); } p.mix = function(a, b, f) { return a + (((b - a) * f) >> 8); } p.peg = function(n) { return (n < 0) ? 0 : ((n > 255) ? 255 : n); }
blendColor() blending modes
// blending modes p.modes = { replace: function(a, b){ return p.rgbaToInt(b); }, blend: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | p.mix(c1 & p.RED_MASK, c2 & p.RED_MASK, f) & p.RED_MASK | p.mix(c1 & p.GREEN_MASK, c2 & p.GREEN_MASK, f) & p.GREEN_MASK | p.mix(c1 & p.BLUE_MASK, c2 & p.BLUE_MASK, f)); }, add: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | Math.min(((c1 & p.RED_MASK) + ((c2 & p.RED_MASK) >> 8) * f), p.RED_MASK) & p.RED_MASK | Math.min(((c1 & p.GREEN_MASK) + ((c2 & p.GREEN_MASK) >> 8) * f), p.GREEN_MASK) & p.GREEN_MASK | Math.min((c1 & p.BLUE_MASK) + (((c2 & p.BLUE_MASK) * f) >> 8), p.BLUE_MASK)); }, subtract: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | Math.max(((c1 & p.RED_MASK) - ((c2 & p.RED_MASK) >> 8) * f), p.GREEN_MASK) & p.RED_MASK | Math.max(((c1 & p.GREEN_MASK) - ((c2 & p.GREEN_MASK) >> 8) * f), p.BLUE_MASK) & p.GREEN_MASK | Math.max((c1 & p.BLUE_MASK) - (((c2 & p.BLUE_MASK) * f) >> 8), 0)); }, lightest: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | Math.max(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f) & p.RED_MASK | Math.max(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f) & p.GREEN_MASK | Math.max(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8)); }, darkest: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | p.mix(c1 & p.RED_MASK, Math.min(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f), f) & p.RED_MASK | p.mix(c1 & p.GREEN_MASK, Math.min(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f), f) & p.GREEN_MASK | p.mix(c1 & p.BLUE_MASK, Math.min(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8), f)); }, difference: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (ar > br) ? (ar-br) : (br-ar); var cg = (ag > bg) ? (ag-bg) : (bg-ag); var cb = (ab > bb) ? (ab-bb) : (bb-ab); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, exclusion: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = ar + br - ((ar * br) >> 7); var cg = ag + bg - ((ag * bg) >> 7); var cb = ab + bb - ((ab * bb) >> 7); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, multiply: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (ar * br) >> 8; var cg = (ag * bg) >> 8; var cb = (ab * bb) >> 8; // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, screen: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = 255 - (((255 - ar) * (255 - br)) >> 8); var cg = 255 - (((255 - ag) * (255 - bg)) >> 8); var cb = 255 - (((255 - ab) * (255 - bb)) >> 8); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, hard_light: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (br < 128) ? ((ar*br)>>7) : (255-(((255-ar)*(255-br))>>7)); var cg = (bg < 128) ? ((ag*bg)>>7) : (255-(((255-ag)*(255-bg))>>7)); var cb = (bb < 128) ? ((ab*bb)>>7) : (255-(((255-ab)*(255-bb))>>7)); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, soft_light: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = ((ar*br)>>7) + ((ar*ar)>>8) - ((ar*ar*br)>>15); var cg = ((ag*bg)>>7) + ((ag*ag)>>8) - ((ag*ag*bg)>>15); var cb = ((ab*bb)>>7) + ((ab*ab)>>8) - ((ab*ab*bb)>>15); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, overlay: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (ar < 128) ? ((ar*br)>>7) : (255-(((255-ar)*(255-br))>>7)); var cg = (ag < 128) ? ((ag*bg)>>7) : (255-(((255-ag)*(255-bg))>>7)); var cb = (ab < 128) ? ((ab*bb)>>7) : (255-(((255-ab)*(255-bb))>>7)); // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, dodge: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (br==255) ? 255 : p.peg((ar << 8) / (255 - br)); // division requires pre-peg()-ing var cg = (bg==255) ? 255 : p.peg((ag << 8) / (255 - bg)); // " var cb = (bb==255) ? 255 : p.peg((ab << 8) / (255 - bb)); // " // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); }, burn: function(a, b){ var c1 = p.rgbaToInt(a); var c2 = p.rgbaToInt(b); var f = (c2 & p.ALPHA_MASK) >>> 24; var ar = (c1 & p.RED_MASK) >> 16; var ag = (c1 & p.GREEN_MASK) >> 8; var ab = (c1 & p.BLUE_MASK); var br = (c2 & p.RED_MASK) >> 16; var bg = (c2 & p.GREEN_MASK) >> 8; var bb = (c2 & p.BLUE_MASK); // formula: var cr = (br==0) ? 0 : 255 - p.peg(((255 - ar) << 8) / br); // division requires pre-peg()-ing var cg = (bg==0) ? 0 : 255 - p.peg(((255 - ag) << 8) / bg); // " var cb = (bb==0) ? 0 : 255 - p.peg(((255 - ab) << 8) / bb); // " // alpha blend (this portion will always be the same) return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 | (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) | (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) | (p.peg(ab + (((cb - ab) * f) >> 8)) ) ); } };
screen
p.screen = { width:screen.width, height:screen.height }
log()
p.log = function( num ) { return Math.log(num > 0 ? num : 0); }
exp()
p.exp = function( num ){ return Math.exp(num > 0 ? num : 0); }
asin()
p.asin = function( num ){ return Math.asin(num); }
acos()
p.acos = function( num ){ return Math.acos(num); }
atan()
p.atan = function( num ){ return Math.atan(num); }
tan()
p.tan = function( num ){ return Math.tan(num); }
map()
p.map = function( value, low1, high1, low2, high2 ){ return (((value-low1)/(high1-low1))*(high2-low2))+low2; }
nfc()
Specification for nfc() in processing here.
nfc() is a function used to format numbers with commas every 3rd digit and optionally how many decimal places to show right of the decimal place. It accepts int, int[], float, and float[] types and returns either a single string or array of strings depending on the input.
p.nfc = function( num, right ){ var str; var decimals = right >= 0 ? right : 0; if (typeof num == "object"){ str = new Array(); for(var i=0; i < num.length; i++){ str[i] = p.nfc(num[i], decimals); } } else if (arguments.length == 2){ var rawStr = p.nfs(num, 0, decimals); var digits = ("" + Math.floor(Math.abs(rawStr))).length; var ary = new Array(); ary = rawStr.split('.'); // ary[0] contains left of decimal, ary[1] contains decimal places if they exist // insert commas now, then append ary[1] if it exists var leftStr = ary[0]; var rightStr = ary.length > 1 ? '.' + ary[1] : ; var commas = /(\d+)(\d{3})/; while (commas.test(leftStr)){ leftStr = leftStr.replace(commas, '$1' + ',' + '$2'); } str = leftStr + rightStr; } else if (arguments.length == 1){ str = p.nfc(num, 0); } return str; }
Example of this function and test is here.
Known issues: None.
shorten()
Specification for shorten() in processing here.
Arrays in JS have no type, the elements in them can contain any type and do not all have to match. Arrays are also passed by reference which means a reference to the object is passed in not the entire object. so my code creates a new array and then copies the passed in array first and then pops one element off the new array and the newary object is returned. This is built to accept a processing type of String, int, boolean, char, byte, and float. Support for arrays of objects will be added in 0.2.
p.shorten = function( ary ) { var newary = new Array(); // copy ary into newary for ( var i = 0; i < size; i++ ) { newary[ i ] = ary[ i ]; } newary.pop(); return newary; }
Example of this function and test is here.
Known issues: This has not been tested with arrays of objects. I'm assuming it will copy object elements in an array by reference and not produce a proper deep copy. I plan to fix this by 0.2. (confirmed, needs deep copy support for arrays of objects).
expand()
Specification for expand() in processing here.
Expand takes an array as its argument and returns a copy of the array with its length doubled. There is an optional 2nd parameter to specify the new size of the array as well.
p.expand = function( ary, newSize ) { var newary = new Array(); for ( var i = 0; i < ary.length; i++ ) { newary[ i ] = ary[ i ]; } if (arguments.length == 1) { // double size of array newary.length *= 2; } else if (arguments.length == 2) { // size is newSize newary.length = newSize; } return newary; }
Example of this function and test is here.
Known issues: Not yet tested with arrays of objects.
unhex()
Specification for unhex() in processing here.
unhex takes a string representing a 8 digit hex code as its only argument and returns an int representation of the string. JavaScript supports 64 bit floats as var's so it took a little number crunching to make it output an exact replication of the Java implementation with signed int's.
p.unhex = function( str ) { var value = 0; var multiplier = 1; var num = 0; for (var i = str.length-1; i >= 0; i--){ try{ switch(str[i]){ case "0": num = 0; break; case "1": num = 1; break; case "2": num = 2; break; case "3": num = 3; break; case "4": num = 4; break; case "5": num = 5; break; case "6": num = 6; break; case "7": num = 7; break; case "8": num = 8; break; case "9": num = 9; break; case "A": case "a": num = 10; break; case "B": case "b": num = 11; break; case "C": case "c": num = 12; break; case "D": case "d": num = 13; break; case "E": case "e": num = 14; break; case "F": case "f": num = 15; break; default:return 0; break; } value += num * multiplier; multiplier *= 16; }catch(e){;} // correct for int overflow java expectation if (value > 2147483647) { value -= 4294967296; } } return value; }
Example of this function and test is here.
Known issues: None.
nfs()
Specification for nfs() in processing here.
nfs() is a function used to format numbers as strings with padding of 0's on either the left or right of the decimal place. It accepts int, int[], float, and float[] types and returns either a single string or array of strings depending on the input.
p.nfs = function( num, left, right){ var str; // array handling if (typeof num == "object"){ str = new Array(); for(var i=0; i < num.length; i++){ str[i] = p.nfs(num[i], left, right); } } else if (arguments.length == 3){ var negative = false; if (num < 0) negative = true; str = "" + Math.abs(num); var digits = ("" + Math.floor(Math.abs(num))).length; var count = left - digits; while (count > 0){ str = "0" + str; count--; } // get the number of decimal places, if none will be -1 var decimals = ("" + Math.abs(num)).length - digits - 1; if (decimals == -1 && right > 0) str = str + "."; if (decimals != -1) count = right - decimals; else if (decimals == -1 && right > 0){ count = right; } else count = 0; while (count > 0){ str = str + "0"; count--; } str = (negative ? "-" : " ") + str; } else if (arguments.length == 2){ str = p.nfs(num, left, 0); } return str; }
Example of this function and test is here.
Known issues: None.