Files
nand2tetris/projects/12/OutputTest/Screen.jack
2021-04-21 17:01:42 +03:00

163 lines
4.7 KiB
Plaintext

// 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 boolean color;
/** Initializes the Screen. */
function void init() {
let color = true;
let twoToThe = Array.new(16);
let twoToThe[0] = 1;
let twoToThe[1] = 2;
let twoToThe[2] = 4;
let twoToThe[3] = 8;
let twoToThe[4] = 16;
let twoToThe[5] = 32;
let twoToThe[6] = 64;
let twoToThe[7] = 128;
let twoToThe[8] = 256;
let twoToThe[9] = 512;
let twoToThe[10] = 1024;
let twoToThe[11] = 2048;
let twoToThe[12] = 4096;
let twoToThe[13] = 8192;
let twoToThe[14] = 16384;
let twoToThe[15] = 16384 + 16384;
return;
}
/** Erases the entire screen. */
function void clearScreen() {
var int x, y;
var boolean prevColor;
let x = 0;
let y = 0;
let prevColor = color;
let color = false;
while (x < 256) {
while (y < 512) {
do Screen.drawPixel(x, y);
let y = y + 1;
}
let x = x + 1;
}
let color = prevColor;
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 Array address, value;
let address = (32 * y) + (x/16);
let value = Memory.peek(16384 + address);
if(color) {
let value = value | twoToThe[x & 15];
} else {
let value = value & (~(twoToThe[x & 15]));
}
do Memory.poke(16384 + address, 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 dx, dy, a, b, diff;
let dx = x2-x1;
let dy = y2-y1;
let a = 0;
let b = 0;
let diff = 0;
if(dx = 0) {
while(~(dy = 0)) {
do Screen.drawPixel(x1, y1 + dy);
if(dy > 0) {
let dy = dy - 1;
} else {
let dy = dy + 1;
}
}
return;
}
if(dy = 0) {
while(~(dx = 0)) {
do Screen.drawPixel(x1 + dx, y1);
if (dx > 0) {
let dx = dx - 1;
} else {
let dx = dx + 1;
}
}
return;
}
while((~(Math.abs(a) > Math.abs(dx))) & (~(Math.abs(b) > Math.abs(dy)))) {
do Screen.drawPixel(x1 + a, y1 + b);
if(diff < 0) {
if(dx > 0) {
let a = a + 1;
}
if(dx < 0) {
let a = a - 1;
}
let diff = diff + Math.abs(dy);
} else {
if(dy > 0) {
let b = b + 1;
}
if(dy < 0) {
let b = b - 1;
}
let diff = diff - Math.abs(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 dy;
let dy = y2 - y1;
while(~(Math.abs(dy) = 0)) {
if (dy > 0) {
do Screen.drawLine(x1, y1 + dy, x2, y1 + dy);
let dy = dy - 1;
} else {
do Screen.drawLine(x1, y1 + dy, x2, y1 + dy);
let dy = dy + 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;
let dy = -r;
if (r > 181) {
return;
}
while(dy < (r + 1)) {
do Screen.drawLine(x-Math.sqrt((r*r)-(dy*dy)),y + dy,x+Math.sqrt((r*r)-(dy*dy)),y + dy);
let dy = dy + 1;
}
return;
}
}