Blender  V3.3
lineart_chain.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. All rights reserved. */
3 
8 #include "BLI_linklist.h"
9 #include "BLI_listbase.h"
10 #include "BLI_math.h"
11 
12 #include "MOD_lineart.h"
13 
14 #include "lineart_intern.h"
15 
16 #include <math.h>
17 
18 #define LRT_OTHER_VERT(e, vt) ((vt) == (e)->v1 ? (e)->v2 : ((vt) == (e)->v2 ? (e)->v1 : NULL))
19 
20 struct Object;
21 
22 /* Get a connected line, only for lines who has the exact given vert, or (in the case of
23  * intersection lines) who has a vert that has the exact same position. */
25  LineartVert *vt,
26  LineartVert **new_vt,
27  int match_flag,
28  uint8_t match_isec_mask,
29  struct Object *match_isec_object)
30 {
31  for (int i = 0; i < ba->line_count; i++) {
32  LineartEdge *n_e = ba->linked_lines[i];
33 
34  if ((!(n_e->flags & LRT_EDGE_FLAG_ALL_TYPE)) || (n_e->flags & LRT_EDGE_FLAG_CHAIN_PICKED)) {
35  continue;
36  }
37 
38  if (match_flag && ((n_e->flags & LRT_EDGE_FLAG_ALL_TYPE) & match_flag) == 0) {
39  continue;
40  }
41 
42  if (n_e->intersection_mask != match_isec_mask) {
43  continue;
44  }
45 
46  *new_vt = LRT_OTHER_VERT(n_e, vt);
47  if (*new_vt) {
48  return n_e;
49  }
50 
51  if (n_e->flags & LRT_EDGE_FLAG_INTERSECTION) {
52  if (n_e->object_ref != match_isec_object) {
53  continue;
54  }
55  if (vt->fbcoord[0] == n_e->v1->fbcoord[0] && vt->fbcoord[1] == n_e->v1->fbcoord[1]) {
56  *new_vt = LRT_OTHER_VERT(n_e, n_e->v1);
57  return n_e;
58  }
59  if (vt->fbcoord[0] == n_e->v2->fbcoord[0] && vt->fbcoord[1] == n_e->v2->fbcoord[1]) {
60  *new_vt = LRT_OTHER_VERT(n_e, n_e->v2);
61  return n_e;
62  }
63  }
64  }
65 
66  return NULL;
67 }
68 
70 {
71  LineartEdgeChain *ec;
73 
74  BLI_addtail(&ld->chains, ec);
75 
76  return ec;
77 }
78 
80  float x,
81  float y,
82  double threshold)
83 {
84  if (!eci) {
85  return false;
86  }
87  if (((eci->pos[0] + threshold) >= x) && ((eci->pos[0] - threshold) <= x) &&
88  ((eci->pos[1] + threshold) >= y) && ((eci->pos[1] - threshold) <= y)) {
89  return true;
90  }
91  return false;
92 }
93 
95  LineartEdgeChain *ec,
96  float fbcoord[4],
97  float gpos[3],
98  float normal[3],
99  uint8_t type,
100  int level,
101  uint8_t material_mask_bits,
102  uint32_t shadow_mask_bits,
103  size_t index)
104 {
106 
107  if (lineart_point_overlapping(ec->chain.last, fbcoord[0], fbcoord[1], 1e-5)) {
108  /* Because the new chain point is overlapping, just replace the type and occlusion level of the
109  * current point. This makes it so that the line to the point after this one has the correct
110  * type and level. */
111  LineartEdgeChainItem *old_eci = ec->chain.last;
112  old_eci->line_type = type;
113  old_eci->occlusion = level;
114  old_eci->material_mask_bits = material_mask_bits;
115  old_eci->shadow_mask_bits = shadow_mask_bits;
116  return old_eci;
117  }
118 
120 
121  copy_v4_v4(eci->pos, fbcoord);
122  copy_v3_v3(eci->gpos, gpos);
123  eci->index = index;
124  copy_v3_v3(eci->normal, normal);
126  eci->occlusion = level;
127  eci->material_mask_bits = material_mask_bits;
128  eci->shadow_mask_bits = shadow_mask_bits;
129  BLI_addtail(&ec->chain, eci);
130 
131  return eci;
132 }
133 
135  LineartEdgeChain *ec,
136  float fbcoord[4],
137  float gpos[3],
138  float normal[3],
139  uint8_t type,
140  int level,
141  uint8_t material_mask_bits,
142  uint32_t shadow_mask_bits,
143  size_t index)
144 {
146 
147  if (lineart_point_overlapping(ec->chain.first, fbcoord[0], fbcoord[1], 1e-5)) {
148  return ec->chain.first;
149  }
150 
152 
153  copy_v4_v4(eci->pos, fbcoord);
154  copy_v3_v3(eci->gpos, gpos);
155  eci->index = index;
156  copy_v3_v3(eci->normal, normal);
158  eci->occlusion = level;
159  eci->material_mask_bits = material_mask_bits;
160  eci->shadow_mask_bits = shadow_mask_bits;
161  BLI_addhead(&ec->chain, eci);
162 
163  return eci;
164 }
165 
167 {
168  LineartEdgeChain *ec;
171  LineartEdgeSegment *es;
172  int last_occlusion;
173  uint8_t last_transparency;
174  uint32_t last_shadow;
175  /* Used when converting from double. */
176  float use_fbcoord[4];
177  float use_gpos[3];
178 
179 #define VERT_COORD_TO_FLOAT(a) \
180  copy_v4fl_v4db(use_fbcoord, (a)->fbcoord); \
181  copy_v3fl_v3db(use_gpos, (a)->gloc);
182 
183 #define POS_TO_FLOAT(lpos, gpos) \
184  copy_v3fl_v3db(use_fbcoord, lpos); \
185  copy_v3fl_v3db(use_gpos, gpos);
186 
188  {
189  if ((!(e->flags & LRT_EDGE_FLAG_ALL_TYPE)) || (e->flags & LRT_EDGE_FLAG_CHAIN_PICKED)) {
191  continue;
192  }
193 
194  e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
195 
196  ec = lineart_chain_create(ld);
197 
198  /* One chain can only have one object_ref and intersection_mask,
199  * so we assign them based on the first segment we found. */
200  ec->object_ref = e->object_ref;
201  ec->intersection_mask = e->intersection_mask;
202 
203  LineartEdge *new_e;
204  LineartVert *new_vt;
205  float N[3] = {0};
206 
207  if (e->t1) {
208  N[0] += e->t1->gn[0];
209  N[1] += e->t1->gn[1];
210  N[2] += e->t1->gn[2];
211  }
212  if (e->t2) {
213  N[0] += e->t2->gn[0];
214  N[1] += e->t2->gn[1];
215  N[2] += e->t2->gn[2];
216  }
217  if (e->t1 || e->t2) {
218  normalize_v3(N);
219  }
220 
221  /* Step 1: grow left. */
222  ba = MOD_lineart_get_bounding_area(ld, e->v1->fbcoord[0], e->v1->fbcoord[1]);
223  new_vt = e->v1;
224  es = e->segments.first;
225  VERT_COORD_TO_FLOAT(new_vt);
227  ec,
228  use_fbcoord,
229  use_gpos,
230  N,
231  e->flags,
232  es->occlusion,
233  es->material_mask_bits,
234  es->shadow_mask_bits,
235  e->v1->index);
236  while (ba && (new_e = lineart_line_get_connected(
237  ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) {
239 
240  if (new_e->t1 || new_e->t2) {
241  zero_v3(N);
242  if (new_e->t1) {
243  N[0] += new_e->t1->gn[0];
244  N[1] += new_e->t1->gn[1];
245  N[2] += new_e->t1->gn[2];
246  }
247  if (new_e->t2) {
248  N[0] += new_e->t2->gn[0];
249  N[1] += new_e->t2->gn[1];
250  N[2] += new_e->t2->gn[2];
251  }
252  normalize_v3(N);
253  }
254 
255  if (new_vt == new_e->v1) {
256  for (es = new_e->segments.last; es; es = es->prev) {
257  double gpos[3], lpos[3];
258  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
259  double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
260  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
261  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
262  use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
263  POS_TO_FLOAT(lpos, gpos)
265  ec,
266  use_fbcoord,
267  use_gpos,
268  N,
269  new_e->flags,
270  es->occlusion,
271  es->material_mask_bits,
272  es->shadow_mask_bits,
273  new_e->v1->index);
274  last_occlusion = es->occlusion;
275  last_transparency = es->material_mask_bits;
276  last_shadow = es->shadow_mask_bits;
277  }
278  }
279  else if (new_vt == new_e->v2) {
280  es = new_e->segments.first;
281  last_occlusion = es->occlusion;
282  last_transparency = es->material_mask_bits;
283  last_shadow = es->shadow_mask_bits;
284  es = es->next;
285  for (; es; es = es->next) {
286  double gpos[3], lpos[3];
287  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
288  double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
289  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
290  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
291  use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
292  POS_TO_FLOAT(lpos, gpos)
294  ec,
295  use_fbcoord,
296  use_gpos,
297  N,
298  new_e->flags,
299  last_occlusion,
300  last_transparency,
301  last_shadow,
302  new_e->v2->index);
303  last_occlusion = es->occlusion;
304  last_transparency = es->material_mask_bits;
305  last_shadow = es->shadow_mask_bits;
306  }
307  VERT_COORD_TO_FLOAT(new_e->v2);
309  ec,
310  use_fbcoord,
311  use_gpos,
312  N,
313  new_e->flags,
314  last_occlusion,
315  last_transparency,
316  last_shadow,
317  new_e->v2->index);
318  }
319  ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
320  }
321 
322  /* Restore normal value. */
323  if (e->t1 || e->t2) {
324  zero_v3(N);
325  if (e->t1) {
326  N[0] += e->t1->gn[0];
327  N[1] += e->t1->gn[1];
328  N[2] += e->t1->gn[2];
329  }
330  if (e->t2) {
331  N[0] += e->t2->gn[0];
332  N[1] += e->t2->gn[1];
333  N[2] += e->t2->gn[2];
334  }
335  normalize_v3(N);
336  }
337  /* Step 2: Adding all cuts from the given line, so we can continue connecting the right side
338  * of the line. */
339  es = e->segments.first;
340  last_occlusion = es->occlusion;
341  last_transparency = es->material_mask_bits;
342  last_shadow = es->shadow_mask_bits;
343  for (es = es->next; es; es = es->next) {
344  double gpos[3], lpos[3];
345  double *lfb = e->v1->fbcoord, *rfb = e->v2->fbcoord;
346  double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
347  interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->ratio);
348  interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
349  use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at);
350  POS_TO_FLOAT(lpos, gpos)
352  ec,
353  use_fbcoord,
354  use_gpos,
355  N,
356  e->flags,
357  es->occlusion,
358  es->material_mask_bits,
359  es->shadow_mask_bits,
360  e->v1->index);
361  last_occlusion = es->occlusion;
362  last_transparency = es->material_mask_bits;
363  last_shadow = es->shadow_mask_bits;
364  }
367  ec,
368  use_fbcoord,
369  use_gpos,
370  N,
371  e->flags,
372  last_occlusion,
373  last_transparency,
374  last_shadow,
375  e->v2->index);
376 
377  /* Step 3: grow right. */
378  ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]);
379  new_vt = e->v2;
380  while (ba && (new_e = lineart_line_get_connected(
381  ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) {
383 
384  if (new_e->t1 || new_e->t2) {
385  zero_v3(N);
386  if (new_e->t1) {
387  N[0] += new_e->t1->gn[0];
388  N[1] += new_e->t1->gn[1];
389  N[2] += new_e->t1->gn[2];
390  }
391  if (new_e->t2) {
392  N[0] += new_e->t2->gn[0];
393  N[1] += new_e->t2->gn[1];
394  N[2] += new_e->t2->gn[2];
395  }
396  normalize_v3(N);
397  }
398 
399  /* Fix leading vertex type. */
400  eci = ec->chain.last;
401  eci->line_type = new_e->flags & LRT_EDGE_FLAG_ALL_TYPE;
402 
403  if (new_vt == new_e->v1) {
404  es = new_e->segments.last;
405  last_occlusion = es->occlusion;
406  last_transparency = es->material_mask_bits;
407  last_shadow = es->shadow_mask_bits;
408  /* Fix leading vertex occlusion. */
409  eci->occlusion = last_occlusion;
410  eci->material_mask_bits = last_transparency;
411  eci->shadow_mask_bits = last_shadow;
412  for (es = new_e->segments.last; es; es = es->prev) {
413  double gpos[3], lpos[3];
414  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
415  double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
416  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
417  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
418  use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
419  last_occlusion = es->prev ? es->prev->occlusion : last_occlusion;
420  last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency;
421  last_shadow = es->prev ? es->prev->shadow_mask_bits : last_shadow;
422  POS_TO_FLOAT(lpos, gpos)
424  ec,
425  use_fbcoord,
426  use_gpos,
427  N,
428  new_e->flags,
429  last_occlusion,
430  last_transparency,
431  last_shadow,
432  new_e->v1->index);
433  }
434  }
435  else if (new_vt == new_e->v2) {
436  es = new_e->segments.first;
437  last_occlusion = es->occlusion;
438  last_transparency = es->material_mask_bits;
439  last_shadow = es->shadow_mask_bits;
440  eci->occlusion = last_occlusion;
441  eci->material_mask_bits = last_transparency;
442  eci->shadow_mask_bits = last_shadow;
443  es = es->next;
444  for (; es; es = es->next) {
445  double gpos[3], lpos[3];
446  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
447  double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
448  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
449  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
450  use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
451  POS_TO_FLOAT(lpos, gpos)
453  ec,
454  use_fbcoord,
455  use_gpos,
456  N,
457  new_e->flags,
458  es->occlusion,
459  es->material_mask_bits,
460  es->shadow_mask_bits,
461  new_e->v2->index);
462  last_occlusion = es->occlusion;
463  last_transparency = es->material_mask_bits;
464  last_shadow = es->shadow_mask_bits;
465  }
466  VERT_COORD_TO_FLOAT(new_e->v2)
468  ec,
469  use_fbcoord,
470  use_gpos,
471  N,
472  new_e->flags,
473  last_occlusion,
474  last_transparency,
475  last_shadow,
476  new_e->v2->index);
477  }
478  ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
479  }
480  if (ld->conf.fuzzy_everything) {
482  }
483  else {
484  ec->type = (e->flags & LRT_EDGE_FLAG_ALL_TYPE);
485  }
486  }
488 }
489 
491  LineartBoundingArea *root,
493 {
494  if (root->child == NULL) {
495  return root;
496  }
497 
498  LineartBoundingArea *ch = root->child;
499 #define IN_BOUND(ba, eci) \
500  ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
501 
502  if (IN_BOUND(ch[0], eci)) {
503  return lineart_bounding_area_get_eci_recursive(ld, &ch[0], eci);
504  }
505  if (IN_BOUND(ch[1], eci)) {
506  return lineart_bounding_area_get_eci_recursive(ld, &ch[1], eci);
507  }
508  if (IN_BOUND(ch[2], eci)) {
509  return lineart_bounding_area_get_eci_recursive(ld, &ch[2], eci);
510  }
511  if (IN_BOUND(ch[3], eci)) {
512  return lineart_bounding_area_get_eci_recursive(ld, &ch[3], eci);
513  }
514 #undef IN_BOUND
515  return NULL;
516 }
517 
520 {
521  if (!eci) {
522  return NULL;
523  }
524  LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(ld, eci->pos[0], eci->pos[1]);
525  if (root == NULL) {
526  return NULL;
527  }
528  return lineart_bounding_area_get_eci_recursive(ld, root, eci);
529 }
530 
538  LineartBoundingArea *root,
539  LineartEdgeChain *ec,
541 {
542  if (root->child == NULL) {
544  &root->linked_chains, ld->chain_data_pool, ec, sizeof(LineartChainRegisterEntry));
545 
546  cre->eci = eci;
547 
548  if (eci == ec->chain.first) {
549  cre->is_left = 1;
550  }
551  }
552  else {
553  LineartBoundingArea *ch = root->child;
554 
555 #define IN_BOUND(ba, eci) \
556  ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
557 
558  if (IN_BOUND(ch[0], eci)) {
559  lineart_bounding_area_link_point_recursive(ld, &ch[0], ec, eci);
560  }
561  else if (IN_BOUND(ch[1], eci)) {
562  lineart_bounding_area_link_point_recursive(ld, &ch[1], ec, eci);
563  }
564  else if (IN_BOUND(ch[2], eci)) {
565  lineart_bounding_area_link_point_recursive(ld, &ch[2], ec, eci);
566  }
567  else if (IN_BOUND(ch[3], eci)) {
568  lineart_bounding_area_link_point_recursive(ld, &ch[3], ec, eci);
569  }
570 
571 #undef IN_BOUND
572  }
573 }
574 
576 {
577  LineartEdgeChainItem *pl = ec->chain.first;
578  LineartEdgeChainItem *pr = ec->chain.last;
581 
582  if (ba1) {
584  }
585  if (ba2) {
587  }
588 }
589 
591  LineartEdgeChainItem *last_matching_eci,
592  float distance_threshold,
593  bool preserve_details,
594  LineartEdgeChainItem **r_next_eci)
595 {
596  float dist_accum = 0;
597 
598  int fixed_occ = last_matching_eci->occlusion;
599  uint8_t fixed_mask = last_matching_eci->material_mask_bits;
600  uint32_t fixed_shadow = last_matching_eci->shadow_mask_bits;
601 
602  LineartEdgeChainItem *can_skip_to = NULL;
603  LineartEdgeChainItem *last_eci = last_matching_eci;
604  for (LineartEdgeChainItem *eci = last_matching_eci->next; eci; eci = eci->next) {
605  dist_accum += len_v2v2(last_eci->pos, eci->pos);
606  if (dist_accum > distance_threshold) {
607  break;
608  }
609  last_eci = eci;
610  /* The reason for this is because we don't want visible segments to be "skipped" into
611  * connecting with invisible segments. */
612  if (eci->occlusion < fixed_occ) {
613  break;
614  }
615  if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ &&
616  eci->shadow_mask_bits == fixed_shadow) {
617  can_skip_to = eci;
618  }
619  }
620  if (can_skip_to) {
621  /* Either mark all in-between segments with the same occlusion and mask or delete those
622  * different ones. */
623  LineartEdgeChainItem *next_eci;
624  for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) {
625  next_eci = eci->next;
626  if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ &&
627  eci->shadow_mask_bits == fixed_shadow) {
628  continue;
629  }
630  if (preserve_details) {
631  eci->material_mask_bits = fixed_mask;
632  eci->occlusion = fixed_occ;
633  eci->shadow_mask_bits = fixed_shadow;
634  }
635  else {
636  BLI_remlink(&ec->chain, eci);
637  }
638  }
639  *r_next_eci = can_skip_to;
640  return true;
641  }
642  return false;
643 }
644 
646 {
647  LineartEdgeChain *ec, *new_ec;
648  LineartEdgeChainItem *eci, *next_eci;
649  ListBase swap = {0};
650 
651  swap.first = ld->chains.first;
652  swap.last = ld->chains.last;
653 
654  ld->chains.last = ld->chains.first = NULL;
655 
656  int loop_id = 0;
657  while ((ec = BLI_pophead(&swap)) != NULL) {
658  ec->next = ec->prev = NULL;
659  BLI_addtail(&ld->chains, ec);
660 
661  ec->loop_id = loop_id;
662  loop_id++;
663 
665  int fixed_occ = first_eci->occlusion;
666  uint8_t fixed_mask = first_eci->material_mask_bits;
667  uint32_t fixed_shadow = first_eci->shadow_mask_bits;
668  ec->level = fixed_occ;
669  ec->material_mask_bits = fixed_mask;
670  ec->shadow_mask_bits = fixed_shadow;
671  for (eci = first_eci->next; eci; eci = next_eci) {
672  next_eci = eci->next;
673  if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask ||
674  eci->shadow_mask_bits != fixed_shadow) {
675  if (next_eci) {
676  if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) {
677  continue;
678  }
680  eci->prev,
683  &next_eci)) {
684  continue;
685  }
686  }
687  else {
688  /* Set the same occlusion level for the end vertex, so when further connection is needed
689  * the backwards occlusion info is also correct. */
690  eci->occlusion = fixed_occ;
691  eci->shadow_mask_bits = fixed_shadow;
692  eci->material_mask_bits = fixed_mask;
693  /* No need to split at the last point anyway. */
694  break;
695  }
696  new_ec = lineart_chain_create(ld);
697  new_ec->chain.first = eci;
698  new_ec->chain.last = ec->chain.last;
699  new_ec->loop_id = loop_id;
700  ec->chain.last = eci->prev;
701  ((LineartEdgeChainItem *)ec->chain.last)->next = 0;
702  eci->prev = 0;
703 
704  /* End the previous one. */
706  ec,
707  eci->pos,
708  eci->gpos,
709  eci->normal,
710  eci->line_type,
711  fixed_occ,
712  fixed_mask,
713  fixed_shadow,
714  eci->index);
715  new_ec->object_ref = ec->object_ref;
716  new_ec->type = ec->type;
717  new_ec->intersection_mask = ec->intersection_mask;
718  ec = new_ec;
719  fixed_occ = eci->occlusion;
720  fixed_mask = eci->material_mask_bits;
721  fixed_shadow = eci->shadow_mask_bits;
722  ec->level = fixed_occ;
723  ec->material_mask_bits = fixed_mask;
724  ec->shadow_mask_bits = fixed_shadow;
725  }
726  }
727  }
728 
730 
731  LISTBASE_FOREACH (LineartEdgeChain *, iec, &ld->chains) {
733  }
734 }
735 
740  LineartEdgeChain *onto,
741  LineartEdgeChain *sub,
742  int reverse_1,
743  int reverse_2)
744 {
746  if (onto->type == LRT_EDGE_FLAG_INTERSECTION) {
747  if (sub->object_ref) {
748  onto->object_ref = sub->object_ref;
749  onto->type = LRT_EDGE_FLAG_CONTOUR;
750  }
751  }
752  else if (sub->type == LRT_EDGE_FLAG_INTERSECTION) {
753  if (onto->type != LRT_EDGE_FLAG_INTERSECTION) {
754  onto->type = LRT_EDGE_FLAG_CONTOUR;
755  }
756  }
757  if (!reverse_1) { /* L--R L-R. */
758  if (reverse_2) { /* L--R R-L. */
760  }
761  eci = sub->chain.first;
762  if (lineart_point_overlapping(onto->chain.last, eci->pos[0], eci->pos[1], 1e-5)) {
763  BLI_pophead(&sub->chain);
764  if (sub->chain.first == NULL) {
765  return;
766  }
767  }
768  ((LineartEdgeChainItem *)onto->chain.last)->next = sub->chain.first;
769  ((LineartEdgeChainItem *)sub->chain.first)->prev = onto->chain.last;
770  onto->chain.last = sub->chain.last;
771  }
772  else { /* L-R L--R. */
773  if (!reverse_2) { /* R-L L--R. */
775  }
776  eci = onto->chain.first;
777  if (lineart_point_overlapping(sub->chain.last, eci->pos[0], eci->pos[1], 1e-5)) {
778  BLI_pophead(&onto->chain);
779  if (onto->chain.first == NULL) {
780  return;
781  }
782  }
783  ((LineartEdgeChainItem *)sub->chain.last)->next = onto->chain.first;
784  ((LineartEdgeChainItem *)onto->chain.first)->prev = sub->chain.last;
785  onto->chain.first = sub->chain.first;
786  }
787 }
788 
791  LineartEdgeChain *ec,
793  int occlusion,
794  uint8_t material_mask_bits,
795  uint8_t isec_mask,
796  uint32_t shadow_mask,
797  int loop_id,
798  float dist,
799  float *result_new_len,
800  LineartBoundingArea *caller_ba)
801 {
802 
803  LineartChainRegisterEntry *closest_cre = NULL;
804 
805  /* Keep using for loop because `cre` could be removed from the iteration before getting to the
806  * next one. */
808  if (cre->ec->object_ref != ec->object_ref) {
809  if (!ld->conf.fuzzy_everything) {
810  if (ld->conf.fuzzy_intersections) {
811  /* If none of those are intersection lines... */
812  if ((!(cre->ec->type & LRT_EDGE_FLAG_INTERSECTION)) &&
813  (!(ec->type & LRT_EDGE_FLAG_INTERSECTION))) {
814  continue; /* We don't want to chain along different objects at the moment. */
815  }
816  }
817  else {
818  continue;
819  }
820  }
821  }
822  if (cre->ec->picked || cre->picked) {
823  continue;
824  }
825  if (cre->ec == ec || (!cre->ec->chain.first) || (cre->ec->level != occlusion) ||
826  (cre->ec->material_mask_bits != material_mask_bits) ||
827  (cre->ec->intersection_mask != isec_mask) || (cre->ec->shadow_mask_bits != shadow_mask)) {
828  continue;
829  }
830  if (!ld->conf.fuzzy_everything) {
831  if (cre->ec->type != ec->type) {
832  if (ld->conf.fuzzy_intersections) {
833  if (!(cre->ec->type == LRT_EDGE_FLAG_INTERSECTION ||
835  continue; /* Fuzzy intersections but no intersection line found. */
836  }
837  }
838  else { /* Line type different but no fuzzy. */
839  continue;
840  }
841  }
842  }
843 
844  float new_len = ld->conf.use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
845  len_v2v2(cre->eci->pos, eci->pos);
846  /* Even if the vertex is not from the same contour loop, we try to chain it still if the
847  * distance is small enough. This way we can better chain smaller loops and smooth them out
848  * later. */
849  if (((cre->ec->loop_id == loop_id) && (new_len < dist)) ||
850  ((cre->ec->loop_id != loop_id) && (new_len < dist / 10))) {
851  closest_cre = cre;
852  dist = new_len;
853  if (result_new_len) {
854  (*result_new_len) = new_len;
855  }
856  }
857  }
858 
859  /* We want a closer point anyway. So using modified dist is fine. */
860  float adjacent_new_len = dist;
861  LineartChainRegisterEntry *adjacent_closest;
862 
863 #define LRT_TEST_ADJACENT_AREAS(dist_to, list) \
864  if (dist_to < dist && dist_to > 0) { \
865  LISTBASE_FOREACH (LinkData *, link, list) { \
866  LineartBoundingArea *sba = (LineartBoundingArea *)link->data; \
867  adjacent_closest = lineart_chain_get_closest_cre(ld, \
868  sba, \
869  ec, \
870  eci, \
871  occlusion, \
872  material_mask_bits, \
873  isec_mask, \
874  shadow_mask, \
875  loop_id, \
876  dist, \
877  &adjacent_new_len, \
878  ba); \
879  if (adjacent_new_len < dist) { \
880  dist = adjacent_new_len; \
881  closest_cre = adjacent_closest; \
882  } \
883  } \
884  }
885  if (!caller_ba) {
886  LRT_TEST_ADJACENT_AREAS(eci->pos[0] - ba->l, &ba->lp);
887  LRT_TEST_ADJACENT_AREAS(ba->r - eci->pos[0], &ba->rp);
888  LRT_TEST_ADJACENT_AREAS(ba->u - eci->pos[1], &ba->up);
889  LRT_TEST_ADJACENT_AREAS(eci->pos[1] - ba->b, &ba->bp);
890  }
891  if (result_new_len) {
892  (*result_new_len) = dist;
893  }
894  return closest_cre;
895 }
896 
898 {
899  LineartEdgeChain *ec;
900  LineartEdgeChainItem *eci_l, *eci_r;
901  LineartBoundingArea *ba_l, *ba_r;
902  LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
903  float dist = ld->conf.chaining_image_threshold;
904  float dist_l, dist_r;
905  int reverse_main, loop_id;
906  uint8_t occlusion, material_mask_bits, isec_mask;
907  uint32_t shadow_mask;
908  ListBase swap = {0};
909 
910  if (ld->conf.chaining_image_threshold < 0.0001) {
911  return;
912  }
913 
914  swap.first = ld->chains.first;
915  swap.last = ld->chains.last;
916 
917  ld->chains.last = ld->chains.first = NULL;
918 
919  while ((ec = BLI_pophead(&swap)) != NULL) {
920  ec->next = ec->prev = NULL;
921  if (ec->picked || ec->chain.first == ec->chain.last) {
922  continue;
923  }
924  BLI_addtail(&ld->chains, ec);
925  loop_id = ec->loop_id;
926 
927  if (ec->type == LRT_EDGE_FLAG_LOOSE && (!ld->conf.use_loose_edge_chain)) {
928  continue;
929  }
930 
931  occlusion = ec->level;
932  material_mask_bits = ec->material_mask_bits;
933  isec_mask = ec->intersection_mask;
934  shadow_mask = ec->shadow_mask_bits;
935 
936  eci_l = ec->chain.first;
937  eci_r = ec->chain.last;
938  while ((ba_l = lineart_bounding_area_get_end_point(ld, eci_l)) &&
939  (ba_r = lineart_bounding_area_get_end_point(ld, eci_r))) {
940  closest_cre_l = lineart_chain_get_closest_cre(ld,
941  ba_l,
942  ec,
943  eci_l,
944  occlusion,
945  material_mask_bits,
946  isec_mask,
947  shadow_mask,
948  loop_id,
949  dist,
950  &dist_l,
951  NULL);
952  closest_cre_r = lineart_chain_get_closest_cre(ld,
953  ba_r,
954  ec,
955  eci_r,
956  occlusion,
957  material_mask_bits,
958  isec_mask,
959  shadow_mask,
960  loop_id,
961  dist,
962  &dist_r,
963  NULL);
964  if (closest_cre_l && closest_cre_r) {
965  if (dist_l < dist_r) {
966  closest_cre = closest_cre_l;
967  reverse_main = 1;
968  }
969  else {
970  closest_cre = closest_cre_r;
971  reverse_main = 0;
972  }
973  }
974  else if (closest_cre_l) {
975  closest_cre = closest_cre_l;
976  reverse_main = 1;
977  }
978  else if (closest_cre_r) {
979  closest_cre = closest_cre_r;
980  BLI_remlink(&ba_r->linked_chains, closest_cre_r);
981  reverse_main = 0;
982  }
983  else {
984  break;
985  }
986  closest_cre->picked = 1;
987  closest_cre->ec->picked = 1;
988  if (closest_cre->is_left) {
989  lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 0);
990  }
991  else {
992  lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 1);
993  }
994  BLI_remlink(&swap, closest_cre->ec);
995  eci_l = ec->chain.first;
996  eci_r = ec->chain.last;
997  }
998  ec->picked = 1;
999  }
1000 }
1001 
1003 {
1004  LineartEdgeChainItem *eci;
1005  float offset_accum = 0;
1006  float dist;
1007  float last_point[2];
1008 
1009  eci = ec->chain.first;
1010  if (!eci) {
1011  return 0;
1012  }
1013  copy_v2_v2(last_point, eci->pos);
1014  for (eci = ec->chain.first; eci; eci = eci->next) {
1015  dist = len_v2v2(eci->pos, last_point);
1016  offset_accum += dist;
1017  copy_v2_v2(last_point, eci->pos);
1018  }
1019  return offset_accum;
1020 }
1021 
1023  const float threshold,
1024  uint8_t max_occlusion)
1025 {
1026  LineartEdgeChain *ec, *next_ec;
1027  for (ec = ld->chains.first; ec; ec = next_ec) {
1028  next_ec = ec->next;
1029  if (ec->level > max_occlusion || MOD_lineart_chain_compute_length(ec) < threshold) {
1030  BLI_remlink(&ld->chains, ec);
1031  }
1032  }
1033 }
1034 
1036 {
1037  int count = 0;
1039  count++;
1040  }
1041  return count;
1042 }
1043 
1045 {
1046  if (lc == NULL) {
1047  return;
1048  }
1049  LISTBASE_FOREACH (LineartEdgeChain *, ec, &lc->chains) {
1050  ec->picked = 0;
1051  }
1052 }
1053 
1055 {
1056  LISTBASE_FOREACH (LineartElementLinkNode *, eln, elns) {
1057  if (eln->object_ref == obj) {
1058  return eln;
1059  }
1060  }
1061  return NULL;
1062 }
1063 
1065 {
1066  LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
1067  if (ELEM(ec->type,
1071  continue;
1072  }
1074  ec->object_ref);
1075  BLI_assert(eln != NULL);
1076  if (LIKELY(eln)) {
1077  LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
1078  if (eci->index > eln->global_index_offset) {
1079  eci->index -= eln->global_index_offset;
1080  }
1081  }
1082  }
1083  }
1084 }
1085 
1086 void MOD_lineart_smooth_chains(LineartData *ld, float tolerance)
1087 {
1088  LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
1089  /* Go through the chain two times, once from each direction. */
1090  for (int times = 0; times < 2; times++) {
1091  for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci;
1092  eci = next_eci) {
1093  LineartEdgeChainItem *eci2, *eci3, *eci4;
1094 
1095  if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) {
1096  /* Not enough points to simplify. */
1097  next_eci = eci->next;
1098  continue;
1099  }
1100  /* No need to care for different line types/occlusion and so on, because at this stage they
1101  * are all the same within a chain.
1102  *
1103  * We need to simplify a chain from this:
1104  * 1-----------2
1105  * 3-----------4
1106  * to this:
1107  * 1-----------2--_
1108  * `--4 */
1109 
1110  /* If p3 is within the p1-p2 segment of a width of "tolerance", in other words, p3 is
1111  * approximately on the segment of p1-p2. */
1112  if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
1113  float vec2[2], vec3[2], v2n[2], ratio, len2;
1114  sub_v2_v2v2(vec2, eci2->pos, eci->pos);
1115  sub_v2_v2v2(vec3, eci3->pos, eci->pos);
1116  normalize_v2_v2(v2n, vec2);
1117  ratio = dot_v2v2(v2n, vec3);
1118  len2 = len_v2(vec2);
1119  /* Because this smoothing applies on geometries of different scales in the same scene,
1120  * some small scale features (e.g. the "tails" on the inner ring of a torus geometry)
1121  * could be completely erased if the tolerance value is set for accommodating the entire
1122  * scene. Those situations typically result in (ratio << 0), looks like this:
1123  * 1---2
1124  * 3-------------------------------4
1125  * (this sort of long zigzag obviously are "features" that can't be erased)
1126  * setting a ratio of -10 turned out to be a reasonable threshold in tests. */
1127  if (ratio < len2 && ratio > -len2 * 10) {
1128  /* We only remove p3 if p4 is on the extension of p1->p2. */
1129  if ((eci4 = eci3->next) &&
1130  (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
1131  BLI_remlink(&ec->chain, eci3);
1132  next_eci = eci;
1133  continue;
1134  }
1135  if (!eci4) {
1136  /* See if the last segment's direction is reversed, if so remove that.
1137  * Basically we don't need to preserve p3 if the entire chain looked like this:
1138  * ...----1----3===2 */
1139  if (len_v2(vec2) > len_v2(vec3)) {
1140  BLI_remlink(&ec->chain, eci3);
1141  }
1142  next_eci = NULL;
1143  continue;
1144  }
1145  }
1146  }
1147  next_eci = eci->next;
1148  }
1149  BLI_listbase_reverse(&ec->chain);
1150  }
1151  }
1152 }
1153 
1155  LineartEdgeChainItem *eci_inside,
1156  LineartEdgeChainItem *eci_outside)
1157 {
1158  float isec[2];
1159  /* l: left, r: right, b: bottom, u: top. */
1160  float ref_lu[2] = {-1.0f, 1.0f}, ref_lb[2] = {-1.0f, -1.0f}, ref_ru[2] = {1.0f, 1.0f},
1161  ref_rb[2] = {1.0f, -1.0f};
1162  bool found = false;
1163  LineartEdgeChainItem *eci2 = eci_outside, *eci1 = eci_inside;
1164  if (eci2->pos[0] < -1.0f) {
1165  found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_lb, isec) > 0);
1166  }
1167  if (!found && eci2->pos[0] > 1.0f) {
1168  found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_ru, ref_rb, isec) > 0);
1169  }
1170  if (!found && eci2->pos[1] < -1.0f) {
1171  found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lb, ref_rb, isec) > 0);
1172  }
1173  if (!found && eci2->pos[1] > 1.0f) {
1174  found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_ru, isec) > 0);
1175  }
1176 
1177  if (UNLIKELY(!found)) {
1178  return NULL;
1179  }
1180 
1181  float ratio = (fabs(eci2->pos[0] - eci1->pos[0]) > fabs(eci2->pos[1] - eci1->pos[1])) ?
1182  ratiof(eci1->pos[0], eci2->pos[0], isec[0]) :
1183  ratiof(eci1->pos[1], eci2->pos[1], isec[1]);
1184  float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]);
1185 
1187  sizeof(LineartEdgeChainItem));
1188  memcpy(eci, eci1, sizeof(LineartEdgeChainItem));
1189  interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio);
1190  interp_v3_v3v3(eci->pos, eci1->pos, eci2->pos, ratio);
1191  eci->pos[3] = interpf(eci2->pos[3], eci1->pos[3], gratio);
1192  eci->next = eci->prev = NULL;
1193  return eci;
1194 }
1195 
1196 #define LRT_ECI_INSIDE(eci) \
1197  ((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \
1198  (eci)->pos[1] <= 1.0f)
1199 
1201 {
1202  LineartEdgeChain *ec;
1203  LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci;
1204  bool is_inside, new_inside;
1205  ListBase swap = {0};
1206  swap.first = ld->chains.first;
1207  swap.last = ld->chains.last;
1208 
1209  ld->chains.last = ld->chains.first = NULL;
1210  while ((ec = BLI_pophead(&swap)) != NULL) {
1211  bool ec_added = false;
1213  is_inside = LRT_ECI_INSIDE(first_eci) ? true : false;
1214  if (!is_inside) {
1215  ec->picked = 1;
1216  }
1217  for (eci = first_eci->next; eci; eci = next_eci) {
1218  next_eci = eci->next;
1219  prev_eci = eci->prev;
1220 
1221  /* We only need to do something if the edge crossed from outside to the inside or from inside
1222  * to the outside. */
1223  if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) {
1224  if (new_inside == false) {
1225  /* Stroke goes out. */
1226  new_eci = lineart_chain_create_crossing_point(ld, prev_eci, eci);
1227 
1229  sizeof(LineartEdgeChain));
1230  memcpy(new_ec, ec, sizeof(LineartEdgeChain));
1231  new_ec->chain.first = next_eci;
1232  eci->prev = NULL;
1233  prev_eci->next = NULL;
1234  ec->chain.last = prev_eci;
1235  BLI_addtail(&ec->chain, new_eci);
1236  BLI_addtail(&ld->chains, ec);
1237  ec_added = true;
1238  ec = new_ec;
1239 
1240  next_eci = eci->next;
1241  is_inside = new_inside;
1242  continue;
1243  }
1244  /* Stroke comes in. */
1245  new_eci = lineart_chain_create_crossing_point(ld, eci, prev_eci);
1246 
1247  ec->chain.first = eci;
1248  eci->prev = NULL;
1249 
1250  BLI_addhead(&ec->chain, new_eci);
1251 
1252  ec_added = false;
1253 
1254  next_eci = eci->next;
1255  is_inside = new_inside;
1256  continue;
1257  }
1258  }
1259 
1260  if ((!ec_added) && is_inside) {
1261  BLI_addtail(&ld->chains, ec);
1262  }
1263  }
1264 }
1265 
1266 void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
1267 {
1268  LineartEdgeChain *ec, *new_ec;
1269  LineartEdgeChainItem *eci, *next_eci, *prev_eci;
1270  ListBase swap = {0};
1271 
1272  swap.first = ld->chains.first;
1273  swap.last = ld->chains.last;
1274 
1275  ld->chains.last = ld->chains.first = NULL;
1276 
1277  while ((ec = BLI_pophead(&swap)) != NULL) {
1278  ec->next = ec->prev = NULL;
1279  BLI_addtail(&ld->chains, ec);
1281  for (eci = first_eci->next; eci; eci = next_eci) {
1282  next_eci = eci->next;
1283  prev_eci = eci->prev;
1284  float angle = M_PI;
1285  if (next_eci && prev_eci) {
1286  angle = angle_v2v2v2(prev_eci->pos, eci->pos, next_eci->pos);
1287  }
1288  else {
1289  break; /* No need to split at the last point anyway. */
1290  }
1291  if (angle < angle_threshold_rad) {
1292  new_ec = lineart_chain_create(ld);
1293  new_ec->chain.first = eci;
1294  new_ec->chain.last = ec->chain.last;
1295  ec->chain.last = eci->prev;
1296  ((LineartEdgeChainItem *)ec->chain.last)->next = 0;
1297  eci->prev = 0;
1298 
1299  /* End the previous one. */
1301  ec,
1302  eci->pos,
1303  eci->gpos,
1304  eci->normal,
1305  eci->line_type,
1306  ec->level,
1307  eci->material_mask_bits,
1308  eci->shadow_mask_bits,
1309  eci->index);
1310  new_ec->object_ref = ec->object_ref;
1311  new_ec->type = ec->type;
1312  new_ec->level = ec->level;
1313  new_ec->loop_id = ec->loop_id;
1314  new_ec->intersection_mask = ec->intersection_mask;
1315  new_ec->material_mask_bits = ec->material_mask_bits;
1316  new_ec->shadow_mask_bits = ec->shadow_mask_bits;
1317  ec = new_ec;
1318  }
1319  }
1320  }
1321 }
1322 
1323 void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera)
1324 {
1325  float dir[3];
1326  float cam[3];
1327  float view[3];
1328  float view_clamp[3];
1329 
1330  if (use_custom_camera) {
1331  copy_v3fl_v3db(cam, ld->conf.camera_pos);
1332  }
1333  else {
1335  }
1336 
1337  if (ld->conf.cam_is_persp) {
1338  LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
1339  LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
1340  sub_v3_v3v3(dir, cam, eci->gpos);
1341  float orig_len = len_v3(dir);
1342  normalize_v3(dir);
1343  mul_v3_fl(dir, MIN2(dist, orig_len - ld->conf.near_clip));
1344  add_v3_v3(eci->gpos, dir);
1345  }
1346  }
1347  }
1348  else {
1350  LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
1351  LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
1352  sub_v3_v3v3(dir, cam, eci->gpos);
1353  float len_lim = dot_v3v3(view, dir) - ld->conf.near_clip;
1354  normalize_v3_v3(view_clamp, view);
1355  mul_v3_fl(view_clamp, MIN2(dist, len_lim));
1356  add_v3_v3(eci->gpos, view_clamp);
1357  }
1358  }
1359  }
1360 }
1361 
1363 {
1364  LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
1365  if (ec->type == LRT_EDGE_FLAG_CONTOUR &&
1366  ec->shadow_mask_bits & LRT_SHADOW_SILHOUETTE_ERASED_GROUP) {
1367  uint32_t target = ec->shadow_mask_bits & LRT_OBINDEX_HIGHER;
1369  target);
1370  if (!eln) {
1371  continue;
1372  }
1373  ec->silhouette_backdrop = eln->object_ref;
1374  }
1375  }
1376 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:221
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void void void void void void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1)
Definition: listbase.c:797
MINLINE float interpf(float a, float b, float t)
MINLINE float ratiof(float min, float max, float pos)
#define M_PI
Definition: BLI_math_base.h:20
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2])
Definition: math_geom.c:1296
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:292
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:278
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:395
MINLINE void copy_v4_v4(float r[4], const float a[4])
void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], double t)
Definition: math_vector.c:1305
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void copy_v3fl_v3db(float r[3], const double a[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v2_v2(float r[2], const float a[2])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define LIKELY(x)
void swap(T &a, T &b)
Definition: Common.h:19
@ LRT_EDGE_FLAG_PROJECTED_SHADOW
@ LRT_EDGE_FLAG_LOOSE
@ LRT_EDGE_FLAG_INTERSECTION
@ LRT_EDGE_FLAG_LIGHT_CONTOUR
@ LRT_EDGE_FLAG_CHAIN_PICKED
@ LRT_EDGE_FLAG_CONTOUR
#define LRT_EDGE_FLAG_ALL_TYPE
static AppView * view
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
#define DBL_EDGE_LIM
Definition: MOD_lineart.h:432
#define LRT_OBINDEX_HIGHER
Definition: MOD_lineart.h:482
#define LRT_SHADOW_SILHOUETTE_ERASED_GROUP
Definition: MOD_lineart.h:452
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
static bool is_inside(int x, int y, int cols, int rows)
Definition: filesel.c:706
IconTextureDrawCall normal
int count
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
static LineartEdgeChain * lineart_chain_create(LineartData *ld)
Definition: lineart_chain.c:69
#define POS_TO_FLOAT(lpos, gpos)
static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, LineartEdgeChainItem *last_matching_eci, float distance_threshold, bool preserve_details, LineartEdgeChainItem **r_next_eci)
#define LRT_ECI_INSIDE(eci)
void MOD_lineart_chain_connect(LineartData *ld)
void MOD_lineart_chain_discard_unused(LineartData *ld, const float threshold, uint8_t max_occlusion)
static LineartEdge * lineart_line_get_connected(LineartBoundingArea *ba, LineartVert *vt, LineartVert **new_vt, int match_flag, uint8_t match_isec_mask, struct Object *match_isec_object)
Definition: lineart_chain.c:24
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
static LineartEdgeChainItem * lineart_chain_prepend_point(LineartData *ld, LineartEdgeChain *ec, float fbcoord[4], float gpos[3], float normal[3], uint8_t type, int level, uint8_t material_mask_bits, uint32_t shadow_mask_bits, size_t index)
void MOD_lineart_chain_clip_at_border(LineartData *ld)
int MOD_lineart_chain_count(const LineartEdgeChain *ec)
static void lineart_chain_connect(LineartData *UNUSED(ld), LineartEdgeChain *onto, LineartEdgeChain *sub, int reverse_1, int reverse_2)
static LineartEdgeChainItem * lineart_chain_create_crossing_point(LineartData *ld, LineartEdgeChainItem *eci_inside, LineartEdgeChainItem *eci_outside)
static LineartEdgeChainItem * lineart_chain_append_point(LineartData *ld, LineartEdgeChain *ec, float fbcoord[4], float gpos[3], float normal[3], uint8_t type, int level, uint8_t material_mask_bits, uint32_t shadow_mask_bits, size_t index)
Definition: lineart_chain.c:94
#define VERT_COORD_TO_FLOAT(a)
void MOD_lineart_finalize_chains(LineartData *ld)
static LineartBoundingArea * lineart_bounding_area_get_end_point(LineartData *ld, LineartEdgeChainItem *eci)
static void lineart_bounding_area_link_chain(LineartData *ld, LineartEdgeChain *ec)
#define LRT_OTHER_VERT(e, vt)
Definition: lineart_chain.c:18
void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld)
LineartElementLinkNode * lineart_find_matching_eln_obj(ListBase *elns, struct Object *obj)
static bool lineart_point_overlapping(LineartEdgeChainItem *eci, float x, float y, double threshold)
Definition: lineart_chain.c:79
void MOD_lineart_chain_feature_lines(LineartData *ld)
static LineartChainRegisterEntry * lineart_chain_get_closest_cre(LineartData *ld, LineartBoundingArea *ba, LineartEdgeChain *ec, LineartEdgeChainItem *eci, int occlusion, uint8_t material_mask_bits, uint8_t isec_mask, uint32_t shadow_mask, int loop_id, float dist, float *result_new_len, LineartBoundingArea *caller_ba)
#define LRT_TEST_ADJACENT_AREAS(dist_to, list)
static LineartBoundingArea * lineart_bounding_area_get_eci_recursive(LineartData *ld, LineartBoundingArea *root, LineartEdgeChainItem *eci)
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
static void lineart_bounding_area_link_point_recursive(LineartData *ld, LineartBoundingArea *root, LineartEdgeChain *ec, LineartEdgeChainItem *eci)
void MOD_lineart_smooth_chains(LineartData *ld, float tolerance)
void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera)
#define IN_BOUND(ba, eci)
LineartBoundingArea * MOD_lineart_get_bounding_area(LineartData *ld, double x, double y)
Definition: lineart_cpu.c:4511
LineartBoundingArea * MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y)
Definition: lineart_cpu.c:4442
void * lineart_list_append_pointer_pool_sized(ListBase *h, struct LineartStaticMemPool *smp, void *data, int size)
Definition: lineart_util.c:35
#define LRT_ITER_ALL_LINES_END
#define LRT_ITER_ALL_LINES_NEXT
#define LRT_ITER_ALL_LINES_BEGIN
LineartElementLinkNode * lineart_find_matching_eln(struct ListBase *shadow_elns, int obindex)
void * lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size)
Definition: lineart_util.c:104
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
#define N
static const pxr::TfToken occlusion("occlusion", pxr::TfToken::Immortal)
unsigned int uint32_t
Definition: stdint.h:80
unsigned char uint8_t
Definition: stdint.h:78
struct LineartBoundingArea * child
Definition: MOD_lineart.h:551
struct LineartEdge ** linked_lines
Definition: MOD_lineart.h:568
ListBase linked_chains
Definition: MOD_lineart.h:571
ListBase chains
Definition: MOD_lineart.h:421
LineartEdgeChainItem * eci
Definition: MOD_lineart.h:235
LineartEdgeChain * ec
Definition: MOD_lineart.h:234
double view_vector[3]
Definition: MOD_lineart.h:390
float chaining_image_threshold
Definition: MOD_lineart.h:385
double active_camera_pos[3]
Definition: MOD_lineart.h:380
double camera_pos[3]
Definition: MOD_lineart.h:378
bool use_geometry_space_chain
Definition: MOD_lineart.h:355
ListBase vertex_buffer_pointers
Definition: MOD_lineart.h:308
ListBase line_buffer_pointers
Definition: MOD_lineart.h:309
struct LineartData::_conf conf
struct LineartData::_geom geom
ListBase chains
Definition: MOD_lineart.h:405
LineartStaticMemPool * chain_data_pool
Definition: MOD_lineart.h:279
uint8_t material_mask_bits
Definition: MOD_lineart.h:226
struct LineartEdgeChainItem * next
Definition: MOD_lineart.h:218
uint32_t shadow_mask_bits
Definition: MOD_lineart.h:228
struct LineartEdgeChainItem * prev
Definition: MOD_lineart.h:218
uint8_t material_mask_bits
Definition: MOD_lineart.h:205
struct LineartEdgeChain * next
Definition: MOD_lineart.h:191
struct LineartEdgeChain * prev
Definition: MOD_lineart.h:191
uint32_t shadow_mask_bits
Definition: MOD_lineart.h:207
uint8_t intersection_mask
Definition: MOD_lineart.h:206
struct Object * object_ref
Definition: MOD_lineart.h:213
struct LineartEdgeSegment * prev
Definition: MOD_lineart.h:94
struct LineartEdgeSegment * next
Definition: MOD_lineart.h:94
uint32_t shadow_mask_bits
Definition: MOD_lineart.h:107
uint8_t material_mask_bits
Definition: MOD_lineart.h:102
uint16_t flags
Definition: MOD_lineart.h:164
struct LineartVert * v2
Definition: MOD_lineart.h:154
ListBase segments
Definition: MOD_lineart.h:160
struct LineartTriangle * t2
Definition: MOD_lineart.h:158
uint8_t intersection_mask
Definition: MOD_lineart.h:165
struct LineartTriangle * t1
Definition: MOD_lineart.h:158
struct Object * object_ref
Definition: MOD_lineart.h:187
struct LineartVert * v1
Definition: MOD_lineart.h:154
double gn[3]
Definition: MOD_lineart.h:37
double fbcoord[4]
Definition: MOD_lineart.h:147
double gloc[3]
Definition: MOD_lineart.h:146
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31