summaryrefslogtreecommitdiff
path: root/projects/12/Screen.jack
blob: a370ab976467ace1bc33068f57fd9379ddeb6e69 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// 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;
    }
}