// 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;
return;
}
/** Erases the entire screen. */
function void clearScreen() {
var boolean c;
let c = color;
let color = false;
do 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, diff;
let x = x1;
let y = y1;
do 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 drawPixel(x, y);
}
}
/** 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) {
if ((x1 > x2) | (y1 > y2)) {
return;
}
let x = x1;
while (~(x > x2)) {
do drawLine(x, y1, x, y2);
}
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) {
String.println("drawCircle: radius too big!");
Sys.error(2);
return;
}
let dy = -r;
let r2 = r * r;
while (~(dy > r)) {
let dx = Math.sqrt(r2 - (dy * dy));
do drawLine(x - dx, y + dy, x + dx, y + dy);
let dy = dy + 1;
}
return;
}
}