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