|
1 | 1 | (function() {
|
2 |
| - var X_MASK = (1 << 9) - 1, |
3 |
| - MSB_MASK = 1 << 15; |
| 2 | + var WIDTH = 512, |
| 3 | + HEIGHT = 256; |
4 | 4 |
|
5 | 5 | function Screen(elem) {
|
6 | 6 | this.canvas = elem.getContext('2d');
|
| 7 | + this.image = this.canvas.createImageData(WIDTH, HEIGHT); |
7 | 8 | this.store = {};
|
8 | 9 | }
|
9 | 10 |
|
|
18 | 19 |
|
19 | 20 | Screen.prototype.redrawPixels = function (addr, bits) {
|
20 | 21 | var offset = 16 * addr, // Each address corresponds to 16 horizontal pixels.
|
21 |
| - x = offset & X_MASK, // Modulo: offset & (COLUMNS - 1) = offset % COLUMNS |
22 |
| - y = offset >> 9, // Integer division: offset >> log2(COLUMNS) == Math.floor(offset / COLUMNS) |
23 |
| - run = 1, // run will hold how many contiguous pixels with the same colour we've seen. |
24 |
| - prev, // prev will hold the colour of the previous pixel in the loop. |
25 |
| - colour; // colour will hold the current pixel's colour. |
| 22 | + idx = offset << 2, // Multiply offset by 4 because each pixel has RGBA components. |
| 23 | + colour; |
26 | 24 |
|
27 |
| - // Initialise prev to be the colour corresponding to the MSB. |
28 |
| - // This way we can skip the first iteration of the loop below. |
29 |
| - prev = (bits & MSB_MASK) ? 'black' : 'white'; |
| 25 | + // We need to loop over all 16 bits stored at addr. |
| 26 | + for (var i = 0; i < 16; i++) { |
| 27 | + // Examine the ith bit: true means black, false means white. |
| 28 | + colour = bits & (1 << i) ? 0 : 255; |
30 | 29 |
|
31 |
| - // We need to loop over 16 bits, but as we've already peeked |
32 |
| - // at the first one, this loop can start from 15 instead. |
33 |
| - // |
34 |
| - // Note that this loop runs from the MSB (rightmost pixel) |
35 |
| - // to the LSB (leftmost pixel). Having a decrementing loop |
36 |
| - // with no bounds checking gives us a tiny speed boost, but |
37 |
| - // more importantly it makes our drawing code easier below. |
38 |
| - for (var i = 15; i--;) { |
39 |
| - colour = (bits & (1 << i)) ? 'black' : 'white'; |
| 30 | + // Set the RGB components of the pixel. |
| 31 | + this.image.data[idx++] = colour; |
| 32 | + this.image.data[idx++] = colour; |
| 33 | + this.image.data[idx++] = colour; |
40 | 34 |
|
41 |
| - // If this pixel's colour is the same as the previous pixel's |
42 |
| - // colour, increase the length of the current "run" and move |
43 |
| - // on to the next pixel before we do any drawing. |
44 |
| - if (prev == colour) { |
45 |
| - run++; |
46 |
| - continue; |
47 |
| - } |
48 |
| - |
49 |
| - // If the run has ended, we need to draw the block of pixels |
50 |
| - // up to, but excluding, the current one. As we're iterating |
51 |
| - // from right to left, we can draw a rectangle starting at |
52 |
| - // the previous pixel (x + i + 1), with length run. |
53 |
| - this.canvas.fillStyle = prev; |
54 |
| - this.canvas.fillRect(x + i + 1, y, run, 1); |
55 |
| - |
56 |
| - // Start a new run of length 1 for the current pixel's colour. |
57 |
| - prev = colour; |
58 |
| - run = 1; |
| 35 | + // Always set alpha to 255 (opaque). |
| 36 | + this.image.data[idx++] = 255; |
59 | 37 | }
|
60 | 38 |
|
61 |
| - // Now that we've processed all the pixels, we can draw the last |
62 |
| - // (leftmost) run of pixels, which may have length from 1 to 16. |
63 |
| - this.canvas.fillStyle = colour; |
64 |
| - this.canvas.fillRect(x, y, run, 1); |
| 39 | + this.canvas.putImageData(this.image, 0, 0); |
65 | 40 | };
|
66 | 41 |
|
67 | 42 | window.Screen = Screen;
|
|
0 commit comments