1 module Engine.math;
2 
3 public import gl3n.linalg;
4 import std.traits;
5 
6 struct dirty(T) {
7 	bool dirty = true;
8 	T val;
9 
10 	alias val this;	
11 
12 	this(T v) {
13 		val = v;
14 	}
15 
16 	@property opDispatch(string s, Args...)(Args args) {
17 		static if (mixin("isSomeFunction!(T."~s~")")) {
18 			static if(mixin("isFuncMutable!(T."~s~")") && !mixin("functionAttributes!(T."~s~") & FunctionAttribute.property")) {
19 				dirty = true;
20 			}
21 			static if (mixin("is(ReturnType!(T."~s~") == void)")) {
22 				mixin("val." ~ s ~ "(args);");
23 			} else {
24 				static if (args.length > 0 && mixin("functionAttributes!(T."~s~") & FunctionAttribute.property")) {
25 					dirty = true;
26 					mixin("val." ~ s ~ " = cast(typeof(val." ~ s ~"))args[0];");
27 				} else {
28 					return mixin("val." ~ s ~ "(args)");
29 				}
30 			}
31 		} else {
32 			static if(args.length > 0) {
33 				dirty = true;
34 				mixin("val." ~ s ~ " = cast(typeof(val." ~ s  ~ "))args[0];");
35 			} else {
36 				return mixin("val." ~ s);
37 			}
38 		}
39 	}
40 
41 	void opOpAssign(string op, R)(R r) {
42 		dirty = true;
43 		mixin("val" ~ op ~ "= r;");
44 	}
45 
46 	void opAssign(R)(auto ref const R r) {
47 		static if (__traits(compiles, val.opAssign!R(r))) {
48 			val.opAssign!R(r);
49 		} else {
50 			val = r;
51 		}
52 		dirty = true;
53 	}
54 
55 	T opUnary(string s)() {
56 		dirty = true;
57 		return mixin(s ~ "val");
58 	}
59 }
60 
61 template isFuncMutable(T...) if (T.length == 1)
62 {
63 	enum bool isFuncMutable = !(is(typeof(T[0]) == const) || is(typeof(T[0]) == immutable));
64 }
65 
66 
67 alias Rect!(int) recti;
68 alias Rect!(float) rect;
69 
70 struct Rect(T) {
71 	alias Vector!(T, 2) vectp;
72 	vectp min = vectp(0,0);
73 	vectp max = vectp(0,0);
74 
75 	static Rect Zero = Rect();
76 
77 
78 	this(T width, T height) {
79 		max = vectp(width,height);
80 	}
81 
82 	void add(vectp v) {
83 		min += v;
84 		max += v;
85 	}
86 
87 	nothrow this(vectp min, vectp max) {
88 		this.min = min;
89 		this.max = max;
90 	}
91 
92 	// Empty returns whether the rectangle contains no points.
93 	nothrow pure bool Empty()() const  {
94 		return min.x >= max.x || min.y >= max.y;
95 	}
96 
97 	nothrow pure T Dx()() const  {
98 		return max.x - min.x;
99 	}
100 
101 	nothrow pure T Dy()() const  {
102 		return max.y - min.y;
103 	}
104 
105 	nothrow pure bool In()(Rect s) const   {
106 		if (Empty()) {
107 			return true;
108 		}
109 		// Note that r.Max is an exclusive bound for r, so that this.In(s)
110 		// does not require that this.max.In(s).
111 		return s.min.x <= min.x && max.x <= s.max.x &&
112 			s.min.y <= min.y && max.y <= s.max.y;
113 	}
114 
115 	//returns an AABB that holds both a and b.
116 	public static nothrow Rect!T  Merge()(auto ref const Rect!T a,auto ref const Rect!T b ) {
117 		return Rect!T(
118 				  minv(a.min, b.min),
119 				  maxv(a.max, b.max),
120 				  );
121 	}	
122 
123 	T Area()() {
124         return (max.x - min.x) * (max.y - min.y);
125 	}
126 
127 	static T  MergedArea()(auto ref const Rect!T a,auto ref const Rect!T b ) {
128         return (maxv(a.max.x, b.max.x) - minv(a.min.x, b.min.x)) * (maxv(a.max.y, b.max.y) - minv(a.min.y, b.min.y));
129 	}
130 
131 	static T Proximity()(auto ref const Rect!T a,auto ref const Rect!T b ) {
132         return abs(a.min.x+a.max.x-b.min.x-b.max.x) + abs(a.min.y+a.max.y-b.min.y-b.max.y);
133 	}
134 
135 	static bool Intersects()(auto ref const Rect!T a,auto ref const Rect!T b ) {
136         return (a.min.x <= b.max.x && b.min.x <= a.max.x && a.min.y <= b.max.y && b.min.y <= a.max.y);
137 	}
138 
139 	static bool Contains()(auto ref const Rect!T aabb,auto ref const Rect!T other ) {
140         return aabb.min.x <= other.min.x &&
141 			aabb.max.x >= other.max.x &&
142 			aabb.min.y <= other.min.y &&
143 			aabb.max.y >= other.max.y;
144 	}
145 
146 
147 	nothrow static T abs()(T v)  {
148 		if (v > 0)
149 			return v;
150 		return -v;
151 	}
152 
153 	nothrow static T minv()(T v1,T v2)  {
154 		if (v1 > v2)
155 			return v2;
156 		return v1;
157 	}
158 
159 	nothrow static T maxv()(T v1,T v2)  {
160 		if (v1 > v2)
161 			return v1;
162 		return v2;
163 	}
164 
165 
166 	nothrow static vectp minv()(vectp v1,vectp v2)  {
167 		vectp o;
168 		if (v1.x < v2.x) {
169 			o.x = v1.x;
170 		} else {
171 			o.x = v2.x;
172 		}
173 
174 		if (v1.y < v2.y) {
175 			o.y = v1.y;
176 		} else {
177 			o.y = v2.y;
178 		}
179 		return o;
180 	}
181 
182 	nothrow static vectp maxv()(vectp v1,vectp v2)  {
183 		vectp o;
184 		if (v1.x > v2.x) {
185 			o.x = v1.x;
186 		} else {
187 			o.x = v2.x;
188 		}
189 
190 		if (v1.y > v2.y) {
191 			o.y = v1.y;
192 		} else {
193 			o.y = v2.y;
194 		}
195 		return o;
196 	}
197 }