Gnash
0.8.10
|
00001 // 00002 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 00003 // 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 const double square = squareDistancePtSeg(pt, A, B); 00126 return std::sqrt(square); 00127 } 00128 00130 // 00136 static point 00137 pointOnCurve(const point& A, const point& C, const point& B, float t) 00138 { 00139 point Q1(A, C, t); 00140 point Q2(C, B, t); 00141 point R(Q1, Q2, t); 00142 00143 return R; 00144 } 00145 00148 // 00155 static boost::int64_t squareDistancePtCurve(const point& A, 00156 const point& C, 00157 const point& B, 00158 const point& p, float t) 00159 { 00160 return p.squareDistance( pointOnCurve(A, C, B, t) ); 00161 } 00162 }; 00163 00164 00166 class DSOEXPORT Path 00167 { 00168 public: 00170 unsigned m_fill0; 00171 00173 unsigned m_fill1; 00174 00176 unsigned m_line; 00177 00179 point ap; 00180 00182 std::vector<Edge> m_edges; 00183 00188 bool m_new_shape; 00189 00191 // 00195 Path(bool newShape = false) 00196 : 00197 m_new_shape(newShape) 00198 { 00199 reset(0, 0, 0, 0, 0); 00200 } 00201 00202 Path(const Path& from) 00203 : 00204 m_fill0(from.m_fill0), 00205 m_fill1(from.m_fill1), 00206 m_line(from.m_line), 00207 ap(from.ap), 00208 m_edges(from.m_edges), 00209 m_new_shape(from.m_new_shape) 00210 { 00211 } 00212 00214 // 00235 Path(boost::int32_t ax, boost::int32_t ay, 00236 unsigned fill0, unsigned fill1, unsigned line, 00237 bool newShape) 00238 : 00239 m_new_shape(newShape) 00240 { 00241 reset(ax, ay, fill0, fill1, line); 00242 } 00243 00245 // 00257 // 00261 void reset(boost::int32_t ax, boost::int32_t ay, 00262 unsigned fill0, unsigned fill1, unsigned line) 00263 // Reset all our members to the given values, and clear our edge list. 00264 { 00265 ap.x = ax; 00266 ap.y = ay; 00267 m_fill0 = fill0; 00268 m_fill1 = fill1; 00269 m_line = line; 00270 00271 m_edges.resize(0); 00272 assert(empty()); 00273 } 00274 00276 // 00288 void 00289 expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const 00290 { 00291 const Path& p = *this; 00292 size_t nedges = m_edges.size(); 00293 00294 if ( ! nedges ) return; // this path adds nothing 00295 00296 if (thickness) 00297 { 00298 // NOTE: Half of thickness would be enough (and correct) for 00299 // radius, but that would not match how Flash calculates the 00300 // bounds using the drawing API. 00301 unsigned int radius = swfVersion < 8 ? thickness : thickness/2; 00302 00303 r.expand_to_circle(ap.x, ap.y, radius); 00304 for (unsigned int j = 0; j<nedges; j++) 00305 { 00306 r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius); 00307 r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius); 00308 } 00309 } 00310 else 00311 { 00312 r.expand_to_point(ap.x, ap.y); 00313 for (unsigned int j = 0; j<nedges; j++) 00314 { 00315 r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y); 00316 r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y); 00317 } 00318 } 00319 } 00320 00325 00327 // 00337 void 00338 drawLineTo(boost::int32_t dx, boost::int32_t dy) 00339 { 00340 m_edges.push_back(Edge(dx, dy, dx, dy)); 00341 } 00342 00344 // 00360 void 00361 drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, boost::int32_t ady) 00362 { 00363 m_edges.push_back(Edge(cdx, cdy, adx, ady)); 00364 } 00365 00367 void clear() 00368 { 00369 m_edges.resize(0); 00370 m_fill0 = m_fill1 = m_line = 0; 00371 } 00372 00374 00375 00377 bool isClosed() const 00378 { 00379 if (m_edges.empty()) return true; 00380 return m_edges.back().ap == ap; 00381 } 00382 00384 void close() 00385 { 00386 if ( m_edges.empty() ) return; 00387 00388 // Close it with a straight edge if needed 00389 const Edge& lastedge = m_edges.back(); 00390 if ( lastedge.ap != ap ) 00391 { 00392 Edge newedge(ap, ap); 00393 m_edges.push_back(newedge); 00394 } 00395 } 00396 00400 // 00403 bool 00404 withinSquareDistance(const point& p, double dist) const 00405 { 00406 size_t nedges = m_edges.size(); 00407 00408 if ( ! nedges ) return false; 00409 00410 point px(ap); 00411 for (size_t i=0; i<nedges; ++i) 00412 { 00413 const Edge& e = m_edges[i]; 00414 point np(e.ap); 00415 00416 if (e.straight()) 00417 { 00418 double d = Edge::squareDistancePtSeg(p, px, np); 00419 if ( d <= dist ) return true; 00420 } 00421 else 00422 { 00423 00424 const point& A = px; 00425 const point& C = e.cp; 00426 const point& B = e.ap; 00427 00428 // Approximate the curve to segCount segments 00429 // and compute distance of query point from each 00430 // segment. 00431 // 00432 // TODO: find an apprpriate value for segCount based 00433 // on rendering scale ? 00434 // 00435 int segCount = 10; 00436 point p0(A.x, A.y); 00437 for (int i=1; i<=segCount; ++i) 00438 { 00439 float t1 = static_cast<float>(i) / segCount; 00440 point p1 = Edge::pointOnCurve(A, C, B, t1); 00441 00442 // distance from point and segment being an approximation 00443 // of the curve 00444 double d = Edge::squareDistancePtSeg(p, p0, p1); 00445 if ( d <= dist ) return true; 00446 00447 p0.setTo(p1.x, p1.y); 00448 } 00449 } 00450 px = np; 00451 } 00452 00453 return false; 00454 } 00455 00457 void transform(const SWFMatrix& mat) 00458 { 00459 mat.transform(ap); 00460 std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end(); 00461 for(; it != ie; ++it) 00462 { 00463 (*it).transform(mat); 00464 } 00465 } 00466 00468 void setNewShape() 00469 { 00470 m_new_shape=true; 00471 } 00472 00474 bool getNewShape() const 00475 { 00476 return m_new_shape; 00477 } 00478 00480 bool empty() const 00481 { 00482 return m_edges.empty(); 00483 } 00484 00486 // 00494 void setLeftFill(unsigned f) 00495 { 00496 m_fill0 = f; 00497 } 00498 00499 unsigned getLeftFill() const 00500 { 00501 return m_fill0; 00502 } 00503 00505 // 00513 void setRightFill(unsigned f) 00514 { 00515 m_fill1 = f; 00516 } 00517 00518 unsigned getRightFill() const 00519 { 00520 return m_fill1; 00521 } 00522 00524 // 00532 void setLineStyle(unsigned i) 00533 { 00534 m_line = i; 00535 } 00536 00537 unsigned getLineStyle() const 00538 { 00539 return m_line; 00540 } 00541 00543 size_t size() const 00544 { 00545 return m_edges.size(); 00546 } 00547 00549 Edge& operator[] (size_t n) 00550 { 00551 return m_edges[n]; 00552 } 00553 00555 const Edge& operator[] (size_t n) const 00556 { 00557 return m_edges[n]; 00558 } 00559 00561 bool isNewShape() const 00562 { 00563 return m_new_shape; 00564 } 00565 00566 }; // end of class Path 00567 00568 namespace geometry 00569 { 00570 00571 bool pointTest(const std::vector<Path>& paths, 00572 const std::vector<LineStyle>& lineStyles, boost::int32_t x, 00573 boost::int32_t y, const SWFMatrix& wm); 00574 00575 } // namespace geometry 00576 00577 00578 } // namespace gnash 00579 00580 #endif // GNASH_GEOMETRY_H 00581 00582 00583 // Local Variables: 00584 // mode: C++ 00585 // c-basic-offset: 8 00586 // tab-width: 8 00587 // indent-tabs-mode: t 00588 // End: