1 /*
2  * Copyright (c) 2015-2017, by Laszlo Szeremi, under Boost license
3  *
4  * Pixel Perfect Engine, graphics.common module
5  */
6 
7 module pixelperfectengine.graphics.common;
8 
9 //public import CPUblit.colorspaces;
10 
11 import dimage.types : ARGB8888BE;
12 
13 /**
14  * Graphics primitive. Represents a single point on a 2D field.
15  */
16 public struct Point {
17 	public int x, y;
18 	/**
19 	 * Moves the point by the given amount
20 	 */
21 	public void relMove (int rX, int rY) @safe @nogc pure nothrow {
22 		x += rX;
23 		y += rY;
24 	}
25 	public string toString() const {
26 		import std.conv : to;
27 		return "x: " ~ to!string(x) ~ " ; y: " ~ to!string(y);
28 	}
29 	bool opEquals(const Point other) @safe @nogc pure nothrow const {
30 		return this.x == other.x && this.y == other.y;
31 	}
32 }
33 /**
34  * Graphics primitive. Represents a box on a 2D field.
35  * Note on area calculation: The smallest box that can be represented is 1 * 1, as it counts the endpoints as part of the box.
36  * This behavior got added with 0.10.0, to standardize various behaviors of the engine, and fix some odd behavior the GUI
37  * drawing functions had.
38  */
39 public struct Box {
40 	public int left, top, right, bottom;
41 	this(int left, int top, int right, int bottom) @safe pure nothrow @nogc {
42 		this.left=left;
43 		this.top=top;
44 		this.right=right;
45 		this.bottom=bottom;
46 	}
47 	/**
48 	 * Returns the width of the represented box.
49 	 */
50 	public @property @nogc @safe nothrow pure int width() const {
51 		return right - left + 1;
52 	}
53 	/**
54 	 * Sets the width of the represented box while keeping the lefthand coordinate.
55 	 */
56 	public @property int width(int val) @nogc @safe pure nothrow {
57 		right = left + val - 1;
58 		return right - left + 1;
59 	}
60 	/**
61 	 * Returns the height of the represented box.
62 	 */
63 	public @property @nogc @safe nothrow pure int height() const {
64 		return bottom - top + 1;
65 	}
66 	/**
67 	 * Sets the height of the represented box while keeping the top coordinate.
68 	 */
69 	public @property int height(int val) @nogc @safe pure nothrow { 
70 		bottom = top + val - 1;
71 		return bottom - top + 1;
72 	}
73 	/**
74 	 * Returns the area of the represented box.
75 	 */
76 	public @property @nogc @safe nothrow pure size_t area() const {
77 		return width * height;
78 	}
79 	/**
80 	 * Moves the box to the given position.
81 	 */
82 	public void move(int x, int y) @nogc @safe nothrow pure {
83 		right = x + width();
84 		bottom = y + height();
85 		left = x;
86 		top = y;
87 	}
88 	/**
89 	 * Moves the box by the given values.
90 	 */
91 	public void relMove(int x, int y) @nogc @safe nothrow pure {
92 		left = left + x;
93 		right = right + x;
94 		top = top + y;
95 		bottom = bottom + y;
96 	}
97 	/**
98 	 * Returns true if the given point is between the coordinates.
99 	 */
100 	public bool isBetween(int x, int y) @nogc @safe pure nothrow const {
101 		return (x >= left && x <= right && y >= top && y <= bottom);
102 	}
103 	///Ditto
104 	public bool isBetween(Point p) @nogc @safe pure nothrow const {
105 		return (p.x >= left && p.x <= right && p.y >= top && p.y <= bottom);
106 	}
107 	/**
108 	 * Operator overloading for scalar values.
109 	 * `-`: Adds to left and top, substracts from right and bottom. (Shrinks by amount)
110 	 * `+`: Subtracts from left and top, adds to right and bottom. (Grows by amount)
111 	 */
112 	public Box opBinary(string op)(const int rhs) @nogc @safe pure nothrow const {
113 		static if (op == "-") {
114 			return Box(left + rhs, top + rhs, right - rhs, bottom - rhs);
115 		} else static if (op == "+") {
116 			return Box(left - rhs, top - rhs, right + rhs, bottom + rhs);
117 		} else static assert(0, "Unsupported operator!");
118 	}
119 	///Returns the upper-left corner.
120 	public @property Point cornerUL() @nogc @safe pure nothrow const {
121 		return Point(left, top);
122 	}
123 	///Returns the upper-right corner.
124 	public @property Point cornerUR() @nogc @safe pure nothrow const {
125 		return Point(right, top);
126 	}
127 	///Returns the lowew-left corner.
128 	public @property Point cornerLL() @nogc @safe pure nothrow const {
129 		return Point(left, bottom);
130 	}
131 	///Returns the lower-right corner.
132 	public @property Point cornerLR() @nogc @safe pure nothrow const {
133 		return Point(right, bottom);
134 	}
135 	///Pads the edges of the given box by the given amounts and returns a new Box.
136 	public Box pad(const int horiz, const int vert) @nogc @safe pure nothrow const {
137 		return Coordinate(left + horiz, top + vert, right - horiz, bottom - vert);
138 	}
139 	/**
140 	 * Returns a string with the coordinates that is useful for debugging
141 	 */
142 	public string toString() const {
143 		import pixelperfectengine.system.etc;
144 		import std.conv;
145 		/*return "Coordinate: Left: 0x" ~ intToHex(left, 8) ~ " Top: 0x" ~ intToHex(top, 8) ~ " Right: 0x" ~ intToHex(right, 8) ~ " Bottom: 0x" ~ intToHex(bottom, 8) ~
146 				" Width: 0x" ~ intToHex(width(), 8) ~ " Height: 0x" ~ intToHex(height(), 8);*/
147 		return "Coordinate: Left: " ~ to!string(left) ~ " Top: " ~ to!string(top) ~ " Right: " ~ to!string(right) ~
148 				" Bottom: " ~ to!string(bottom) ~ " Width: " ~ to!string(width()) ~ " Height: " ~ to!string(height());
149 	}
150 	public static Box bySize(int x, int y, int w, int h) @nogc @safe pure nothrow {
151 		return Box(x, y, x + w - 1, y + h - 1);
152 	}
153 }
154 alias Coordinate = Box;
155 /**
156  * Defines polygons for sprite transformation (eg. scaling, rotation).
157  * Most likely will be removed due to lack of use.
158  */
159 public struct Quad{
160 	public int midX, midY;		///Defines the midpoint to reduce the need for precision. Corners are referenced to this point
161 	public float cornerAX, cornerAY, cornerAZ;	///Upper-left corner mapping
162 	public float cornerBX, cornerBY, cornerBZ;	///Upper-right corner mapping
163 	public float cornerCX, cornerCY, cornerCZ;	///Lower-left corner mapping
164 	public float cornerDX, cornerDY, cornerDZ;	///Lower-right corner mapping
165 }
166 alias Color = ARGB8888BE;
167 /+
168 /**
169  * Various representations of color with various accessibility modes.
170  * Probably will be replaced with a struct from either CPUBLiT or dimage.
171  */
172 public struct Color{
173 	union{
174 		uint raw;	///Raw representation in integer form, also forces the system to align in INT32.
175 		ubyte[4] colors;	///Normal representation, aliases are used for color naming.
176 	}
177 	version(LittleEndian){
178 		///Returns the alpha channel of the color
179 		public @nogc @safe @property pure nothrow ubyte alpha() const{ return colors[0]; }
180 		///Returns the red channel of the color
181 		public @nogc @safe @property pure nothrow ubyte red() const{ return colors[1]; }
182 		///Returns the green channel of the color
183 		public @nogc @safe @property pure nothrow ubyte green() const{ return colors[2]; }
184 		///Returns the blue channel of the color
185 		public @nogc @safe @property pure nothrow ubyte blue() const{ return colors[3]; }
186 		///Sets the alpha channel of the color
187 		public @nogc @safe @property pure nothrow ubyte alpha(ubyte value) { return colors[0] = value; }
188 		///Sets the red channel of the color
189 		public @nogc @safe @property pure nothrow ubyte red(ubyte value) { return colors[1] = value; }
190 		///Sets the green channel of the color
191 		public @nogc @safe @property pure nothrow ubyte green(ubyte value) { return colors[2] = value; }
192 		///Sets the blue channel of the color
193 		public @nogc @safe @property pure nothrow ubyte blue(ubyte value) { return colors[3] = value; }
194 	}else{
195 		///Returns the alpha channel of the color
196 		public @nogc @safe @property pure nothrow ubyte alpha() const{ return colors[3]; }
197 		///Returns the red channel of the color
198 		public @nogc @safe @property pure nothrow ubyte red() const{ return colors[2]; }
199 		///Returns the green channel of the color
200 		public @nogc @safe @property pure nothrow ubyte green() const{ return colors[1]; }
201 		///Returns the blue channel of the color
202 		public @nogc @safe @property pure nothrow ubyte blue() const{ return colors[0]; }
203 		///Sets the alpha channel of the color
204 		public @nogc @safe @property pure nothrow ubyte alpha(ubyte value) { return colors[3] = value; }
205 		///Sets the red channel of the color
206 		public @nogc @safe @property pure nothrow ubyte red(ubyte value) { return colors[2] = value; }
207 		///Sets the green channel of the color
208 		public @nogc @safe @property pure nothrow ubyte green(ubyte value) { return colors[1] = value; }
209 		///Sets the blue channel of the color
210 		public @nogc @safe @property pure nothrow ubyte blue(ubyte value) { return colors[0] = value; }
211 	}
212 	/**
213 	 * Contructs a color from four individual values.
214 	 */
215 	public @nogc this(ubyte alpha, ubyte red, ubyte green, ubyte blue) nothrow pure @safe {
216 		this.alpha = alpha;
217 		this.red = red;
218 		this.green = green;
219 		this.blue = blue;
220 	}
221 	/**
222 	 * Constructs a color from a single 32 bit unsigned integer.
223 	 */
224 	public @nogc this(uint val) nothrow pure @safe {
225 		raw = val;
226 	}
227 	/**
228 	 * Operator overloading for quick math. '*' is alpha-blending, '^' is XOR blitter, '&' is normal "blitter".
229 	 * Alpha is used from right hand side and kept on left hand side when needed
230 	 */
231 	public Color opBinary(string op)(Color rhs){
232 		static if(op == "+"){
233 			int r = red + rhs.red, g = green + rhs.green, b = blue + rhs.blue, a = alpha + rhs.alpha;
234 			return Color(a > 255 ? 255 : cast(ubyte)a, r > 255 ? 255 : cast(ubyte)r, g > 255 ? 255 : cast(ubyte)g, b > 255 ? 255 : cast(ubyte)b);
235 		}else static if(op == "-"){
236 			int r = red - rhs.red, g = green - rhs.green, b = blue - rhs.blue, a = alpha - rhs.alpha;
237 			return Color(a < 0 ? 0 : cast(ubyte)a, r < 0 ? 0 : cast(ubyte)r, g < 0 ? 0 : cast(ubyte)g, b < 0 ? 0 : cast(ubyte)b);
238 		}else static if(op == "^"){
239 			return Color(alpha ^ rhs.alpha, red ^ rhs.red, green ^ rhs.green, blue ^ rhs.blue);
240 		}else static if(op == "&"){
241 			return rhs.alpha ? rhs : this;
242 		}else static if(op == "*"){
243 			return Color(alpha, cast(ubyte)( ( (rhs.red * (1 + rhs.alpha)) + (red * (256 - rhs.alpha)) )>>8 ),
244 								cast(ubyte)( ( (rhs.green * (1 + rhs.alpha)) + (green * (256 - rhs.alpha)) )>>8 ),
245 								cast(ubyte)( ( (rhs.blue * (1 + rhs.alpha)) + (blue * (256 - rhs.alpha)) )>>8 ));
246 		}else static assert(0, "Operator '" ~ op ~ "' not supported!");
247 	}
248 	/**
249 	 * Returns a string for debugging.
250 	 */
251 	public string toString() const{
252 		import PixelPerfectEngine.system.etc;
253 		return "0x" ~ intToHex(raw, 8);
254 	}
255 }+/
256 //alias Pixel32Bit Color;