1/*
2 * Copyright 2012 Google, Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Google Author(s): Behdad Esfahbod, Maysum Panju
17 */
18
19
20#ifndef GLYPHY_INFINITY
21#  define GLYPHY_INFINITY 1e9
22#endif
23#ifndef GLYPHY_EPSILON
24#  define GLYPHY_EPSILON  1e-5
25#endif
26
27#ifndef GLYPHY_RGBA
28#  ifdef GLYPHY_BGRA
29#    define GLYPHY_RGBA(v) glyphy_bgra (v)
30#  else
31#    define GLYPHY_RGBA(v) glyphy_rgba (v)
32#  endif
33#endif
34
35vec4
36glyphy_rgba (const vec4 v)
37{
38  return v.rgba;
39}
40
41vec4
42glyphy_bgra (const vec4 v)
43{
44  return v.bgra;
45}
46
47
48struct glyphy_arc_t {
49  vec2  p0;
50  vec2  p1;
51  float d;
52};
53
54struct glyphy_arc_endpoint_t {
55  /* Second arc endpoint */
56  vec2  p;
57  /* Infinity if this endpoint does not form an arc with the previous
58   * endpoint.  Ie. a "move_to".  Test with glyphy_isinf().
59   * Arc depth otherwise.  */
60  float d;
61};
62
63struct glyphy_arc_list_t {
64  /* Number of endpoints in the list.
65   * Will be zero if we're far away inside or outside, in which case side is set.
66   * Will be -1 if this arc-list encodes a single line, in which case line_* are set. */
67  int num_endpoints;
68
69  /* If num_endpoints is zero, this specifies whether we are inside (-1)
70   * or outside (+1).  Otherwise we're unsure (0). */
71  int side;
72  /* Offset to the arc-endpoints from the beginning of the glyph blob */
73  int offset;
74
75  /* A single line is all we care about.  It's right here. */
76  float line_angle;
77  float line_distance; /* From nominal glyph center */
78};
79
80bool
81glyphy_isinf (const float v)
82{
83  return abs (v) >= GLYPHY_INFINITY * .5;
84}
85
86bool
87glyphy_iszero (const float v)
88{
89  return abs (v) <= GLYPHY_EPSILON * 2.;
90}
91
92vec2
93glyphy_ortho (const vec2 v)
94{
95  return vec2 (-v.y, v.x);
96}
97
98int
99glyphy_float_to_byte (const float v)
100{
101  return int (v * (256. - GLYPHY_EPSILON));
102}
103
104ivec4
105glyphy_vec4_to_bytes (const vec4 v)
106{
107  return ivec4 (v * (256. - GLYPHY_EPSILON));
108}
109
110ivec2
111glyphy_float_to_two_nimbles (const float v)
112{
113  int f = glyphy_float_to_byte (v);
114  return ivec2 (f / 16, int(mod (float(f), 16.)));
115}
116
117/* returns tan (2 * atan (d)) */
118float
119glyphy_tan2atan (const float d)
120{
121  return 2. * d / (1. - d * d);
122}
123
124glyphy_arc_endpoint_t
125glyphy_arc_endpoint_decode (const vec4 v, const ivec2 nominal_size)
126{
127  vec2 p = (vec2 (glyphy_float_to_two_nimbles (v.a)) + v.gb) / 16.;
128  float d = v.r;
129  if (d == 0.)
130    d = GLYPHY_INFINITY;
131  else
132#define GLYPHY_MAX_D .5
133    d = float(glyphy_float_to_byte (d) - 128) * GLYPHY_MAX_D / 127.;
134#undef GLYPHY_MAX_D
135  return glyphy_arc_endpoint_t (p * vec2(nominal_size), d);
136}
137
138vec2
139glyphy_arc_center (const glyphy_arc_t a)
140{
141  return mix (a.p0, a.p1, .5) +
142	 glyphy_ortho (a.p1 - a.p0) / (2. * glyphy_tan2atan (a.d));
143}
144
145bool
146glyphy_arc_wedge_contains (const glyphy_arc_t a, const vec2 p)
147{
148  float d2 = glyphy_tan2atan (a.d);
149  return dot (p - a.p0, (a.p1 - a.p0) * mat2(1,  d2, -d2, 1)) >= 0. &&
150	 dot (p - a.p1, (a.p1 - a.p0) * mat2(1, -d2,  d2, 1)) <= 0.;
151}
152
153float
154glyphy_arc_wedge_signed_dist_shallow (const glyphy_arc_t a, const vec2 p)
155{
156  vec2 v = normalize (a.p1 - a.p0);
157  float line_d = dot (p - a.p0, glyphy_ortho (v));
158  if (a.d == 0.)
159    return line_d;
160
161  float d0 = dot ((p - a.p0), v);
162  if (d0 < 0.)
163    return sign (line_d) * distance (p, a.p0);
164  float d1 = dot ((a.p1 - p), v);
165  if (d1 < 0.)
166    return sign (line_d) * distance (p, a.p1);
167  float r = 2. * a.d * (d0 * d1) / (d0 + d1);
168  if (r * line_d > 0.)
169    return sign (line_d) * min (abs (line_d + r), min (distance (p, a.p0), distance (p, a.p1)));
170  return line_d + r;
171}
172
173float
174glyphy_arc_wedge_signed_dist (const glyphy_arc_t a, const vec2 p)
175{
176  if (abs (a.d) <= .03)
177    return glyphy_arc_wedge_signed_dist_shallow (a, p);
178  vec2 c = glyphy_arc_center (a);
179  return sign (a.d) * (distance (a.p0, c) - distance (p, c));
180}
181
182float
183glyphy_arc_extended_dist (const glyphy_arc_t a, const vec2 p)
184{
185  /* Note: this doesn't handle points inside the wedge. */
186  vec2 m = mix (a.p0, a.p1, .5);
187  float d2 = glyphy_tan2atan (a.d);
188  if (dot (p - m, a.p1 - m) < 0.)
189    return dot (p - a.p0, normalize ((a.p1 - a.p0) * mat2(+d2, -1, +1, +d2)));
190  else
191    return dot (p - a.p1, normalize ((a.p1 - a.p0) * mat2(-d2, -1, +1, -d2)));
192}
193
194int
195glyphy_arc_list_offset (const vec2 p, const ivec2 nominal_size)
196{
197  ivec2 cell = ivec2 (clamp (floor (p), vec2 (0.,0.), vec2(nominal_size - 1)));
198  return cell.y * nominal_size.x + cell.x;
199}
200
201glyphy_arc_list_t
202glyphy_arc_list_decode (const vec4 v, const ivec2 nominal_size)
203{
204  glyphy_arc_list_t l;
205  ivec4 iv = glyphy_vec4_to_bytes (v);
206  l.side = 0; /* unsure */
207  if (iv.r == 0) { /* arc-list encoded */
208    l.offset = (iv.g * 256) + iv.b;
209    l.num_endpoints = iv.a;
210    if (l.num_endpoints == 255) {
211      l.num_endpoints = 0;
212      l.side = -1;
213    } else if (l.num_endpoints == 0)
214      l.side = +1;
215  } else { /* single line encoded */
216    l.num_endpoints = -1;
217    l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 0x4000) / float (0x1FFF)
218                    * max (float (nominal_size.x), float (nominal_size.y));
219    l.line_angle = float(-((iv.b * 256 + iv.a) - 0x8000)) / float (0x7FFF) * 3.14159265358979;
220  }
221  return l;
222}
223