FastUIDraw
fastuidraw_restricted_rays.glsl.hpp
Go to the documentation of this file.
1 /*!
2  * \file fastuidraw_restricted_rays.glsl.hpp
3  * \brief file fastuidraw_restricted_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_restricted_rays_transformation
43 {
44  vec2 translation;
45  vec2 t_vector, jq_vector;
46  float reference_location, orientation;
47 };
48 
49 struct fastuidraw_restricted_rays_curve_type
50 {
51  vec2 p1, p2, p3;
52  bool is_quadratic;
53 };
54 
55 struct fastuidraw_restricted_rays_box_type
56 {
57  vec2 min_point, max_point, center_point, size;
58 };
59 
60 struct fastuidraw_restricted_rays_distance_type
61 {
62  float distance_increment;
63  float distance_decrement;
64 };
65 
66 struct fastuidraw_restricted_rays_winding_sample_type
67 {
68  int reference_winding;
69  vec2 reference_position;
70 };
71 
72 void
73 fastuidraw_restricted_rays_init_distance(out fastuidraw_restricted_rays_distance_type nv)
74 {
75  /* Just initialize to some value that is large (strictly speaking
76  * we only need a value greater than 0.5, but make it larger
77  * for debug renders to be useful).
78  */
79  nv.distance_increment = nv.distance_decrement = 120.0;
80 }
81 
82 void
83 fastuidraw_restricted_rays_update_distance(in float dist, in bool is_increment,
84  inout fastuidraw_restricted_rays_distance_type nv)
85 {
86  /* We are assuming that there are no cancelling curves in the glyph data.
87  * The class GlyphRenderDataRestrictedRays has code to detect most forms
88  * of cancelling curves (it detects partially overlapping vertical and
89  * horizontal curves along with perfectly overlapping general curves).
90  */
91  if (is_increment)
92  {
93  nv.distance_increment = min(nv.distance_increment, dist);
94  }
95  else
96  {
97  nv.distance_decrement = min(nv.distance_decrement, dist);
98  }
99 }
100 
101 void
102 fastuidraw_restricted_rays_update_distance(in vec2 p, in bool is_increment,
103  inout fastuidraw_restricted_rays_distance_type nv)
104 {
105  float d;
106 
107  d = abs(p.x) + abs(p.y);
108  fastuidraw_restricted_rays_update_distance(d, is_increment, nv);
109 }
110 
111 bool
112 fastuidraw_restricted_rays_is_increment(in vec2 p, in vec2 dp)
113 {
114  float det;
115 
116  /* The vector from the origin to the point is given by the point value, p.
117  * the direction of the curve is given by dp. When crossing the curve in the
118  * direction from the origin to p, the winding is incremented if the pair
119  * (p, dp) forms a 2x2 matrix that has positive determinant and decrements
120  * otherwise.
121  */
122  det = p.x * dp.y - p.y * dp.x;
123  return det > 0.0;
124 }
125 
126 void
127 fastuidraw_restricted_rays_update_distance(in vec2 p, in vec2 dp,
128  inout fastuidraw_restricted_rays_distance_type nv)
129 {
130  fastuidraw_restricted_rays_update_distance(p, fastuidraw_restricted_rays_is_increment(p, dp), nv);
131 }
132 
133 uint
134 fastuidaw_restricted_rays_compute_box(in vec2 p,
135  in uint data_location,
136  out fastuidraw_restricted_rays_box_type box,
137  out uint curve_list,
138  out uint num_curves)
139 {
140  uint v, offset;
141 
142  box.min_point = vec2(-fastuidraw_restricted_rays_glyph_coord_value, -fastuidraw_restricted_rays_glyph_coord_value);
143  box.max_point = vec2(fastuidraw_restricted_rays_glyph_coord_value, fastuidraw_restricted_rays_glyph_coord_value);
144 
145  offset = data_location;
146  v = fastuidraw_fetch_glyph_data(offset);
147 
148  while((v & fastuidraw_restricted_rays_hierarchy_node_mask) != 0u)
149  {
150  uint c, bit0;
151  float split_pt;
152  bool take_max_choice;
153 
154  c = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_hierarchy_split_coord_bit, 1u, v);
155  if (c == 0u)
156  {
157  split_pt = 0.5 * (box.min_point.x + box.max_point.x);
158  take_max_choice = (p.x > split_pt);
159  box.min_point.x = (take_max_choice) ? split_pt : box.min_point.x;
160  box.max_point.x = (take_max_choice) ? box.max_point.x : split_pt;
161  }
162  else
163  {
164  split_pt = 0.5 * (box.min_point.y + box.max_point.y);
165  take_max_choice = (p.y > split_pt);
166  box.min_point.y = (take_max_choice) ? split_pt : box.min_point.y;
167  box.max_point.y = (take_max_choice) ? box.max_point.y : split_pt;
168  }
169 
170  bit0 = (take_max_choice) ?
171  fastuidraw_restricted_rays_hierarchy_child1_bit:
172  fastuidraw_restricted_rays_hierarchy_child0_bit;
173  offset = FASTUIDRAW_EXTRACT_BITS(bit0,
174  fastuidraw_restricted_rays_hierarchy_child_num_bits,
175  v);
176  offset += data_location;
177  v = fastuidraw_fetch_glyph_data(offset);
178  }
179 
180  box.size = box.max_point - box.min_point;
181  box.center_point = 0.5 * (box.min_point + box.max_point);
182  curve_list = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_hierarchy_curve_list_bit0,
183  fastuidraw_restricted_rays_hierarchy_curve_list_num_bits,
184  v);
185  num_curves = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_hierarchy_curve_list_size_bit0,
186  fastuidraw_restricted_rays_hierarchy_curve_list_size_num_bits,
187  v);
188 
189  return offset + 1u;
190 }
191 
192 vec2
193 fastuidraw_restricted_rays_unpack_point(in uint ptr)
194 {
196 }
197 
198 void
199 fastuidraw_restricted_rays_compute_transformation(in vec2 frag_point,
200  in vec2 frag_point_dx,
201  in vec2 frag_point_dy,
202  in vec2 reference_point,
203  out fastuidraw_restricted_rays_transformation tr)
204 {
205  /* We need to create a matrix M that has the following properties:
206  * 1. M(q) = (V, 0) where q = reference_point - frag_point
207  * and V can be any non-negative value
208  * 2. M * F is a rotation where F is the 2x2 matrix giving the
209  * the local transformation from window coordinates to
210  * glyph coordinates.
211  *
212  *
213  * The computation for M is as follows:
214  * Let Q be st F(Q) = q.
215  * Let T be st <T, Q> = 0, i.e. T = J(Q) where J(x, y) = (-y, x)
216  * Let t = J(F(T))
217  *
218  * thus,
219  *
220  * t = (J * F * J * Finverse)(q)
221  *
222  * The matrix F is given by
223  *
224  * | frag_point_dx.x frag_point_dy.x |
225  * | frag_point_dx.y frag_point_dy.y |
226  *
227  * For any matrix K
228  *
229  * | a b |
230  * | c d |
231  *
232  * the matrix J * K * J * Kinverse is given by
233  *
234  * | -(cc + dd) / R (ac + bd) / R |
235  * | (ac + bd) / R -(aa + bb) / R |
236  *
237  * where R is det(K). Since we are only needing the
238  * direction of the vector t, we can skip the divide
239  * by R. Letting L be the above matrix, we set N to
240  * be the matrix
241  *
242  * | t.x t.y |
243  * | jq.x jq.y |
244  *
245  * where jq = (-q.y, q.x) and t = L * q. Finally,
246  * M is given by N scaled so that F*jq and F*t have
247  * unit L1-length, M*jq = (V, 0) with V > 0 and
248  * M is orientation preserving (this is required
249  * because if M reverses orientation the winding
250  * changes to the refernece point would then need
251  * to be negated).
252  */
253 
254  vec2 q, top_row, bottom_row, em;
255  float a, b, c, d;
256 
257  tr.translation = frag_point;
258  q = reference_point - frag_point;
259  tr.jq_vector.x = -q.y;
260  tr.jq_vector.y = q.x;
261 
262  a = frag_point_dx.x;
263  b = frag_point_dy.x;
264  c = frag_point_dx.y;
265  d = frag_point_dy.y;
266 
267  top_row.x = -(c * c + d * d);
268  top_row.y = bottom_row.x = (a * c + b * d);
269  bottom_row.y = -(a * a + b * b);
270 
271  tr.t_vector.x = dot(top_row, q);
272  tr.t_vector.y = dot(bottom_row, q);
273 
274  /* em represents the normalization so that the pre-image of t_vector
275  * and jq_vector in screen coordinates has length 1.
276  */
277  em.x = abs(dot(tr.t_vector, frag_point_dx)) + abs(dot(tr.t_vector, frag_point_dy));
278  em.y = abs(dot(tr.jq_vector, frag_point_dx)) + abs(dot(tr.jq_vector, frag_point_dy));
279 
280  /* Prevent divide by zero. if em.x or em.y is very small, that means
281  * that on screen the x (repsectively y) local coordinate axis is
282  * severely stretched. Since the sample point is to be reasonably
283  * far from any curve, clamping em.x and em.y away from zero will
284  * not have effect on coverage computation.
285  */
286  const float min_em = 1e-7;
287  em.x = max(em.x, min_em);
288  em.y = max(em.y, min_em);
289 
290  tr.t_vector /= em.x;
291  tr.jq_vector /= em.y;
292  tr.reference_location = dot(tr.t_vector, q);
293 
294  if (tr.reference_location < 0.0)
295  {
296  /* we need to send q to (V, 0) where
297  * V is positive.
298  */
299  tr.t_vector = -tr.t_vector;
300  tr.reference_location = -tr.reference_location;
301  }
302 
303  float det;
304 
305  det = (tr.t_vector.x * tr.jq_vector.y - tr.t_vector.y * tr.jq_vector.x);
306  /* we need the transformation to be orientation preserving.
307  * The only requirement we have on jq_vector is that
308  * dot(jq_vector, q) is zero, so negate jq_vector to get the
309  * transformation matrix to be orientation preserving.
310  */
311  if (det < 0.0)
312  {
313  tr.jq_vector = -tr.jq_vector;
314  }
315 }
316 
317 vec2
318 fastuidraw_restricted_rays_apply_transformation(in vec2 p,
319  in fastuidraw_restricted_rays_transformation tr)
320 {
321  p -= tr.translation;
322  return vec2(dot(tr.t_vector, p),
323  dot(tr.jq_vector, p));
324 }
325 
326 int
327 fastuidraw_restricted_rays_compute_winding_contribution(in fastuidraw_restricted_rays_curve_type curve,
328  in fastuidraw_restricted_rays_transformation tr,
329  inout fastuidraw_restricted_rays_distance_type dst)
330 {
331  vec2 A, B, C;
332  int R = 0;
333  bool use_t1, use_t2;
334  float t1, t2, x1, x2, y1, y2;
335  const float quad_tol = 0.0001;
336 
337  curve.p1 = fastuidraw_restricted_rays_apply_transformation(curve.p1, tr);
338  curve.p2 = fastuidraw_restricted_rays_apply_transformation(curve.p2, tr);
339  curve.p3 = fastuidraw_restricted_rays_apply_transformation(curve.p3, tr);
340 
341  A = curve.p1 - 2.0 * curve.p2 + curve.p3;
342  B = curve.p1 - curve.p2;
343  C = curve.p1;
344 
345  /*
346  * Let
347  *
348  * f(t) = [p1, p2, p3](t) = At^2 - 2Bt + C
349  *
350  * where
351  *
352  * A = p1 - 2p2 + p3
353  * B = p1 - p2
354  * C = p1
355  *
356  * we wish to solve for t so that f_y(t) = 0 but enforce that
357  * 0 < t < 1. Dropping the .y suffixes, the quadratic formula
358  * gives us the two roots:
359  *
360  * t1 = (B - sqrt(B^2 - AC)) / A
361  * t2 = (B + sqrt(B^2 - AC)) / A
362  *
363  * using 0 < t < 1 directly is numerically unstable, instead
364  * we will use algebra to enforce that condition from p1, p2, p3.
365  * When A > 0, high school algebra yields
366  *
367  * 0 < t1 < 1 if and only if (p1 > p2 && p1 > 0 && (p3 > p2 || p3 < 0))
368  * 0 < t2 < 1 if and only if (p3 > p2 && p3 > 0 && (p1 > p2 || p1 < 0))
369  *
370  * which, again via high school algebra (under the condition A > 0),
371  * becomes
372  *
373  * 0 < t1 < 1 if and only if (p1 > 0 && (p2 < 0 || p3 < 0))
374  * 0 < t2 < 1 if and only if (p3 > 0 && (p2 < 0 || p1 < 0))
375  *
376  * These inequalities are incorrect if A < 0. For the case where
377  * A < 0, the same high school algebra techniques give
378  *
379  * 0 < t1 < 1 if and only if (p3 < 0 && (p2 > 0 || p1 > 0))
380  * 0 < t2 < 1 if and only if (p1 < 0 && (p2 > 0 || p3 > 0))
381  *
382  * Putting together gives
383  *
384  * 0 < t1 < 1 if and only if (p3 < 0 && (p2 > 0 || p1 > 0) && A < 0) || (p1 > 0 && (p2 < 0 || p3 < 0) && A > 0)
385  * 0 < t2 < 1 if and only if (p1 < 0 && (p2 > 0 || p3 > 0) && A < 0) || (p3 > 0 && (p2 < 0 || p1 < 0) && A > 0)
386  *
387  * We can still simplify more. Indeed, the value of
388  *
389  * (p3 < 0 && (p2 > 0 || p1 > 0) && A < 0) | (p1 > 0 && (p2 < 0 || p3 < 0) && A > 0)
390  *
391  * is equivalent to via algebra (by examining the three cases (p1 <= 0),
392  * (p3 >= 0) and (p1 > 0 && p3 < 0) to:
393  *
394  * (p3 < 0 && (p2 > 0 || p1 > 0)) || (p1 > 0 && (p2 < 0 || p3 < 0))
395  *
396  * Similair logic gives that
397  *
398  * (p1 < 0 && (p2 > 0 || p3 > 0) && A < 0) || (p3 > 0 && (p2 < 0 || p1 < 0) && A > 0)
399  *
400  * is equivalent to
401  *
402  * (p1 < 0 && (p2 > 0 || p3 > 0)) || (p3 > 0 && (p2 < 0 || p1 < 0))
403  *
404  * Which implies that instead of having a conditional branch on A < 0,
405  * we can just put a logical of them together. Therefore,
406  *
407  * T1 = (p3 < 0 && (p2 > 0 || p1 > 0)) || (p1 > 0 && (p2 < 0 || p3 < 0))
408  * = (p3 < 0 && p1 > 0) || (p3 < 0 && p2 > 0) || (p1 > 0 && p2 < 0) || (p1 > 0 && p3 < 0)
409  * = (p3 < 0 && p1 > 0) || (p3 < 0 && p2 > 0) || (p1 > 0 && p2 < 0)
410  *
411  * T2 = (p1 < 0 && (p2 > 0 || p3 > 0)) || (p3 > 0 && (p2 < 0 || p1 < 0))
412  * = (p1 < 0 && p2 > 0) || (p1 < 0 && p3 > 0) || (p3 > 0 && p1 < 0) || (p3 > 0 && p2 < 0)
413  * = (p1 < 0 && p2 > 0) || (p1 < 0 && p3 > 0) || (p3 > 0 && p2 < 0)
414  *
415  * The last issue is to handle the end-points of the curve correctly.
416  * We use the rules:
417  *
418  * (a) use 0 if and only if f(0) = 0 && f'(0) < 0
419  * (b) use 1 if and only if f(1) = 1 && f'(1) > 0
420  *
421  * Which become
422  *
423  * (a) use 0 if and only if p1 == 0 && p2 < p1
424  * (b) use 1 if and only if p3 == 0 && p2 < p3
425  *
426  * If p1.y is zero, then
427  *
428  * t1 = (B - |B|) / A
429  * t2 = (B + |B|) / A
430  *
431  * If p2 < 0 = p1, then B > 0 and thus t1 = 0, i.e.
432  * use t1 whenever (a) is true.
433  *
434  * If p3.y is zero, then algebra will give that
435  *
436  * t1 = ((p1 - p2) - |p2|) / (p1 - 2p2)
437  * t2 = ((p1 - p2) + |p2|) / (p1 - 2p2)
438  *
439  * thus on condition (b) gives
440  *
441  * t1 = p1 / (p1 - 2p2)
442  * t2 = 1
443  *
444  * which means use t2 when (b) is true.
445  *
446  * Thus,
447  *
448  * use_t1 = T1 || (p1 == 0 && p2 < 0)
449  * = (p3 < 0 && p1 > 0) || (p3 < 0 && p2 > 0) || (p1 >= 0 && p2 < 0)
450  *
451  * use_t2 = T2 || (p3 == 0 && p2 < 0)
452  * = (p1 < 0 && p2 > 0) || (p1 < 0 && p3 > 0) || (p3 >= 0 && p2 < 0)
453  */
454  use_t1 = (curve.p3.y < 0.0 && curve.p1.y > 0.0)
455  || (curve.p3.y < 0.0 && curve.p2.y > 0.0)
456  || (curve.p1.y >= 0.0 && curve.p2.y < 0.0);
457 
458  use_t2 = (curve.p1.y < 0 && curve.p2.y > 0.0)
459  || (curve.p1.y < 0.0 && curve.p3.y > 0.0)
460  || (curve.p3.y >= 0.0 && curve.p2.y < 0.0);
461 
462  if (curve.is_quadratic && abs(A.y) > quad_tol)
463  {
464  float D, rA;
465 
466  D = B.y * B.y - A.y * C.y;
467  if (D < 0.0)
468  {
469  /* the parobola does not go through y = 0, thus it does
470  * not contribute to the winding number.
471  */
472  t1 = t2 = 2.0;
473  use_t1 = use_t2 = false;
474  }
475  else
476  {
477  rA = 1.0 / A.y;
478  D = sqrt(D);
479 
480  t1 = (B.y - D) * rA;
481  t2 = (B.y + D) * rA;
482  }
483  }
484  else
485  {
486  t1 = t2 = 0.5 * C.y / B.y;
487  }
488 
489  /* We know that t1 always increments and t2 always decerements
490  * the winding number via
491  *
492  * f_y(t) = Ay * (t - t1) * (t - t2)
493  * f_y'(t) = Ay * (t - t1) + Ay * (t - t2)
494  *
495  * then
496  * if Ay < 0, then t1 > t2 and thus f_y'(t1) < 0 and f_y'(t2) > 0
497  * if Ay > 0, then t1 < t2 and thus f_y'(t1) < 0 and f_y'(t2) > 0
498  */
499  if (use_t1)
500  {
501  x1 = (A.x * t1 - B.x * 2.0) * t1 + C.x;
502  if (x1 <= tr.reference_location && x1 >= 0.0)
503  {
504  R += 1;
505  }
506  fastuidraw_restricted_rays_update_distance(abs(x1), x1 < 0.0, dst);
507  }
508 
509  if (use_t2)
510  {
511  x2 = (A.x * t2 - B.x * 2.0) * t2 + C.x;
512  if (x2 <= tr.reference_location && x2 >= 0.0)
513  {
514  R -= 1;
515  }
516  fastuidraw_restricted_rays_update_distance(abs(x2), x2 > 0.0, dst);
517  }
518 
519  /* we do the x-solve just for the distance function,
520  * since we are just aiming for a distance, we can
521  * use the numerically unstable 0 <= t <= 1 instead
522  * of the nasty condition from the control points
523  * directly.
524  */
525  if (curve.is_quadratic && abs(A.x) > quad_tol)
526  {
527  float D;
528 
529  D = B.x * B.x - A.x * C.x;
530  if (D < 0.0)
531  {
532  use_t1 = use_t2 = false;
533  }
534  else
535  {
536  float rA = 1.0 / A.x;
537 
538  D = sqrt(D);
539  t1 = (B.x - D) * rA;
540  t2 = (B.x + D) * rA;
541 
542  use_t1 = (t1 >= 0.0 && t1 <= 1.0);
543  use_t2 = (t2 >= 0.0 && t2 <= 1.0);
544  }
545  }
546  else
547  {
548  t1 = t2 = 0.5 * C.x / B.x;
549  use_t1 = (curve.p1.x > 0.0 && curve.p3.x < 0.0);
550  use_t2 = (curve.p1.x < 0.0 && curve.p3.x > 0.0);
551  }
552 
553  /* For the same resason that t1 always increments the winding
554  * and t2 always decrements the winding, we know that only
555  * the sign of y1 and y2 effect which distance they should
556  * update.
557  */
558  if (use_t1)
559  {
560  y1 = (A.y * t1 - B.y * 2.0) * t1 + C.y;
561  fastuidraw_restricted_rays_update_distance(abs(y1), y1 > 0.0, dst);
562  }
563 
564  if (use_t2)
565  {
566  y2 = (A.y * t2 - B.y * 2.0) * t2 + C.y;
567  fastuidraw_restricted_rays_update_distance(abs(y2), y2 < 0.0, dst);
568  }
569 
570  /* We are just computing a distance-like value to perform anti-aliasing;
571  * as such we can skip computing the other critical points for the L1-distance
572  * function f(t) = |x(t) - x| + |y(t) - y| which are the end points and the
573  * points p(t) = (x(t), y(t)) where |x'(t)| = |y'(t)|. The points correspond
574  * to
575  *
576  * t1 = (A.x - A.y) / (B.x - B.y)
577  * t2 = (A.x + A.y) / (B.x + B.y)
578  *
579  * If we are to check the end-points, we would need to only check t = 0.
580  * This is because if t = 1 is within the cell, then the curve that starts
581  * at t = 1 would also be within the cell. Checking the end point t = 0
582  * is the code:
583  *
584  * fastuidraw_restricted_rays_update_distance(curve.p1, -B, dst);
585  *
586  * this is because the curve is p(t) = At^2 -2Bt + C, thus its
587  * derivative is p'(t) = -2At - 2B which at p'(0) = -2B. We only need
588  * the direction of the derivative in the 2nd argument, so -B is
589  * sufficient and the curve at 0 is curve.p1.
590  *
591  * TODO: decide if doing the proper L1-distance is necessary.
592  */
593  return R;
594 }
595 
596 void
597 fastuidraw_restricted_rays_load_curve(in uint raw,
598  in uint glyph_data_location,
599  out fastuidraw_restricted_rays_curve_type curve)
600 {
601  uint curve_src;
602 
603  curve_src = glyph_data_location + FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_curve_bit0,
604  fastuidraw_restricted_rays_curve_num_bits,
605  raw);
606  curve.is_quadratic = (raw & fastuidraw_restricted_rays_curve_is_quadratic_mask) != 0u;
607 
608  curve.p1 = fastuidraw_restricted_rays_unpack_point(curve_src);
609  curve.p2 = fastuidraw_restricted_rays_unpack_point(curve_src + 1u);
610 
611  if (curve.is_quadratic)
612  {
613  curve.p3 = fastuidraw_restricted_rays_unpack_point(curve_src + 2u);
614  }
615  else
616  {
617  curve.p3 = curve.p2;
618  curve.p2 = 0.5 * (curve.p1 + curve.p3);
619  }
620 }
621 
622 int
623 fastuidraw_restricted_rays_load_and_process_curve(in uint raw,
624  in uint glyph_data_location,
625  in fastuidraw_restricted_rays_transformation tr,
626  inout fastuidraw_restricted_rays_distance_type nv)
627 {
628  fastuidraw_restricted_rays_curve_type curve_data;
629  int return_value;
630 
631  fastuidraw_restricted_rays_load_curve(raw,
632  glyph_data_location,
633  curve_data);
634 
635 
636  return_value =
637  fastuidraw_restricted_rays_compute_winding_contribution(curve_data, tr, nv);
638  return return_value;
639 }
640 
641 void
642 fastuidraw_restricted_rays_load_winding_reference(in uint location,
643  in fastuidraw_restricted_rays_box_type box,
644  out fastuidraw_restricted_rays_winding_sample_type s)
645 {
646  uint texel, biased_winding;
647  uvec2 uint_delta;
648  vec2 position, delta;
649 
650  position = box.min_point;
651  texel = fastuidraw_fetch_glyph_data(location);
652 
653  biased_winding = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_winding_value_bit0,
654  fastuidraw_restricted_rays_winding_value_num_bits, texel);
655  uint_delta.x = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_position_delta_x_bit0,
656  fastuidraw_restricted_rays_position_delta_num_bits, texel);
657  uint_delta.y = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_position_delta_y_bit0,
658  fastuidraw_restricted_rays_position_delta_num_bits, texel);
659 
660  delta = vec2(uint_delta) * box.size;
661  delta /= float(fastuidraw_restricted_rays_position_delta_divide);
662  position += delta;
663 
664  s.reference_position = position;
665  s.reference_winding = int(biased_winding) - int(fastuidraw_restricted_rays_winding_value_bias);
666 }
667 
668 float
669 fastuidraw_restricted_rays_compute_coverage(in uint glyph_data_location,
670  in vec2 glyph_coord,
671  in vec2 glyph_coord_dx,
672  in vec2 glyph_coord_dy,
673  in bool use_odd_even_rule
674  #ifdef FASTUIDRAW_DEBUG
675  ,out fastuidraw_restricted_rays_box_type out_texel_box,
676  out fastuidraw_restricted_rays_winding_sample_type out_S,
677  out int out_winding_number, out uint out_num_curves,
678  out fastuidraw_restricted_rays_distance_type out_nv
679  #endif
680  )
681 {
682  uint src, c, curve_list, winding_sample_data_location;
683  fastuidraw_restricted_rays_transformation tr;
684  fastuidraw_restricted_rays_box_type texel_box;
685  fastuidraw_restricted_rays_winding_sample_type S;
686  int winding_number;
687  uint num_curves;
688  fastuidraw_restricted_rays_distance_type nv;
689 
690  winding_sample_data_location =
691  fastuidaw_restricted_rays_compute_box(glyph_coord,
692  glyph_data_location,
693  texel_box, curve_list, num_curves);
694  fastuidraw_restricted_rays_init_distance(nv);
695  fastuidraw_restricted_rays_load_winding_reference(winding_sample_data_location,
696  texel_box, S);
697 
698  fastuidraw_restricted_rays_compute_transformation(glyph_coord,
699  glyph_coord_dx, glyph_coord_dy,
700  S.reference_position, tr);
701  winding_number = S.reference_winding;
702 
703  src = curve_list + glyph_data_location;
704  for (c = 0u; c < num_curves; c += 2u)
705  {
706  uint cA, cB, curve_pair;
707 
708  curve_pair = fastuidraw_fetch_glyph_data(src);
709  ++src;
710 
711  cA = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_curve_entry0_bit0,
712  fastuidraw_restricted_rays_curve_entry_num_bits,
713  curve_pair);
714  winding_number += fastuidraw_restricted_rays_load_and_process_curve(cA, glyph_data_location, tr, nv);
715 
716  if (c + 1u < num_curves)
717  {
718  cB = FASTUIDRAW_EXTRACT_BITS(fastuidraw_restricted_rays_curve_entry1_bit0,
719  fastuidraw_restricted_rays_curve_entry_num_bits,
720  curve_pair);
721  winding_number += fastuidraw_restricted_rays_load_and_process_curve(cB, glyph_data_location, tr, nv);
722  }
723  }
724 
725  float cvg, distance;
726 
727  /* If using the odd-even fill rule of if the winding number at
728  * the fragment is 0, use the minimum of those two; if the
729  * winding value is 1 use the decrement value and if the winding
730  * is -1 use the increment winding number; if the absolute value
731  * of the winding value is greater than two, we will fallback
732  * and simply view the fragment as fully covered.
733  */
734  if (winding_number == 0 || use_odd_even_rule)
735  {
736  distance = min(nv.distance_increment,
737  nv.distance_decrement);
738  }
739  else if (winding_number == -1)
740  {
741  distance = nv.distance_increment;
742  }
743  else if (winding_number == 1)
744  {
745  distance = nv.distance_decrement;
746  }
747  else
748  {
749  distance = 0.5;
750  }
751 
752  distance = min(distance, 0.5);
753  winding_number = (use_odd_even_rule && (winding_number & 1) == 0) ? 0 : winding_number;
754  cvg = (winding_number != 0) ?
755  (0.5 + distance) :
756  (0.5 - distance);
757 
758  #ifdef FASTUIDRAW_DEBUG
759  {
760  out_texel_box = texel_box;
761  out_S = S;
762  out_winding_number = winding_number;
763  out_num_curves = num_curves;
764  out_nv = nv;
765  }
766  #endif
767 
768  return cvg;
769 }
770 
771 #ifdef FASTUIDRAW_DEBUG
772 float
773 fastuidraw_restricted_rays_compute_coverage(in uint glyph_data_location,
774  in vec2 glyph_coord,
775  in vec2 glyph_coord_dx,
776  in vec2 glyph_coord_dy,
777  in bool use_odd_even_rule)
778 {
779  fastuidraw_restricted_rays_box_type texel_box;
780  fastuidraw_restricted_rays_winding_sample_type S;
781  fastuidraw_restricted_rays_distance_type nv;
782  int winding_number;
783  uint num_curves;
784 
785  return fastuidraw_restricted_rays_compute_coverage(glyph_data_location,
786  glyph_coord,
787  glyph_coord_dx, glyph_coord_dy,
788  use_odd_even_rule,
789  texel_box, S, winding_number,
790  num_curves, nv);
791 }
792 #endif
793 ///@endcond
794 
795 /*!
796  * Compute the coverage of a fragment within a \ref fastuidraw::GlyphRenderDataRestrictedRays glyph.
797  * \param glyph_data_location location of the glyph data (see \ref
798  * fastuidraw::GlyphRenderDataRestrictedRays::glyph_offset)
799  * \param glyph_coord the coordinate of the fragment in glyph coordinates
800  * \param glyph_coord_dx the value of dFdx(glyph_coord)
801  * \param glyph_coord_dy the value of dFdy(glyph_coord)
802  * \param use_odd_even_rule if true, use the odd-even fill rule, otherwise use the non-zero fill rule.
803  */
804 float
805 fastuidraw_restricted_rays_compute_coverage(in uint glyph_data_location,
806  in vec2 glyph_coord,
807  in vec2 glyph_coord_dx,
808  in vec2 glyph_coord_dy,
809  in bool use_odd_even_rule);
810 /*! @} */
float fastuidraw_restricted_rays_compute_coverage(in uint glyph_data_location, in vec2 glyph_coord, in vec2 glyph_coord_dx, in vec2 glyph_coord_dy, in bool use_odd_even_rule)
#define fastuidraw_fetch_glyph_data_fp16x2(X)
vecN< float, 2 > vec2
Definition: vecN.hpp:1231
vecN< uint32_t, 2 > uvec2
Definition: vecN.hpp:1282
#define FASTUIDRAW_EXTRACT_BITS(bit0, num_bits, src)
T dot(const vecN< T, N > &a, const vecN< T, N > &b)
Definition: vecN.hpp:1124
#define fastuidraw_fetch_glyph_data(X)
static size_t size(void)
Definition: vecN.hpp:1060
reference x(void)
Definition: vecN.hpp:435