Support unrar64.dll
[xy_vsfilter.git] / src / subtitles / libssf / Glyph.cpp
blob4d43df190556fa32d6d16595eb43b26e54634c2d
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
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 2, or (at your option)
8 * 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.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "stdafx.h"
23 #include "Glyph.h"
24 #include "Split.h"
26 #define deg2rad(d) (float)(M_PI/180*(d))
28 namespace ssf
30 Glyph::Glyph()
32 c = 0;
33 font = NULL;
34 ascent = descent = width = spacing = fill = 0;
35 tl.x = tl.y = tls.x = tls.y = 0;
38 float Glyph::GetBackgroundSize() const
40 return style.background.size * (scale.cx + scale.cy) / 2;
43 float Glyph::GetShadowDepth() const
45 return style.shadow.depth * (scale.cx + scale.cy) / 2;
48 CRect Glyph::GetClipRect() const
50 CRect r = bbox + tl;
52 int size = (int)(GetBackgroundSize() + 0.5);
53 int depth = (int)(GetShadowDepth() + 0.5);
55 r.InflateRect(size, size);
56 r.InflateRect(depth, depth);
58 r.left >>= 6;
59 r.top >>= 6;
60 r.right = (r.right + 32) >> 6;
61 r.bottom = (r.bottom + 32) >> 6;
63 return r;
66 void Glyph::CreateBkg()
68 path_bkg.RemoveAll();
70 if(style.background.type == L"enlarge" && style.background.size > 0)
72 path_bkg.Enlarge(path, GetBackgroundSize());
74 else if(style.background.type == L"box" && style.background.size >= 0)
76 if(c != ssf::Text::LSEP)
78 int s = (int)(GetBackgroundSize() + 0.5);
79 int x0 = (!vertical ? -spacing/2 : ascent - row_ascent);
80 int y0 = (!vertical ? ascent - row_ascent : -spacing/2);
81 int x1 = x0 + (!vertical ? width + spacing : row_ascent + row_descent);
82 int y1 = y0 + (!vertical ? row_ascent + row_descent : width + spacing);
83 path_bkg.types.SetCount(4);
84 path_bkg.types[0] = PT_MOVETO;
85 path_bkg.types[1] = PT_LINETO;
86 path_bkg.types[2] = PT_LINETO;
87 path_bkg.types[3] = PT_LINETO;
88 path_bkg.points.SetCount(4);
89 path_bkg.points[0] = CPoint(x0-s, y0-s);
90 path_bkg.points[1] = CPoint(x1+s, y0-s);
91 path_bkg.points[2] = CPoint(x1+s, y1+s);
92 path_bkg.points[3] = CPoint(x0-s, y1+s);
97 void Glyph::CreateSplineCoeffs(const CRect& spdrc)
99 spline.RemoveAll();
101 if(style.placement.path.IsEmpty())
102 return;
104 size_t i = 0, j = style.placement.path.GetCount();
106 CAtlArray<Point> pts;
107 pts.SetCount(j + 2);
109 Point p;
111 while(i < j)
113 p.x = style.placement.path[i].x * scale.cx + spdrc.left * 64;
114 p.y = style.placement.path[i].y * scale.cy + spdrc.top * 64;
115 pts[++i] = p;
118 if(pts.GetCount() >= 4)
120 if(pts[1].x == pts[j].x && pts[1].y == pts[j].y)
122 pts.SetAt(0, pts[j-1]);
123 pts.SetAt(j+1, pts[2]);
125 else
127 p.x = pts[1].x*2 - pts[2].x;
128 p.y = pts[1].y*2 - pts[2].y;
129 pts.SetAt(0, p);
131 p.x = pts[j].x*2 - pts[j-1].x;
132 p.y = pts[j].y*2 - pts[j-1].y;
133 pts.SetAt(j+1, p);
136 spline.SetCount(pts.GetCount()-3);
138 for(size_t i = 0, j = pts.GetCount()-4; i <= j; i++)
140 static const float _1div6 = 1.0f / 6;
142 SplineCoeffs sc;
144 sc.cx[3] = _1div6*(- pts[i+0].x + 3*pts[i+1].x - 3*pts[i+2].x + pts[i+3].x);
145 sc.cx[2] = _1div6*( 3*pts[i+0].x - 6*pts[i+1].x + 3*pts[i+2].x);
146 sc.cx[1] = _1div6*(-3*pts[i+0].x + 3*pts[i+2].x);
147 sc.cx[0] = _1div6*( pts[i+0].x + 4*pts[i+1].x + 1*pts[i+2].x);
149 sc.cy[3] = _1div6*(- pts[i+0].y + 3*pts[i+1].y - 3*pts[i+2].y + pts[i+3].y);
150 sc.cy[2] = _1div6*( 3*pts[i+0].y - 6*pts[i+1].y + 3*pts[i+2].y);
151 sc.cy[1] = _1div6*(-3*pts[i+0].y + 3*pts[i+2].y);
152 sc.cy[0] = _1div6*( pts[i+0].y + 4*pts[i+1].y + 1*pts[i+2].y);
154 spline.SetAt(i, sc);
159 void Glyph::Transform(GlyphPath& path, CPoint org, const CRect& subrect)
161 // TODO: add sse code path
163 float sx = style.font.scale.cx;
164 float sy = style.font.scale.cy;
166 bool brotate = style.placement.angle.x || style.placement.angle.y || style.placement.angle.z;
167 bool bspline = !spline.IsEmpty();
168 bool bscale = brotate || bspline || sx != 1 || sy != 1;
170 float caz = cos(deg2rad(style.placement.angle.z));
171 float saz = sin(deg2rad(style.placement.angle.z));
172 float cax = cos(deg2rad(style.placement.angle.x));
173 float sax = sin(deg2rad(style.placement.angle.x));
174 float cay = cos(deg2rad(style.placement.angle.y));
175 float say = sin(deg2rad(style.placement.angle.y));
177 for(size_t i = 0, j = path.types.GetCount(); i < j; i++)
179 CPoint p = path.points[i];
181 if(bscale)
183 float x, y, z, xx, yy, zz;
185 x = sx * (p.x - org.x);
186 y = sy * (p.y - org.y);
187 z = 0;
189 if(bspline)
191 float pos = vertical ? y + org.y + tl.y - subrect.top : x + org.x + tl.x - subrect.left;
192 float size = vertical ? subrect.Size().cy : subrect.Size().cx;
193 float dist = vertical ? x : y;
195 const SplineCoeffs* sc;
196 float t;
198 if(pos >= size)
200 sc = &spline[spline.GetCount() - 1];
201 t = 1;
203 else
205 float u = size / spline.GetCount();
206 sc = &spline[max((int)(pos / u), 0)];
207 t = fmod(pos, u) / u;
210 float nx = sc->cx[1] + 2*t*sc->cx[2] + 3*t*t*sc->cx[3];
211 float ny = sc->cy[1] + 2*t*sc->cy[2] + 3*t*t*sc->cy[3];
212 float nl = 1.0f / sqrt(nx*nx + ny*ny);
214 nx *= nl;
215 ny *= nl;
217 x = sc->cx[0] + t*(sc->cx[1] + t*(sc->cx[2] + t*sc->cx[3])) - ny * dist - org.x - tl.x;
218 y = sc->cy[0] + t*(sc->cy[1] + t*(sc->cy[2] + t*sc->cy[3])) + nx * dist - org.y - tl.y;
221 if(brotate)
223 xx = x*caz + y*saz;
224 yy = -(x*saz - y*caz);
225 zz = z;
227 x = xx;
228 y = yy*cax + zz*sax;
229 z = yy*sax - zz*cax;
231 xx = x*cay + z*say;
232 yy = y;
233 zz = x*say - z*cay;
235 zz = 1.0f / (max(zz, -19000) + 20000);
237 x = (xx * 20000) * zz;
238 y = (yy * 20000) * zz;
241 p.x = (int)(x + org.x + 0.5);
242 p.y = (int)(y + org.y + 0.5);
244 path.points[i] = p;
247 if(p.x < bbox.left) bbox.left = p.x;
248 if(p.x > bbox.right) bbox.right = p.x;
249 if(p.y < bbox.top) bbox.top = p.y;
250 if(p.y > bbox.bottom) bbox.bottom = p.y;
254 void Glyph::Transform(CPoint org, const CRect& subrect)
256 if(!style.placement.org.auto_x) org.x = style.placement.org.x * scale.cx;
257 if(!style.placement.org.auto_y) org.y = style.placement.org.y * scale.cy;
259 org -= tl;
261 bbox.SetRect(INT_MAX, INT_MAX, INT_MIN, INT_MIN);
263 Transform(path_bkg, org, subrect);
264 Transform(path, org, subrect);
266 bbox |= CRect(0, 0, 0, 0);
269 void Glyph::Rasterize()
271 if(!path_bkg.IsEmpty())
273 ras_bkg.ScanConvert(path_bkg, bbox);
274 ras_bkg.Rasterize(tl.x, tl.y);
277 ras.ScanConvert(path, bbox);
279 if(style.background.type == L"outline" && style.background.size > 0)
281 ras.CreateWidenedRegion((int)(GetBackgroundSize() + 0.5));
286 Rasterizer* r = path_bkg.IsEmpty() ? &ras : &ras_bkg;
287 int plane = path_bkg.IsEmpty() ? (style.font.color.a < 255 ? 2 : 1) : 0;
289 ras.Rasterize(tl.x, tl.y);
290 r->Blur(style.background.blur, plane);
292 if(style.shadow.depth > 0)
294 ras_shadow.Reuse(*r);
296 float depth = GetShadowDepth();
298 tls.x = tl.x + (int)(depth * cos(deg2rad(style.shadow.angle)) + 0.5);
299 tls.y = tl.y + (int)(depth * -sin(deg2rad(style.shadow.angle)) + 0.5);
301 ras_shadow.Rasterize(tls.x, tls.y);
302 ras_shadow.Blur(style.shadow.blur, plane ? 1 : 0);