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