// 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 256 rows (indexed 0..255, top to bottom) * of 512 pixels each (indexed 0..511, left to right). The top left pixel on * the screen is indexed (0,0). */ class Screen { static Array mem; static Array st; static boolean color; /** Initializes the Screen. */ function void init() { var int a; let st = Array.new(16); let st[0] = 1; while (a < 15){ let a = a + 1; let st[a] = st[a - 1] + st[a - 1]; } let color = true; return; } /** Erases the entire screen. */ function void clearScreen() { var int a; let a = 16384; while (a < 24575){ let mem[a] = 0; let a = a + 1; } 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 value, address, bit, mem_block; if ((x > 511) | (x < 0) | (y > 255) | (y < 0)){ do Sys.error(7); } let mem_block = x / 16; let address = (32 * y) + mem_block + 16384; let value = mem[address]; let bit = x - (mem_block * 16); if (color){ let mem[address] = st[bit] | value; } else{ let mem[address] = (~st[bit])& value; } 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 diff, dx, dy, a, b; if((x1 < 0) | (x2 > 511) | (y1 < 0) | (y2 > 255)){ do Sys.error(8); } let dx = x2 - x1; let dy = y2 - y1; if (dx = 0){ if (dy > 0){ while(~(b > dy)){ do Screen.drawPixel(x1, y1 + b); let b = b + 1; } return; } else{ while(~(b < dy)){ do Screen.drawPixel(x1, y1 + b); let b = b - 1; } return; } } if (dy = 0){ if (dx > 0){ while(~(a > dx)){ do Screen.drawPixel(x1 + a, y1); let a = a + 1; } return; } else{ while(~(a < dx)){ do Screen.drawPixel(x1 + a, y1); let a = a - 1; } return; } } if (dx < 0){ if (dy < 0){ while ((~(a < dx)) & (~(b < dy))){ do Screen.drawPixel(x1 + a, y1 + b); if (diff < 0){ let a = a - 1; let diff = diff - dy; } else{ let b = b - 1; let diff = diff + dx; } } } else{ while ((~(a < dx)) & (~(b > dy))){ do Screen.drawPixel(x1 + a, y1 + b); if (diff < 0){ let a = a - 1; let diff = diff + dy; } else{ let b = b + 1; let diff = diff + dx; } } } } else{ if (dy < 0){ while ((~(a > dx)) & (~(b < dy))){ do Screen.drawPixel(x1 + a, y1 + b); if (diff < 0){ let a = a + 1; let diff = diff - dy; } else{ let b = b - 1; let diff = diff - dx; } } } else{ while ((~(a > dx)) & (~(b > dy))){ do Screen.drawPixel(x1 + a, y1 + b); if (diff < 0){ let a = a + 1; let diff = diff + dy; } else{ let b = b + 1; let diff = diff - dx; } } } } 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 a, tmp; if (x1 > x2){ let tmp = x1; let x1 = x2; let x2 = tmp; } if (y1 > y2){ let tmp = y1; let y1 = y2; let y2 = tmp; } if((x1 < 0) | (x2 > 511) | (y1 < 0) | (y2 > 255)){ do Sys.error(8); } let tmp = y2 - y1; while(a < tmp){ do Screen.drawLine(x1, y1 + a, x2, y1 + a); let a = a + 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 dy, dx, tmp; if(r > 181){ do Sys.error(7); } let dy = - r; while (dy < r){ let tmp = Math.sqrt((r * r) - (dy * dy)); do Screen.drawLine(x - tmp, y + dy, x + tmp, y + dy); let dy = dy + 1; } return; } }