17. chrome://tracing
• Wrap things you care about in
console.time() / console.timeEnd() calls
• Bring up tracing in a tab
• Downside: console spam
18. var profile = function (name, cb) {
console.time(name);
cb();
console.timeEnd(name);
}
// then later...
profile('render', function () {
// my render call.
render();
});
24. Basic Technique
• Create a canvas element in your code
• Get its context
• Write pixels to that context
• Use the canvas in a drawImage() call on
another canvas context
• YOU DON’T ADD THE CACHED CANVAS
TO THE DOM!
27. Basic Idea
• drawImage() (to screen) is expensive
• Build a whole screen cache in a back buffer
(in memory)
• Draw entities to that cache with
drawImage() during render
• Write the entire cache to the screen with a
single drawImage() call
28. Basic Idea
• drawImage() (to screen) is expensive
• Build a whole screen cache in a back buffer
(in memory)
• Draw entities to that cache with
drawImage() during render
• Write the entire cache to the screen with a
single drawImage() call
29. var backBuffer = document.createElement('canvas'),
backBufferCtx;
backBufferCtx = canvasCache.getContext('2d');
// later...
var render = function () {
var i, ent;
mainCtx.drawImage(backBuffer, 0, 0);
for (i = 0; i > entities.length; i++) {
ent = entities[i];
// this is not quite what you'd do but...
backBufferCtx.drawImage(ent.cache, ent.x, ent.y)
}
}
31. Similar thing...
• Save drawImage() calls by compositing into a
cache
• Draw multiple images to the same cache in
order
• Attach the cache to a single game entity
• Write the composited cache to your frame
buffer in your draw call.
35. WTF is
ImageData?
• ImageData is what you get back from a
getImageData() call
• A single byte Array with ALL your pixel
data
• Pixel data is stored as R, G, B, A tuples
36. Single pixel Array
offsets
0 1 2 3
R G B A
8 bits 8 bits 8 bits 8 bits
4 bytes
39. Strategy
• If (x, y) is in the bounding box for the image,
check pixels.
• getImageData() to get a pixel data array for
your sprite at pixel x, y.
• Check byte values for pixel.
40. var isPixelPainted = function (x, y) {
ctx = this.imageCache; // this must be a canvas!
thresh = this.transparencyThreshold || 100;
// Grab a single pixel at x, y: if the alpha channel is greater
// than the threshold, we're in business. idata acts like a byte
// array with each pixel occupying 4 slots (R, G, B , A).
idata = ctx.getImageData(x, y, 1, 1);
return idata.data[3] > thresh;
}
43. Since ImageData
acts like a byte
array....
• We can iterate through the pixels and do
arithmetic or bitwise manipulation on the
data.
• Use XOR, NOT, etc. Get weird!
44. var filter = function (x, y, w, h) {
if (!this._cache) return;
var ctx = this._cache.getContext('2d'),
idata = ctx.getImageData(x, y, w, h),
i;
for (i = 0; i < idata.data.length; i++) {
idata.data[i] = (idata.data[i]++) % 255;
}
};
45. var filter = function (x, y, w, h) {
if (!this._cache) return;
var ctx = this._cache.getContext('2d'),
idata = ctx.getImageData(x, y, w, h),
i;
for (i = 0; i < idata.data.length; i++) {
if (! i % 4 === 3) continue;
idata.data[i] = (idata.data[i]++) % 255;
}
46. Also possible, (but
not necessarily
recommended)
• Masking (if the pixel is colored in one
image...)
• Pixel-wise composition.
• Etc.!
47. Caveats
• Cross-domain issues: if your data came from
somewhere untrusted, the browser will not
send it to the GPU.
• Canvas calls exist for some of these things.
• You can easily produce garbage.