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