| 2173 | } |
| 2174 | |
| 2175 | bool isScreenPointInRect(const Vec2& pt, const Camera* camera, const Mat4& w2l, const Rect& rect, Vec3* p) |
| 2176 | { |
| 2177 | if (nullptr == camera || rect.size.width <= 0 || rect.size.height <= 0) |
| 2178 | { |
| 2179 | return false; |
| 2180 | } |
| 2181 | |
| 2182 | // first, convert pt to near/far plane, get Pn and Pf |
| 2183 | Vec3 Pn(pt.x, pt.y, -1), Pf(pt.x, pt.y, 1); |
| 2184 | Pn = camera->unprojectGL(Pn); |
| 2185 | Pf = camera->unprojectGL(Pf); |
| 2186 | |
| 2187 | // then convert Pn and Pf to node space |
| 2188 | w2l.transformPoint(&Pn); |
| 2189 | w2l.transformPoint(&Pf); |
| 2190 | |
| 2191 | // Pn and Pf define a line Q(t) = D + t * E which D = Pn |
| 2192 | auto E = Pf - Pn; |
| 2193 | |
| 2194 | // second, get three points which define content plane |
| 2195 | // these points define a plane P(u, w) = A + uB + wC |
| 2196 | Vec3 A = Vec3(rect.origin.x, rect.origin.y, 0); |
| 2197 | Vec3 B(rect.origin.x + rect.size.width, rect.origin.y, 0); |
| 2198 | Vec3 C(rect.origin.x, rect.origin.y + rect.size.height, 0); |
| 2199 | B = B - A; |
| 2200 | C = C - A; |
| 2201 | |
| 2202 | // the line Q(t) intercept with plane P(u, w) |
| 2203 | // calculate the intercept point P = Q(t) |
| 2204 | // (BxC).A - (BxC).D |
| 2205 | // t = ----------------- |
| 2206 | // (BxC).E |
| 2207 | Vec3 BxC; |
| 2208 | Vec3::cross(B, C, &BxC); |
| 2209 | auto BxCdotE = BxC.dot(E); |
| 2210 | if (BxCdotE == 0) |
| 2211 | { |
| 2212 | return false; |
| 2213 | } |
| 2214 | auto t = (BxC.dot(A) - BxC.dot(Pn)) / BxCdotE; |
| 2215 | Vec3 P = Pn + t * E; |
| 2216 | if (p) |
| 2217 | { |
| 2218 | *p = P; |
| 2219 | } |
| 2220 | return rect.containsPoint(Vec2(P.x, P.y)); |
| 2221 | } |
| 2222 | |
| 2223 | void Node::applyMaskOnEnter(bool applyChildren) |
| 2224 | { |