Gnash 0.8.9
|
00001 // 00002 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 00003 // 2011 Free Software Foundation, Inc 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; if not, write to the Free Software 00017 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 // 00019 00020 #ifndef GNASH_GEOMETRY_H 00021 #define GNASH_GEOMETRY_H 00022 00023 #include "dsodefs.h" 00024 #include "SWFMatrix.h" 00025 #include "SWFRect.h" 00026 #include "Point2d.h" 00027 00028 #include <vector> // for path composition 00029 #include <cmath> // sqrt 00030 00031 00032 // Forward declarations 00033 namespace gnash { 00034 class LineStyle; 00035 } 00036 00037 namespace gnash { 00038 00044 class Edge 00045 { 00046 public: 00047 00048 // Quadratic bezier: point = p0 * t^2 + p1 * 2t(1-t) + p2 * (1-t)^2 00049 point cp; // control point, TWIPS 00050 point ap; // anchor point, TWIPS 00051 00052 Edge() 00053 : 00054 cp(0, 0), 00055 ap(0, 0) 00056 {} 00057 00058 Edge(boost::int32_t cx, boost::int32_t cy, boost::int32_t ax, 00059 boost::int32_t ay) 00060 : 00061 cp(cx, cy), 00062 ap(ax, ay) 00063 {} 00064 00065 Edge(const Edge& from) 00066 : 00067 cp(from.cp), 00068 ap(from.ap) 00069 {} 00070 00071 Edge(const point& ncp, const point& nap) 00072 : 00073 cp(ncp), 00074 ap(nap) 00075 {} 00076 00077 bool straight() const 00078 { 00079 return cp == ap; 00080 } 00081 00083 void transform(const SWFMatrix& mat) 00084 { 00085 mat.transform(ap); 00086 mat.transform(cp); 00087 } 00088 00090 static double 00091 squareDistancePtSeg(const point& p, const point& A, const point& B) 00092 { 00093 boost::int32_t dx = B.x - A.x; 00094 boost::int32_t dy = B.y - A.y; 00095 00096 if ( dx == 0 && dy == 0 ) 00097 { 00098 return p.squareDistance(A); 00099 } 00100 00101 boost::int32_t pdx = p.x - A.x; 00102 boost::int32_t pdy = p.y - A.y; 00103 00104 double u = (static_cast<double>(pdx) * dx + static_cast<double>(pdy) * dy ) / 00105 (static_cast<double>(dx)*dx + static_cast<double>(dy)*dy ); 00106 00107 if (u <= 0) 00108 { 00109 return p.squareDistance(A); 00110 } 00111 00112 if (u >= 1) 00113 { 00114 return p.squareDistance(B); 00115 } 00116 00117 point px(A, B, u); // FIXME: this interpolation introduce a precision loss (point is int-based) 00118 return p.squareDistance(px); 00119 } 00120 00122 static double 00123 distancePtSeg(const point& pt, const point& A, const point& B) 00124 { 00125 double square = squareDistancePtSeg(pt, A, B); 00126 return std::sqrt(square); 00127 } 00128 00130 // 00137 00138 static point 00139 pointOnCurve(const point& A, const point& C, const point& B, float t) 00140 { 00141 point Q1(A, C, t); 00142 point Q2(C, B, t); 00143 point R(Q1, Q2, t); 00144 00145 return R; 00146 } 00147 00150 // 00157 static boost::int64_t squareDistancePtCurve(const point& A, 00158 const point& C, 00159 const point& B, 00160 const point& p, float t) 00161 { 00162 return p.squareDistance( pointOnCurve(A, C, B, t) ); 00163 } 00164 }; 00165 00166 00168 class DSOEXPORT Path 00169 { 00170 public: 00172 unsigned m_fill0; 00173 00175 unsigned m_fill1; 00176 00178 unsigned m_line; 00179 00181 point ap; 00182 00184 std::vector<Edge> m_edges; 00185 00190 bool m_new_shape; 00191 00193 // 00197 Path(bool newShape = false) 00198 : 00199 m_new_shape(newShape) 00200 { 00201 reset(0, 0, 0, 0, 0); 00202 } 00203 00204 Path(const Path& from) 00205 : 00206 m_fill0(from.m_fill0), 00207 m_fill1(from.m_fill1), 00208 m_line(from.m_line), 00209 ap(from.ap), 00210 m_edges(from.m_edges), 00211 m_new_shape(from.m_new_shape) 00212 { 00213 } 00214 00216 // 00237 Path(boost::int32_t ax, boost::int32_t ay, 00238 unsigned fill0, unsigned fill1, unsigned line, 00239 bool newShape) 00240 : 00241 m_new_shape(newShape) 00242 { 00243 reset(ax, ay, fill0, fill1, line); 00244 } 00245 00247 // 00259 // 00263 void reset(boost::int32_t ax, boost::int32_t ay, 00264 unsigned fill0, unsigned fill1, unsigned line) 00265 // Reset all our members to the given values, and clear our edge list. 00266 { 00267 ap.x = ax; 00268 ap.y = ay; 00269 m_fill0 = fill0; 00270 m_fill1 = fill1; 00271 m_line = line; 00272 00273 m_edges.resize(0); 00274 assert(empty()); 00275 } 00276 00278 // 00290 void 00291 expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const 00292 { 00293 const Path& p = *this; 00294 size_t nedges = m_edges.size(); 00295 00296 if ( ! nedges ) return; // this path adds nothing 00297 00298 if (thickness) 00299 { 00300 // NOTE: Half of thickness would be enough (and correct) for 00301 // radius, but that would not match how Flash calculates the 00302 // bounds using the drawing API. 00303 unsigned int radius = swfVersion < 8 ? thickness : thickness/2; 00304 00305 r.expand_to_circle(ap.x, ap.y, radius); 00306 for (unsigned int j = 0; j<nedges; j++) 00307 { 00308 r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius); 00309 r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius); 00310 } 00311 } 00312 else 00313 { 00314 r.expand_to_point(ap.x, ap.y); 00315 for (unsigned int j = 0; j<nedges; j++) 00316 { 00317 r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y); 00318 r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y); 00319 } 00320 } 00321 } 00322 00327 00329 // 00339 void 00340 drawLineTo(boost::int32_t dx, boost::int32_t dy) 00341 { 00342 m_edges.push_back(Edge(dx, dy, dx, dy)); 00343 } 00344 00346 // 00362 void 00363 drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, boost::int32_t ady) 00364 { 00365 m_edges.push_back(Edge(cdx, cdy, adx, ady)); 00366 } 00367 00369 void clear() 00370 { 00371 m_edges.resize(0); 00372 m_fill0 = m_fill1 = m_line = 0; 00373 } 00374 00376 00377 00379 bool isClosed() const 00380 { 00381 if (m_edges.empty()) return true; 00382 return m_edges.back().ap == ap; 00383 } 00384 00386 void close() 00387 { 00388 if ( m_edges.empty() ) return; 00389 00390 // Close it with a straight edge if needed 00391 const Edge& lastedge = m_edges.back(); 00392 if ( lastedge.ap != ap ) 00393 { 00394 Edge newedge(ap, ap); 00395 m_edges.push_back(newedge); 00396 } 00397 } 00398 00402 // 00405 bool 00406 withinSquareDistance(const point& p, double dist) const 00407 { 00408 size_t nedges = m_edges.size(); 00409 00410 if ( ! nedges ) return false; 00411 00412 point px(ap); 00413 for (size_t i=0; i<nedges; ++i) 00414 { 00415 const Edge& e = m_edges[i]; 00416 point np(e.ap); 00417 00418 if (e.straight()) 00419 { 00420 double d = Edge::squareDistancePtSeg(p, px, np); 00421 if ( d <= dist ) return true; 00422 } 00423 else 00424 { 00425 00426 const point& A = px; 00427 const point& C = e.cp; 00428 const point& B = e.ap; 00429 00430 // Approximate the curve to segCount segments 00431 // and compute distance of query point from each 00432 // segment. 00433 // 00434 // TODO: find an apprpriate value for segCount based 00435 // on rendering scale ? 00436 // 00437 int segCount = 10; 00438 point p0(A.x, A.y); 00439 for (int i=1; i<=segCount; ++i) 00440 { 00441 float t1 = static_cast<float>(i) / segCount; 00442 point p1 = Edge::pointOnCurve(A, C, B, t1); 00443 00444 // distance from point and segment being an approximation 00445 // of the curve 00446 double d = Edge::squareDistancePtSeg(p, p0, p1); 00447 if ( d <= dist ) return true; 00448 00449 p0.setTo(p1.x, p1.y); 00450 } 00451 } 00452 px = np; 00453 } 00454 00455 return false; 00456 } 00457 00459 void transform(const SWFMatrix& mat) 00460 { 00461 mat.transform(ap); 00462 std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end(); 00463 for(; it != ie; it++) 00464 { 00465 (*it).transform(mat); 00466 } 00467 } 00468 00470 void setNewShape() 00471 { 00472 m_new_shape=true; 00473 } 00474 00476 bool getNewShape() const 00477 { 00478 return m_new_shape; 00479 } 00480 00482 bool empty() const 00483 { 00484 return m_edges.empty(); 00485 } 00486 00488 // 00496 void setLeftFill(unsigned f) 00497 { 00498 m_fill0 = f; 00499 } 00500 00501 unsigned getLeftFill() const 00502 { 00503 return m_fill0; 00504 } 00505 00507 // 00515 void setRightFill(unsigned f) 00516 { 00517 m_fill1 = f; 00518 } 00519 00520 unsigned getRightFill() const 00521 { 00522 return m_fill1; 00523 } 00524 00526 // 00534 void setLineStyle(unsigned i) 00535 { 00536 m_line = i; 00537 } 00538 00539 unsigned getLineStyle() const 00540 { 00541 return m_line; 00542 } 00543 00545 size_t size() const 00546 { 00547 return m_edges.size(); 00548 } 00549 00551 Edge& operator[] (size_t n) 00552 { 00553 return m_edges[n]; 00554 } 00555 00557 const Edge& operator[] (size_t n) const 00558 { 00559 return m_edges[n]; 00560 } 00561 00563 bool isNewShape() const 00564 { 00565 return m_new_shape; 00566 } 00567 00568 }; // end of class Path 00569 00570 namespace geometry 00571 { 00572 00573 bool pointTest(const std::vector<Path>& paths, 00574 const std::vector<LineStyle>& lineStyles, boost::int32_t x, 00575 boost::int32_t y, const SWFMatrix& wm); 00576 00577 } // namespace geometry 00578 00579 00580 } // namespace gnash 00581 00582 #endif // GNASH_GEOMETRY_H 00583 00584 00585 // Local Variables: 00586 // mode: C++ 00587 // c-basic-offset: 8 00588 // tab-width: 8 00589 // indent-tabs-mode: t 00590 // End: