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)
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
26 #define deg2rad(d) (float)(M_PI/180*(d))
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
52 int size
= (int)(GetBackgroundSize() + 0.5);
53 int depth
= (int)(GetShadowDepth() + 0.5);
55 r
.InflateRect(size
, size
);
56 r
.InflateRect(depth
, depth
);
60 r
.right
= (r
.right
+ 32) >> 6;
61 r
.bottom
= (r
.bottom
+ 32) >> 6;
66 void Glyph::CreateBkg()
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
)
101 if(style
.placement
.path
.IsEmpty())
104 size_t i
= 0, j
= style
.placement
.path
.GetCount();
106 CAtlArray
<Point
> pts
;
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;
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]);
127 p
.x
= pts
[1].x
*2 - pts
[2].x
;
128 p
.y
= pts
[1].y
*2 - pts
[2].y
;
131 p
.x
= pts
[j
].x
*2 - pts
[j
-1].x
;
132 p
.y
= pts
[j
].y
*2 - pts
[j
-1].y
;
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;
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
);
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
];
183 float x
, y
, z
, xx
, yy
, zz
;
185 x
= sx
* (p
.x
- org
.x
);
186 y
= sy
* (p
.y
- org
.y
);
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
;
200 sc
= &spline
[spline
.GetCount() - 1];
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
);
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
;
224 yy
= -(x
*saz
- y
*caz
);
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);
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
;
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);