FastUIDraw
fastuidraw_banded_rays.glsl.hpp
Go to the documentation of this file.
1 /*!
2  * \file fastuidraw_banded_rays.glsl.hpp
3  * \brief file fastuidraw_banded_rays.glsl.hpp
4  *
5  * Copyright 2018 by Intel.
6  *
7  * Contact: kevin.rogovin@gmail.com
8  *
9  * This Source Code Form is subject to the
10  * terms of the Mozilla Public License, v. 2.0.
11  * If a copy of the MPL was not distributed with
12  * this file, You can obtain one at
13  * http://mozilla.org/MPL/2.0/.
14  *
15  * \author Kevin Rogovin <kevin.rogovin@gmail.com>
16  *
17  */
18 
19 /*!\addtogroup GLSLFragCode
20  * @{
21  */
22 
23 ///@cond
24 
25 /* must have the macro/function
26  *
27  * fastuidraw_fetch_glyph_data(X)
28  *
29  * that returns a single 32-bit uint value at index X of
30  * a large array of 32-bit uint values storing the data
31  *
32  * and optionally define the macro/function
33  *
34  * fastuidraw_fetch_glyph_data_fp16x2(X)
35  *
36  * the reads a single 32-bit uint value that is bit-casted
37  * to a (fp16, fp16) pair realized as a vec2. For example
38  * it can be defined as
39  * unpackHalf2x16(fastuidraw_fetch_glyph_data(X))
40  */
41 
42 struct fastuidraw_banded_rays_band
43 {
44  uint num_curves;
45  uint curve_offset;
46 };
47 
48 struct fastuidraw_banded_rays_curve
49 {
50  vec2 p1, p2, p3;
51 };
52 
53 struct fastuidraw_banded_rays_distance_type
54 {
55  float distance_increment;
56  float distance_decrement;
57 };
58 
59 void
60 fastuidraw_banded_rays_init_distance(out fastuidraw_banded_rays_distance_type nv)
61 {
62  /* Just initialize to some value that is large (strictly speaking
63  * we only need a value greater than 0.5, but make it larger
64  * for debug renders to be useful).
65  */
66  nv.distance_increment = nv.distance_decrement = 120.0;
67 }
68 
69 void
70 fastuidraw_banded_rays_update_distance(in float dist, in bool is_increment,
71  inout fastuidraw_banded_rays_distance_type nv)
72 {
73  /* We are assuming that there are no cancelling curves in the glyph data.
74  * The class GlyphRenderDataRestrictedRays has code to detect most forms
75  * of cancelling curves (it detects partially overlapping vertical and
76  * horizontal curves along with perfectly overlapping general curves),
77  * but GlyphRenderDataBandedRays does not.
78  */
79  if (is_increment)
80  {
81  nv.distance_increment = min(nv.distance_increment, dist);
82  }
83  else
84  {
85  nv.distance_decrement = min(nv.distance_decrement, dist);
86  }
87 }
88 
89 void
90 fastuidraw_banded_rays_load_band(in uint loc, out fastuidraw_banded_rays_band band)
91 {
92  uint raw;
93 
94  raw = fastuidraw_fetch_glyph_data(loc);
95  band.num_curves = FASTUIDRAW_EXTRACT_BITS(fastuidraw_banded_rays_numcurves_bit0,
96  fastuidraw_banded_rays_numcurves_numbits,
97  raw);
98  band.curve_offset = FASTUIDRAW_EXTRACT_BITS(fastuidraw_banded_rays_curveoffset_bit0,
99  fastuidraw_banded_rays_curveoffset_numbits,
100  raw);
101 }
102 
103 vec2
104 fastuidraw_banded_rays_load_point(in uint loc)
105 {
107 }
108 
109 void
110 fastuidraw_banded_rays_load_curve(in uint loc, out fastuidraw_banded_rays_curve curve)
111 {
112  curve.p1 = fastuidraw_banded_rays_load_point(loc);
113  curve.p2 = fastuidraw_banded_rays_load_point(loc + 1u);
114  curve.p3 = fastuidraw_banded_rays_load_point(loc + 2u);
115 }
116 
117 int
118 fastuidraw_banded_rays_compute_winding_contribution(in fastuidraw_banded_rays_curve curve,
119  inout fastuidraw_banded_rays_distance_type dst,
120  in float winding_effect_multiplier)
121 {
122  vec2 A, B, C;
123  int R = 0;
124  bool use_t1, use_t2;
125  float t1, t2, x1, x2, y1, y2;
126  const float quad_tol = 0.0001;
127 
128  /* See fastuidraw_restricted_rays.glsl.resource_string
129  * for an explanation of what is going on here.
130  */
131  A = curve.p1 - 2.0 * curve.p2 + curve.p3;
132  B = curve.p1 - curve.p2;
133  C = curve.p1;
134 
135  use_t1 = (curve.p3.y < 0.0 && curve.p1.y > 0.0)
136  || (curve.p3.y < 0.0 && curve.p2.y > 0.0)
137  || (curve.p1.y >= 0.0 && curve.p2.y < 0.0);
138 
139  use_t2 = (curve.p1.y < 0 && curve.p2.y > 0.0)
140  || (curve.p1.y < 0.0 && curve.p3.y > 0.0)
141  || (curve.p3.y >= 0.0 && curve.p2.y < 0.0);
142 
143  if (abs(A.y) > quad_tol)
144  {
145  float D, rA;
146 
147  D = B.y * B.y - A.y * C.y;
148  if (D < 0.0)
149  {
150  t1 = t2 = 2.0;
151  use_t1 = use_t2 = false;
152  }
153  else
154  {
155  rA = 1.0 / A.y;
156  D = sqrt(D);
157 
158  t1 = (B.y - D) * rA;
159  t2 = (B.y + D) * rA;
160  }
161  }
162  else
163  {
164  t1 = t2 = 0.5 * C.y / B.y;
165  }
166 
167  if (use_t1)
168  {
169  x1 = (A.x * t1 - B.x * 2.0) * t1 + C.x;
170  if (x1 >= 0.0)
171  {
172  R += 1;
173  }
174 
175  fastuidraw_banded_rays_update_distance(abs(x1), winding_effect_multiplier * x1 < 0.0, dst);
176  }
177 
178  if (use_t2)
179  {
180  x2 = (A.x * t2 - B.x * 2.0) * t2 + C.x;
181  if (x2 >= 0.0)
182  {
183  R -= 1;
184  }
185 
186  fastuidraw_banded_rays_update_distance(abs(x2), winding_effect_multiplier * x2 > 0.0, dst);
187  }
188 
189  return R;
190 }
191 
192 void
193 fastuidraw_banded_rays_compute_coverage_from_band(in uint curve_offset,
194  in uint num_curves,
195  in vec2 glyph_coord,
196  in float em,
197  in float ray_direction,
198  in float coordinate_permutation_factor,
199  out int winding,
200  inout fastuidraw_banded_rays_distance_type nv)
201 {
202  winding = 0;
203 
204  /* the effect on the winding number is to negate it if the ray direction
205  * is negative and to negate it (possible again) if the xy coordinates
206  * are swapped
207  */
208  coordinate_permutation_factor *= ray_direction;
209 
210  /* collapse em into the ray direction to reduce the multiplies a little */
211  ray_direction *= em;
212  for (uint c = 0u, curve_src = curve_offset; c < num_curves; curve_src += 3u, ++c)
213  {
214  fastuidraw_banded_rays_curve curve;
215 
216  fastuidraw_banded_rays_load_curve(curve_src, curve);
217 
218  /* translate the curve so that glyph_coord is the origin */
219  curve.p1 -= glyph_coord;
220  curve.p2 -= glyph_coord;
221  curve.p3 -= glyph_coord;
222 
223  /* orient the curves in the direction of the ray */
224  curve.p1.x *= ray_direction;;
225  curve.p2.x *= ray_direction;
226  curve.p3.x *= ray_direction;
227 
228  if (max(curve.p1.x, max(curve.p2.x, curve.p3.x)) < -0.5)
229  break;
230 
231  winding += fastuidraw_banded_rays_compute_winding_contribution(curve, nv, coordinate_permutation_factor);
232  }
233 
234  winding *= int(coordinate_permutation_factor);
235 }
236 ///@endcond
237 
238 /*!
239  * Compute the coverage of a fragment within a \ref fastuidraw::GlyphRenderDataBandedRays glyph.
240  * \param glyph_data_location location of the glyph data (see \ref
241  * fastuidraw::GlyphRenderDataBandedRays::glyph_offset)
242  * \param glyph_coord the coordinate of the fragment in glyph coordinates
243  * \param glyph_coord_fwidth the value of fwidth(glyph_coord)
244  * \param num_vertical_bands the number of vertical bands of the glyph, see \ref
245  * fastuidraw::GlyphRenderDataBandedRays::glyph_num_vertical_bands
246  * \param num_horizontal_bands the number of horizontal bands of the glyph, see \ref
247  * fastuidraw::GlyphRenderDataBandedRays::glyph_num_horizontal_bands
248  * \param use_odd_even_rule if true, use the odd-even fill rule, otherwise use the non-zero fill rule.
249  */
250 float
251 fastuidraw_banded_rays_compute_coverage(in uint glyph_data_location,
252  in vec2 glyph_coord,
253  in vec2 glyph_coord_fwidth,
254  in uint num_vertical_bands,
255  in uint num_horizontal_bands,
256  in bool use_odd_even_rule)
257 {
258  uint horiz_band_offset, vert_band_offset;
259  uint c, curve_src, num_curves, curve_offset;
260  vec2 ray_direction, em, band_factor;
261  fastuidraw_banded_rays_distance_type nv;
262  ivec2 winding;
263  uint horiz_band, vert_band;
264  fastuidraw_banded_rays_band horiz_band_data, vert_band_data;
265 
266  em = vec2(1.0, 1.0) / glyph_coord_fwidth;
267  fastuidraw_banded_rays_init_distance(nv);
268 
269  /* Glyph coord varies -exactly- as [-G, G]x[-G, G]
270  * where G = fastuidraw_banded_rays_glyph_coord.
271  * So to figure out which band, we need to renormalized
272  * [-G, G]x[-G, G] to [0, V]x[0, H].
273  */
274  band_factor = fastuidraw_banded_rays_glyph_coord_half_recip * vec2(num_vertical_bands, num_horizontal_bands);
275  vert_band = min(num_vertical_bands - 1u,
276  uint(band_factor.x * (glyph_coord.x + fastuidraw_banded_rays_glyph_coord)));
277  horiz_band = min(num_horizontal_bands - 1u,
278  uint(band_factor.y * (glyph_coord.y + fastuidraw_banded_rays_glyph_coord)));
279 
280  /* choose which bands, which in turn chooses the direction of the ray */
281  horiz_band_offset = horiz_band;
282  if (glyph_coord.x < 0.0)
283  {
284  horiz_band_offset += num_horizontal_bands;
285  ray_direction.x = -1.0;
286  }
287  else
288  {
289  ray_direction.x = 1.0;
290  }
291 
292  vert_band_offset = vert_band + 2u * num_horizontal_bands;
293  if (glyph_coord.y < 0.0)
294  {
295  vert_band_offset += num_vertical_bands;
296  ray_direction.y = -1.0;
297  }
298  else
299  {
300  ray_direction.y = +1.0;
301  }
302 
303  /* load the horizontal and vertical band headers */
304  fastuidraw_banded_rays_load_band(glyph_data_location + horiz_band_offset, horiz_band_data);
305  fastuidraw_banded_rays_load_band(glyph_data_location + vert_band_offset, vert_band_data);
306 
307  fastuidraw_banded_rays_compute_coverage_from_band(horiz_band_data.curve_offset + glyph_data_location,
308  horiz_band_data.num_curves, glyph_coord,
309  em.x, ray_direction.x, 1.0, winding.x, nv);
310 
311  /* the curves for the vertical bands are saved with the x-coordinate
312  * and y-coordinate swapped; this way we can avoid writing more
313  * routines (to handle the xy-swapping) and just swap the xy-coords
314  * of glyph_coords; this causes the orientation to change which is
315  * why the -1 for coordinate_permutation_factor is passed.
316  */
317  fastuidraw_banded_rays_compute_coverage_from_band(vert_band_data.curve_offset + glyph_data_location,
318  vert_band_data.num_curves, glyph_coord.yx,
319  em.y, ray_direction.y, -1.0, winding.y, nv);
320 
321  float distance, cvg;
322  int winding_number = winding.x;
323 
324  if (winding_number == 0 || use_odd_even_rule)
325  {
326  distance = min(nv.distance_increment,
327  nv.distance_decrement);
328  }
329  else if (winding_number == -1)
330  {
331  distance = nv.distance_increment;
332  }
333  else if (winding_number == 1)
334  {
335  distance = nv.distance_decrement;
336  }
337  else
338  {
339  distance = 0.5;
340  }
341 
342  distance = min(distance, 0.5);
343  winding_number = (use_odd_even_rule && (winding_number & 1) == 0) ? 0 : winding_number;
344  cvg = (winding_number != 0) ?
345  (0.5 + distance) :
346  (0.5 - distance);
347 
348  return cvg;
349 }
350 /*! @} */
#define fastuidraw_fetch_glyph_data_fp16x2(X)
vecN< float, 2 > vec2
Definition: vecN.hpp:1231
reference y(void)
Definition: vecN.hpp:443
#define FASTUIDRAW_EXTRACT_BITS(bit0, num_bits, src)
#define fastuidraw_fetch_glyph_data(X)
vecN< int32_t, 2 > ivec2
Definition: vecN.hpp:1265
float fastuidraw_banded_rays_compute_coverage(in uint glyph_data_location, in vec2 glyph_coord, in vec2 glyph_coord_fwidth, in uint num_vertical_bands, in uint num_horizontal_bands, in bool use_odd_even_rule)