1 module nes.image;
2 
3 import std.algorithm;
4 
5 import nes.color;
6 
7 struct Point {
8     int x, y;
9 }
10 
11 struct Rectangle {
12     Point min, max;
13 
14     int dx() {
15         return this.max.x - this.min.x;
16     }
17 
18     int dy() {
19         return this.max.y - this.min.y;
20     }
21 }
22 
23 // PointIn reports whether p is in r.
24 bool PointIn(Point p, Rectangle r) {
25     return r.min.x <= p.x && p.x < r.max.x &&
26         r.min.y <= p.y && p.y < r.max.y;
27 }
28 
29 class ImageRGBA {
30     ubyte[] pix;
31     int stride;
32     Rectangle rect;
33 
34     this(Rectangle r) {
35         auto w = r.dx();
36         auto h = r.dy();
37         
38         this.pix = new ubyte[4 * w * h];
39         this.stride = 4 * w;
40         this.rect = r;
41     }
42 
43     // PixOffset returns the index of the first element of Pix that corresponds to
44     // the pixel at (x, y).
45     int pixOffset(int x, int y) {
46         return (y - this.rect.min.y) * this.stride + (x - this.rect.min.x) * 4;
47     }
48 
49     void setRGBA(int x, int y, RGBA c) {
50         if (!PointIn(Point(x, y), this.rect)) {
51             return;
52         }
53 
54         auto i = this.pixOffset(x, y);
55         this.pix[i + 0] = c.r;
56         this.pix[i + 1] = c.g;
57         this.pix[i + 2] = c.b;
58         this.pix[i + 3] = c.a;
59     }
60 }
61 
62 Rectangle Rect(int x0, int y0, int x1, int y1) {
63     if (x0 > x1) {
64         swap(x0, x1);
65     }
66 
67     if (y0 > y1) {
68         swap(y0, y1);
69     }
70 
71     return Rectangle(Point(x0, y0), Point(x1, y1));
72 }