// This file is part of www.nand2tetris.org // and the book "The Elements of Computing Systems" // by Nisan and Schocken, MIT Press. // File name: projects/12/Screen.jack /** * A library of functions for displaying graphics on the screen. * The Hack physical screen consists of 512 rows (indexed 0..511, top to bottom) * of 256 pixels each (indexed 0..255, left to right). The top left pixel on * the screen is indexed (0,0). */ class Screen { static Array twoToThe; static Array screen; static boolean color; /** Initializes the Screen. */ function void init() { var int i, x; let x = 1; let i = 0; let twoToThe = Array.new(16); while (i < 16){ let twoToThe[i] = x; let x = x + x; let i = i + 1; } let screen = 16384; let color = true; return; } /** Erases the entire screen. */ function void clearScreen() { var boolean c; let c = color; let color = false; do Screen.drawRectangle(0, 0, 511, 255); let color = c; return; } /** Sets the current color, to be used for all subsequent drawXXX commands. * Black is represented by true, white by false. */ function void setColor(boolean b) { let color = b; return; } /** Draws the (x,y) pixel, using the current color. */ function void drawPixel(int x, int y) { var int addr, t; if ((x < 0) | (y < 0) | (x > 511) | (y > 255)) { //String.println("drawPixel: coordinates out of range!"); //Sys.error(2); return; } let t = x / 16; let addr = 32 * y + t; if (color) { let screen[addr] = screen[addr] | twoToThe[x - (t * 16)]; } else { let screen[addr] = screen[addr] & (- (twoToThe[x - (t * 16)] + 1)); } return; } /** Draws a line from pixel (x1,y1) to pixel (x2,y2), using the current color. */ function void drawLine(int x1, int y1, int x2, int y2) { var int dx, dy, x, y, a, b, diff; let x = x1; let y = y1; do Screen.drawPixel(x, y); if (x1 = x2) { if (y1 = y2) { return; } else { let diff = 1; } } else { if (y1 = y2) { let diff = -1; } else { let diff = 0; } } let dx = x2 - x1; let dy = y2 - y1; let a = Math.sign(dx); let b = Math.sign(dy); let dx = Math.abs(dx); let dy = Math.abs(dy); while (~((x = x2) & (y = y2))) { if (diff < 0){ let x = x + a; let diff = diff + dy; } else { let y = y + b; let diff = diff - dx; } do Screen.drawPixel(x, y); } return; } /** Draws a filled rectangle whose top left corner is (x1, y1) * and bottom right corner is (x2,y2), using the current color. */ function void drawRectangle(int x1, int y1, int x2, int y2) { var int x; if ((x1 > x2) | (y1 > y2)) { return; } let x = x1; while (~(x > x2)) { do Screen.drawLine(x, y1, x, y2); let x = x + 1; } return; } /** Draws a filled circle of radius r<=181 around (x,y), using the current color. */ function void drawCircle(int x, int y, int r) { var int dx, dy, r2; if (r > 181) { do String.println("drawCircle: radius too big!"); do Sys.error(2); return; } let dy = -r; let r2 = r * r; while (~(dy > r)) { let dx = Math.sqrt(r2 - (dy * dy)); do Screen.drawLine(x - dx, y + dy, x + dx, y + dy); let dy = dy + 1; } return; } }