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 }
148 alias Coordinate = Box;
149 /**
150  * Defines polygons for sprite transformation (eg. scaling, rotation).
151  * Most likely will be removed due to lack of use.
152  */
153 public struct Quad{
154 	public int midX, midY;		///Defines the midpoint to reduce the need for precision. Corners are referenced to this point
155 	public float cornerAX, cornerAY, cornerAZ;	///Upper-left corner mapping
156 	public float cornerBX, cornerBY, cornerBZ;	///Upper-right corner mapping
157 	public float cornerCX, cornerCY, cornerCZ;	///Lower-left corner mapping
158 	public float cornerDX, cornerDY, cornerDZ;	///Lower-right corner mapping
159 }
160 alias Color = ARGB8888BE;
161 /+
162 /**
163  * Various representations of color with various accessibility modes.
164  * Probably will be replaced with a struct from either CPUBLiT or dimage.
165  */
166 public struct Color{
167 	union{
168 		uint raw;	///Raw representation in integer form, also forces the system to align in INT32.
169 		ubyte[4] colors;	///Normal representation, aliases are used for color naming.
170 	}
171 	version(LittleEndian){
172 		///Returns the alpha channel of the color
173 		public @nogc @safe @property pure nothrow ubyte alpha() const{ return colors[0]; }
174 		///Returns the red channel of the color
175 		public @nogc @safe @property pure nothrow ubyte red() const{ return colors[1]; }
176 		///Returns the green channel of the color
177 		public @nogc @safe @property pure nothrow ubyte green() const{ return colors[2]; }
178 		///Returns the blue channel of the color
179 		public @nogc @safe @property pure nothrow ubyte blue() const{ return colors[3]; }
180 		///Sets the alpha channel of the color
181 		public @nogc @safe @property pure nothrow ubyte alpha(ubyte value) { return colors[0] = value; }
182 		///Sets the red channel of the color
183 		public @nogc @safe @property pure nothrow ubyte red(ubyte value) { return colors[1] = value; }
184 		///Sets the green channel of the color
185 		public @nogc @safe @property pure nothrow ubyte green(ubyte value) { return colors[2] = value; }
186 		///Sets the blue channel of the color
187 		public @nogc @safe @property pure nothrow ubyte blue(ubyte value) { return colors[3] = value; }
188 	}else{
189 		///Returns the alpha channel of the color
190 		public @nogc @safe @property pure nothrow ubyte alpha() const{ return colors[3]; }
191 		///Returns the red channel of the color
192 		public @nogc @safe @property pure nothrow ubyte red() const{ return colors[2]; }
193 		///Returns the green channel of the color
194 		public @nogc @safe @property pure nothrow ubyte green() const{ return colors[1]; }
195 		///Returns the blue channel of the color
196 		public @nogc @safe @property pure nothrow ubyte blue() const{ return colors[0]; }
197 		///Sets the alpha channel of the color
198 		public @nogc @safe @property pure nothrow ubyte alpha(ubyte value) { return colors[3] = value; }
199 		///Sets the red channel of the color
200 		public @nogc @safe @property pure nothrow ubyte red(ubyte value) { return colors[2] = value; }
201 		///Sets the green channel of the color
202 		public @nogc @safe @property pure nothrow ubyte green(ubyte value) { return colors[1] = value; }
203 		///Sets the blue channel of the color
204 		public @nogc @safe @property pure nothrow ubyte blue(ubyte value) { return colors[0] = value; }
205 	}
206 	/**
207 	 * Contructs a color from four individual values.
208 	 */
209 	public @nogc this(ubyte alpha, ubyte red, ubyte green, ubyte blue) nothrow pure @safe {
210 		this.alpha = alpha;
211 		this.red = red;
212 		this.green = green;
213 		this.blue = blue;
214 	}
215 	/**
216 	 * Constructs a color from a single 32 bit unsigned integer.
217 	 */
218 	public @nogc this(uint val) nothrow pure @safe {
219 		raw = val;
220 	}
221 	/**
222 	 * Operator overloading for quick math. '*' is alpha-blending, '^' is XOR blitter, '&' is normal "blitter".
223 	 * Alpha is used from right hand side and kept on left hand side when needed
224 	 */
225 	public Color opBinary(string op)(Color rhs){
226 		static if(op == "+"){
227 			int r = red + rhs.red, g = green + rhs.green, b = blue + rhs.blue, a = alpha + rhs.alpha;
228 			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);
229 		}else 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 < 0 ? 0 : cast(ubyte)a, r < 0 ? 0 : cast(ubyte)r, g < 0 ? 0 : cast(ubyte)g, b < 0 ? 0 : cast(ubyte)b);
232 		}else static if(op == "^"){
233 			return Color(alpha ^ rhs.alpha, red ^ rhs.red, green ^ rhs.green, blue ^ rhs.blue);
234 		}else static if(op == "&"){
235 			return rhs.alpha ? rhs : this;
236 		}else static if(op == "*"){
237 			return Color(alpha, cast(ubyte)( ( (rhs.red * (1 + rhs.alpha)) + (red * (256 - rhs.alpha)) )>>8 ),
238 								cast(ubyte)( ( (rhs.green * (1 + rhs.alpha)) + (green * (256 - rhs.alpha)) )>>8 ),
239 								cast(ubyte)( ( (rhs.blue * (1 + rhs.alpha)) + (blue * (256 - rhs.alpha)) )>>8 ));
240 		}else static assert(0, "Operator '" ~ op ~ "' not supported!");
241 	}
242 	/**
243 	 * Returns a string for debugging.
244 	 */
245 	public string toString() const{
246 		import PixelPerfectEngine.system.etc;
247 		return "0x" ~ intToHex(raw, 8);
248 	}
249 }+/
250 //alias Pixel32Bit Color;