Include program counter on action limit notification log
[gnash.git] / libcore / SWFMatrix.cpp
blob7d5536efbb13974f62b520d7fc21cd15dbee3322
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 // Original author: Thatcher Ulrich <tu@tulrich.com> 2003
23 #include "SWFMatrix.h"
25 #include <cmath>
26 #include <iomanip>
28 #include "log.h"
29 #include "GnashNumeric.h"
30 #include "SWFRect.h"
31 #include "Point2d.h"
34 // This class intentionally uses overflows, which are not allowed in
35 // signed types; apart from being UB always, in practice it produces
36 // different results on different platforms.
38 // To avoid this, all calculations where an overflow could occur
39 // should use only unsigned types, but assign to the signed SWFMatrix
40 // members using only signed types. This would be much easier
41 // if the matrix values were also unsigned but were converted to
42 // signed for external users.
43 namespace gnash {
45 namespace {
47 inline double
48 rotationX(const SWFMatrix& m)
50 const double b = m.b();
51 const double a = m.a();
52 return std::atan2(b, a);
55 inline double
56 rotationY(const SWFMatrix& m)
58 const double c = m.c();
59 const double d = m.d();
60 return std::atan2(-c, d);
63 inline boost::int32_t
64 toFixed16(double a)
66 return truncateWithFactor<65536>(a);
69 inline boost::int32_t
70 multiplyFixed16(boost::int32_t a, boost::int32_t b)
72 return (static_cast<boost::int64_t>(a) *
73 static_cast<boost::int64_t>(b) + 0x8000) >> 16;
77 } // anonymous namepace
79 void
80 SWFMatrix::transform(geometry::Point2d& p) const
82 boost::int32_t t0 = multiplyFixed16(_a, p.x) + multiplyFixed16(_c, p.y) + _tx;
83 boost::int32_t t1 = multiplyFixed16(_b, p.x) + multiplyFixed16(_d, p.y) + _ty;
84 p.x = t0;
85 p.y = t1;
88 void
89 SWFMatrix::transform(boost::int32_t& x, boost::int32_t& y) const
91 const boost::int32_t t0 = multiplyFixed16(_a, x) + multiplyFixed16(_c, y) + _tx;
92 const boost::int32_t t1 = multiplyFixed16(_b,x) + multiplyFixed16(_d, y) + _ty;
93 x = t0;
94 y = t1;
97 void
98 SWFMatrix::transform(geometry::Range2d<boost::int32_t>& r) const
100 const boost::int32_t xmin = r.getMinX();
101 const boost::int32_t xmax = r.getMaxX();
102 const boost::int32_t ymin = r.getMinY();
103 const boost::int32_t ymax = r.getMaxY();
105 point p0(xmin, ymin);
106 point p1(xmin, ymax);
107 point p2(xmax, ymax);
108 point p3(xmax, ymin);
110 transform(p0);
111 transform(p1);
112 transform(p2);
113 transform(p3);
115 r.setTo(p0.x, p0.y);
116 r.expandTo(p1.x, p1.y);
117 r.expandTo(p2.x, p2.y);
118 r.expandTo(p3.x, p3.y);
121 void
122 SWFMatrix::set_identity()
124 _a = _d = 65536;
125 _b = _c = _tx = _ty = 0;
128 void
129 SWFMatrix::concatenate(const SWFMatrix& m)
131 SWFMatrix t;
132 t._a = multiplyFixed16(_a, m._a) + multiplyFixed16(_c, m._b);
133 t._b = multiplyFixed16(_b, m._a) + multiplyFixed16(_d, m._b);
134 t._c = multiplyFixed16(_a, m._c) + multiplyFixed16(_c, m._d);
135 t._d = multiplyFixed16(_b, m._c) + multiplyFixed16(_d, m._d);
136 t._tx = multiplyFixed16(_a, m._tx) + multiplyFixed16(_c, m._ty) + _tx;
137 t._ty = multiplyFixed16(_b, m._tx) + multiplyFixed16(_d, m._ty) + _ty;
139 *this = t;
142 // Concatenate a translation onto the front of our
143 // SWFMatrix. When transforming points, the translation
144 // happens first, then our original xform.
145 void
146 SWFMatrix::concatenate_translation(int xoffset, int yoffset)
148 _tx += multiplyFixed16(_a, xoffset) + multiplyFixed16(_c, yoffset);
149 _ty += multiplyFixed16(_b, xoffset) + multiplyFixed16(_d, yoffset);
152 // Concatenate scales to our SWFMatrix. When transforming points, these
153 // scales happen first, then our matrix.
154 void
155 SWFMatrix::concatenate_scale(double xscale, double yscale)
157 _a = multiplyFixed16(_a, toFixed16(xscale));
158 _c = multiplyFixed16(_c, toFixed16(yscale));
159 _b = multiplyFixed16(_b, toFixed16(xscale));
160 _d = multiplyFixed16(_d, toFixed16(yscale));
163 // Set this SWFMatrix to a blend of m1 and m2, parameterized by t.
164 void
165 SWFMatrix::set_lerp(const SWFMatrix& m1, const SWFMatrix& m2, float t)
167 _a = lerp<float>(m1._a, m2._a, t);
168 _b = lerp<float>(m1._b, m2._b, t);
169 _c = lerp<float>(m1._c, m2._c, t);
170 _d = lerp<float>(m1._d, m2._d, t);
171 _tx = lerp<float>(m1._tx, m2._tx, t);
172 _ty = lerp<float>(m1._ty, m2._ty, t);
175 // Set the scale & rotation part of the SWFMatrix.
176 // angle in radians.
177 void
178 SWFMatrix::set_scale_rotation(double x_scale, double y_scale, double angle)
180 const double cos_angle = std::cos(angle);
181 const double sin_angle = std::sin(angle);
182 _a = toFixed16(x_scale * cos_angle);
183 _c = toFixed16(y_scale * -sin_angle);
184 _b = toFixed16(x_scale * sin_angle);
185 _d = toFixed16(y_scale * cos_angle);
188 void
189 SWFMatrix::set_x_scale(double xscale)
191 const double rot_x = rotationX(*this);
192 _a = toFixed16(xscale * std::cos(rot_x));
193 _b = toFixed16(xscale * std::sin(rot_x));
196 void
197 SWFMatrix::set_y_scale(double yscale)
199 const double rot_y = rotationY(*this);
201 _c = -toFixed16(yscale * std::sin(rot_y));
202 _d = toFixed16(yscale * std::cos(rot_y));
205 void
206 SWFMatrix::set_scale(double xscale, double yscale)
208 const double rotation = get_rotation();
209 set_scale_rotation(xscale, yscale, rotation);
212 void
213 SWFMatrix::set_rotation(double rotation)
215 const double rot_x = rotationX(*this);
216 const double rot_y = rotationY(*this);
218 const double scale_x = get_x_scale();
219 const double scale_y = get_y_scale();
221 _a = toFixed16(scale_x * std::cos(rotation));
222 _b = toFixed16(scale_x * std::sin(rotation));
223 _c = -toFixed16(scale_y * std::sin(rot_y - rot_x + rotation));
224 _d = toFixed16(scale_y * std::cos(rot_y - rot_x + rotation));
227 // Transform point 'p' by our SWFMatrix. Put the result in *result.
228 void
229 SWFMatrix::transform(point* result, const point& p) const
231 assert(result);
233 result->x = multiplyFixed16(_a, p.x) + multiplyFixed16(_c, p.y) + _tx;
234 result->y = multiplyFixed16(_b, p.x) + multiplyFixed16(_d, p.y) + _ty;
237 void
238 SWFMatrix::transform(SWFRect& r) const
240 if (r.is_null()) return;
242 const boost::int32_t x1 = r.get_x_min();
243 const boost::int32_t y1 = r.get_y_min();
244 const boost::int32_t x2 = r.get_x_max();
245 const boost::int32_t y2 = r.get_y_max();
247 point p0(x1, y1);
248 point p1(x2, y1);
249 point p2(x2, y2);
250 point p3(x1, y2);
252 transform(p0);
253 transform(p1);
254 transform(p2);
255 transform(p3);
257 r.set_to_point(p0.x, p0.y);
258 r.expand_to_point(p1.x, p1.y);
259 r.expand_to_point(p2.x, p2.y);
260 r.expand_to_point(p3.x, p3.y);
263 // invert this SWFMatrix and return the result.
264 SWFMatrix&
265 SWFMatrix::invert()
267 const boost::int64_t det = determinant();
269 if (det == 0) {
270 set_identity();
271 return *this;
274 const double dn = 65536.0 * 65536.0 / det;
276 const boost::int32_t t0 = (boost::int32_t)(d() * dn);
277 _d = (boost::int32_t)(a() * dn);
278 _c = (boost::int32_t)(-c() * dn);
279 _b = (boost::int32_t)(-b() * dn);
281 const boost::int32_t t4 = -(multiplyFixed16(_tx, t0) + multiplyFixed16(_ty, _c));
282 _ty = -(multiplyFixed16(_tx, _b) + multiplyFixed16(_ty, _d));
284 _a = t0;
285 _tx = t4;
287 return *this;
290 double
291 SWFMatrix::get_x_scale() const
293 const double a2 = std::pow(static_cast<double>(a()), 2);
294 const double b2 = std::pow(static_cast<double>(b()), 2);
295 return std::sqrt(a2 + b2) / 65536.0;
298 double
299 SWFMatrix::get_y_scale() const
301 const double d2 = std::pow(static_cast<double>(d()), 2);
302 const double c2 = std::pow(static_cast<double>(c()), 2);
303 return std::sqrt(d2 + c2) / 65536.0;
306 double
307 SWFMatrix::get_rotation() const
309 return rotationX(*this);
312 // private
313 boost::int64_t
314 SWFMatrix::determinant() const
316 // | _a _c _tx |
317 // | _b _d _ty | = T. Using the Leibniz formula:
318 // | 0 0 1 |
320 // Det(T) = ( (_a * _d * 1 ) + (_c * _ty * 0) + (_tx * _b * 0) ) -
321 // ( (0 * _d * _tx) + (0 * _ty * _a) + (1 * _c * _b) )
322 // = _a * _d - _b * _c
323 return (boost::int64_t)a() * d() - (boost::int64_t)b() * c();
326 std::ostream&
327 operator<<(std::ostream& o, const SWFMatrix& m)
329 // 8 digits and a decimal point.
330 const short fieldWidth = 9;
332 o << std::endl << "|"
333 << std::setw(fieldWidth) << std::fixed << std::setprecision(4)
334 << m.a() / 65536.0 << " "
335 << std::setw(fieldWidth) << std::fixed << std::setprecision(4)
336 << m.c()/ 65536.0 << " "
337 << std::setw(fieldWidth) << std::fixed << std::setprecision(4)
338 << twipsToPixels(m.tx()) << " |"
339 << std::endl << "|"
340 << std::setw(fieldWidth) << std::fixed << std::setprecision(4)
341 << m.b()/ 65536.0 << " "
342 << std::setw(fieldWidth) << std::fixed << std::setprecision(4)
343 << m.d() / 65536.0 << " "
344 << std::setw(fieldWidth) << std::fixed << std::setprecision(4)
345 << twipsToPixels(m.ty()) << " |";
347 return o;
350 } // end namespace gnash
353 // Local Variables:
354 // mode: C++
355 // c-basic-offset: 8
356 // tab-width: 8
357 // indent-tabs-mode: t
358 // End: