Blender  V2.93
lineart_chain.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2019 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "BLI_linklist.h"
25 #include "BLI_listbase.h"
26 #include "BLI_math.h"
27 
28 #include "MOD_lineart.h"
29 
30 #include "lineart_intern.h"
31 
32 #include <math.h>
33 
34 #define LRT_OTHER_RV(e, rv) ((rv) == (e)->v1 ? (e)->v2 : ((rv) == (e)->v2 ? (e)->v1 : NULL))
35 
36 /* Get a connected line, only for lines who has the exact given vert, or (in the case of
37  * intersection lines) who has a vert that has the exact same position. */
39  LineartVert *rv,
40  LineartVert **new_rv,
41  int match_flag)
42 {
43  LISTBASE_FOREACH (LinkData *, lip, &ba->linked_lines) {
44  LineartEdge *n_e = lip->data;
45 
46  if ((!(n_e->flags & LRT_EDGE_FLAG_ALL_TYPE)) || (n_e->flags & LRT_EDGE_FLAG_CHAIN_PICKED)) {
47  continue;
48  }
49 
50  if (match_flag && ((n_e->flags & LRT_EDGE_FLAG_ALL_TYPE) & match_flag) == 0) {
51  continue;
52  }
53 
54  *new_rv = LRT_OTHER_RV(n_e, rv);
55  if (*new_rv) {
56  return n_e;
57  }
58 
59  if (n_e->flags & LRT_EDGE_FLAG_INTERSECTION) {
60  if (rv->fbcoord[0] == n_e->v1->fbcoord[0] && rv->fbcoord[1] == n_e->v1->fbcoord[1]) {
61  *new_rv = LRT_OTHER_RV(n_e, n_e->v1);
62  return n_e;
63  }
64  if (rv->fbcoord[0] == n_e->v2->fbcoord[0] && rv->fbcoord[1] == n_e->v2->fbcoord[1]) {
65  *new_rv = LRT_OTHER_RV(n_e, n_e->v2);
66  return n_e;
67  }
68  }
69  }
70 
71  return NULL;
72 }
73 
75 {
76  LineartLineChain *rlc;
78 
79  BLI_addtail(&rb->chains, rlc);
80 
81  return rlc;
82 }
83 
85  float x,
86  float y,
87  double threshold)
88 {
89  if (!rlci) {
90  return false;
91  }
92  if (((rlci->pos[0] + threshold) >= x) && ((rlci->pos[0] - threshold) <= x) &&
93  ((rlci->pos[1] + threshold) >= y) && ((rlci->pos[1] - threshold) <= y)) {
94  return true;
95  }
96  return false;
97 }
98 
100  LineartLineChain *rlc,
101  float *fbcoord,
102  float *gpos,
103  float *normal,
104  char type,
105  int level,
106  unsigned char transparency_mask,
107  size_t index)
108 {
109  LineartLineChainItem *rlci;
110 
111  if (lineart_point_overlapping(rlc->chain.last, fbcoord[0], fbcoord[1], 1e-5)) {
112  /* Because the new chain point is overlapping, just replace the type and occlusion level of the
113  * current point. This makes it so that the line to the point after this one has the correct
114  * type and level. */
115  LineartLineChainItem *old_rlci = rlc->chain.last;
116  old_rlci->line_type = type;
117  old_rlci->occlusion = level;
118  old_rlci->transparency_mask = transparency_mask;
119  return old_rlci;
120  }
121 
123 
124  copy_v2_v2(rlci->pos, fbcoord);
125  copy_v3_v3(rlci->gpos, gpos);
126  rlci->index = index;
127  copy_v3_v3(rlci->normal, normal);
129  rlci->occlusion = level;
130  rlci->transparency_mask = transparency_mask;
131  BLI_addtail(&rlc->chain, rlci);
132 
133  return rlci;
134 }
135 
137  LineartLineChain *rlc,
138  float *fbcoord,
139  float *gpos,
140  float *normal,
141  char type,
142  int level,
143  unsigned char transparency_mask,
144  size_t index)
145 {
146  LineartLineChainItem *rlci;
147 
148  if (lineart_point_overlapping(rlc->chain.first, fbcoord[0], fbcoord[1], 1e-5)) {
149  return rlc->chain.first;
150  }
151 
153 
154  copy_v2_v2(rlci->pos, fbcoord);
155  copy_v3_v3(rlci->gpos, gpos);
156  rlci->index = index;
157  copy_v3_v3(rlci->normal, normal);
159  rlci->occlusion = level;
160  rlci->transparency_mask = transparency_mask;
161  BLI_addhead(&rlc->chain, rlci);
162 
163  return rlci;
164 }
165 
167 {
168  LineartLineChain *rlc;
169  LineartLineChainItem *rlci;
171  LineartLineSegment *rls;
172  int last_occlusion;
173  unsigned char last_transparency;
174  /* Used when converting from double. */
175  float use_fbcoord[2];
176  float use_gpos[3];
177 
178 #define VERT_COORD_TO_FLOAT(a) \
179  copy_v2fl_v2db(use_fbcoord, (a)->fbcoord); \
180  copy_v3fl_v3db(use_gpos, (a)->gloc);
181 
182 #define POS_TO_FLOAT(lpos, gpos) \
183  copy_v2fl_v2db(use_fbcoord, lpos); \
184  copy_v3fl_v3db(use_gpos, gpos);
185 
187  {
188  if ((!(e->flags & LRT_EDGE_FLAG_ALL_TYPE)) || (e->flags & LRT_EDGE_FLAG_CHAIN_PICKED)) {
190  continue;
191  }
192 
193  e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
194 
195  rlc = lineart_chain_create(rb);
196 
197  /* One chain can only have one object_ref,
198  * so we assign it based on the first segment we found. */
199  rlc->object_ref = e->object_ref;
200 
201  LineartEdge *new_e = e;
202  LineartVert *new_rv;
203  float N[3] = {0};
204 
205  if (e->t1) {
206  N[0] += e->t1->gn[0];
207  N[1] += e->t1->gn[1];
208  N[2] += e->t1->gn[2];
209  }
210  if (e->t2) {
211  N[0] += e->t2->gn[0];
212  N[1] += e->t2->gn[1];
213  N[2] += e->t2->gn[2];
214  }
215  if (e->t1 || e->t2) {
216  normalize_v3(N);
217  }
218 
219  /* Step 1: grow left. */
220  ba = MOD_lineart_get_bounding_area(rb, e->v1->fbcoord[0], e->v1->fbcoord[1]);
221  new_rv = e->v1;
222  rls = e->segments.first;
223  VERT_COORD_TO_FLOAT(new_rv);
225  rlc,
226  use_fbcoord,
227  use_gpos,
228  N,
229  e->flags,
230  rls->occlusion,
231  rls->transparency_mask,
232  e->v1_obindex);
233  while (ba && (new_e = lineart_line_get_connected(ba, new_rv, &new_rv, e->flags))) {
235 
236  if (new_e->t1 || new_e->t2) {
237  zero_v3(N);
238  if (new_e->t1) {
239  N[0] += new_e->t1->gn[0];
240  N[1] += new_e->t1->gn[1];
241  N[2] += new_e->t1->gn[2];
242  }
243  if (new_e->t2) {
244  N[0] += new_e->t2->gn[0];
245  N[1] += new_e->t2->gn[1];
246  N[2] += new_e->t2->gn[2];
247  }
248  normalize_v3(N);
249  }
250 
251  if (new_rv == new_e->v1) {
252  for (rls = new_e->segments.last; rls; rls = rls->prev) {
253  double gpos[3], lpos[3];
254  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
255  double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
256  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, rls->at);
257  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
258  POS_TO_FLOAT(lpos, gpos)
260  rlc,
261  use_fbcoord,
262  use_gpos,
263  N,
264  new_e->flags,
265  rls->occlusion,
266  rls->transparency_mask,
267  new_e->v1_obindex);
268  last_occlusion = rls->occlusion;
269  last_transparency = rls->transparency_mask;
270  }
271  }
272  else if (new_rv == new_e->v2) {
273  rls = new_e->segments.first;
274  last_occlusion = rls->occlusion;
275  last_transparency = rls->transparency_mask;
276  rls = rls->next;
277  for (; rls; rls = rls->next) {
278  double gpos[3], lpos[3];
279  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
280  double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
281  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, rls->at);
282  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
283  POS_TO_FLOAT(lpos, gpos)
285  rlc,
286  use_fbcoord,
287  use_gpos,
288  N,
289  new_e->flags,
290  last_occlusion,
291  last_transparency,
292  new_e->v2_obindex);
293  last_occlusion = rls->occlusion;
294  last_transparency = rls->transparency_mask;
295  }
296  VERT_COORD_TO_FLOAT(new_e->v2);
298  rlc,
299  use_fbcoord,
300  use_gpos,
301  N,
302  new_e->flags,
303  last_occlusion,
304  last_transparency,
305  new_e->v2_obindex);
306  }
307  ba = MOD_lineart_get_bounding_area(rb, new_rv->fbcoord[0], new_rv->fbcoord[1]);
308  }
309 
310  /* Restore normal value. */
311  if (e->t1 || e->t2) {
312  zero_v3(N);
313  if (e->t1) {
314  N[0] += e->t1->gn[0];
315  N[1] += e->t1->gn[1];
316  N[2] += e->t1->gn[2];
317  }
318  if (e->t2) {
319  N[0] += e->t2->gn[0];
320  N[1] += e->t2->gn[1];
321  N[2] += e->t2->gn[2];
322  }
323  normalize_v3(N);
324  }
325  /* Step 2: Adding all cuts from the given line, so we can continue connecting the right side
326  * of the line. */
327  rls = e->segments.first;
328  last_occlusion = ((LineartLineSegment *)rls)->occlusion;
329  last_transparency = ((LineartLineSegment *)rls)->transparency_mask;
330  for (rls = rls->next; rls; rls = rls->next) {
331  double gpos[3], lpos[3];
332  double *lfb = e->v1->fbcoord, *rfb = e->v2->fbcoord;
333  double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
334  interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, rls->at);
335  interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
336  POS_TO_FLOAT(lpos, gpos)
338  rlc,
339  use_fbcoord,
340  use_gpos,
341  N,
342  e->flags,
343  rls->occlusion,
344  rls->transparency_mask,
345  e->v1_obindex);
346  last_occlusion = rls->occlusion;
347  last_transparency = rls->transparency_mask;
348  }
351  rlc,
352  use_fbcoord,
353  use_gpos,
354  N,
355  e->flags,
356  last_occlusion,
357  last_transparency,
358  e->v2_obindex);
359 
360  /* Step 3: grow right. */
361  ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]);
362  new_rv = e->v2;
363  while (ba && (new_e = lineart_line_get_connected(ba, new_rv, &new_rv, e->flags))) {
365 
366  if (new_e->t1 || new_e->t2) {
367  zero_v3(N);
368  if (new_e->t1) {
369  N[0] += new_e->t1->gn[0];
370  N[1] += new_e->t1->gn[1];
371  N[2] += new_e->t1->gn[2];
372  }
373  if (new_e->t2) {
374  N[0] += new_e->t2->gn[0];
375  N[1] += new_e->t2->gn[1];
376  N[2] += new_e->t2->gn[2];
377  }
378  normalize_v3(N);
379  }
380 
381  /* Fix leading vertex type. */
382  rlci = rlc->chain.last;
383  rlci->line_type = new_e->flags & LRT_EDGE_FLAG_ALL_TYPE;
384 
385  if (new_rv == new_e->v1) {
386  rls = new_e->segments.last;
387  last_occlusion = rls->occlusion;
388  last_transparency = rls->transparency_mask;
389  /* Fix leading vertex occlusion. */
390  rlci->occlusion = last_occlusion;
391  rlci->transparency_mask = last_transparency;
392  for (rls = new_e->segments.last; rls; rls = rls->prev) {
393  double gpos[3], lpos[3];
394  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
395  double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
396  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, rls->at);
397  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
398  last_occlusion = rls->prev ? rls->prev->occlusion : last_occlusion;
399  last_transparency = rls->prev ? rls->prev->transparency_mask : last_transparency;
400  POS_TO_FLOAT(lpos, gpos)
402  rlc,
403  use_fbcoord,
404  use_gpos,
405  N,
406  new_e->flags,
407  last_occlusion,
408  last_transparency,
409  new_e->v1_obindex);
410  }
411  }
412  else if (new_rv == new_e->v2) {
413  rls = new_e->segments.first;
414  last_occlusion = rls->occlusion;
415  last_transparency = rls->transparency_mask;
416  rlci->occlusion = last_occlusion;
417  rlci->transparency_mask = last_transparency;
418  rls = rls->next;
419  for (; rls; rls = rls->next) {
420  double gpos[3], lpos[3];
421  double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
422  double global_at = lfb[3] * rls->at / (rls->at * lfb[3] + (1 - rls->at) * rfb[3]);
423  interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, rls->at);
424  interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
425  POS_TO_FLOAT(lpos, gpos)
427  rlc,
428  use_fbcoord,
429  use_gpos,
430  N,
431  new_e->flags,
432  rls->occlusion,
433  rls->transparency_mask,
434  new_e->v2_obindex);
435  last_occlusion = rls->occlusion;
436  last_transparency = rls->transparency_mask;
437  }
438  VERT_COORD_TO_FLOAT(new_e->v2)
440  rlc,
441  use_fbcoord,
442  use_gpos,
443  N,
444  new_e->flags,
445  last_occlusion,
446  last_transparency,
447  new_e->v2_obindex);
448  }
449  ba = MOD_lineart_get_bounding_area(rb, new_rv->fbcoord[0], new_rv->fbcoord[1]);
450  }
451  if (rb->fuzzy_everything) {
453  }
454  else {
455  rlc->type = (e->flags & LRT_EDGE_FLAG_ALL_TYPE);
456  }
457  }
459 }
460 
462  LineartBoundingArea *root,
463  LineartLineChainItem *rlci)
464 {
465  if (root->child == NULL) {
466  return root;
467  }
468 
469  LineartBoundingArea *ch = root->child;
470 #define IN_BOUND(ba, rlci) \
471  ba.l <= rlci->pos[0] && ba.r >= rlci->pos[0] && ba.b <= rlci->pos[1] && ba.u >= rlci->pos[1]
472 
473  if (IN_BOUND(ch[0], rlci)) {
474  return lineart_bounding_area_get_rlci_recursive(rb, &ch[0], rlci);
475  }
476  if (IN_BOUND(ch[1], rlci)) {
477  return lineart_bounding_area_get_rlci_recursive(rb, &ch[1], rlci);
478  }
479  if (IN_BOUND(ch[2], rlci)) {
480  return lineart_bounding_area_get_rlci_recursive(rb, &ch[2], rlci);
481  }
482  if (IN_BOUND(ch[3], rlci)) {
483  return lineart_bounding_area_get_rlci_recursive(rb, &ch[3], rlci);
484  }
485 #undef IN_BOUND
486  return NULL;
487 }
488 
490  LineartLineChainItem *rlci)
491 {
492  if (!rlci) {
493  return NULL;
494  }
495  LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, rlci->pos[0], rlci->pos[1]);
496  if (root == NULL) {
497  return NULL;
498  }
499  return lineart_bounding_area_get_rlci_recursive(rb, root, rlci);
500 }
501 
509  LineartBoundingArea *root,
510  LineartLineChain *rlc,
511  LineartLineChainItem *rlci)
512 {
513  if (root->child == NULL) {
515  &root->linked_chains, &rb->render_data_pool, rlc, sizeof(LineartChainRegisterEntry));
516 
517  cre->rlci = rlci;
518 
519  if (rlci == rlc->chain.first) {
520  cre->is_left = 1;
521  }
522  }
523  else {
524  LineartBoundingArea *ch = root->child;
525 
526 #define IN_BOUND(ba, rlci) \
527  ba.l <= rlci->pos[0] && ba.r >= rlci->pos[0] && ba.b <= rlci->pos[1] && ba.u >= rlci->pos[1]
528 
529  if (IN_BOUND(ch[0], rlci)) {
530  lineart_bounding_area_link_point_recursive(rb, &ch[0], rlc, rlci);
531  }
532  else if (IN_BOUND(ch[1], rlci)) {
533  lineart_bounding_area_link_point_recursive(rb, &ch[1], rlc, rlci);
534  }
535  else if (IN_BOUND(ch[2], rlci)) {
536  lineart_bounding_area_link_point_recursive(rb, &ch[2], rlc, rlci);
537  }
538  else if (IN_BOUND(ch[3], rlci)) {
539  lineart_bounding_area_link_point_recursive(rb, &ch[3], rlc, rlci);
540  }
541 
542 #undef IN_BOUND
543  }
544 }
545 
547 {
548  LineartLineChainItem *pl = rlc->chain.first;
549  LineartLineChainItem *pr = rlc->chain.last;
552 
553  if (ba1) {
555  }
556  if (ba2) {
558  }
559 }
560 
562 {
563  LineartLineChain *rlc, *new_rlc;
564  LineartLineChainItem *rlci, *next_rlci;
565  ListBase swap = {0};
566 
567  swap.first = rb->chains.first;
568  swap.last = rb->chains.last;
569 
570  rb->chains.last = rb->chains.first = NULL;
571 
572  while ((rlc = BLI_pophead(&swap)) != NULL) {
573  rlc->next = rlc->prev = NULL;
574  BLI_addtail(&rb->chains, rlc);
576  int fixed_occ = first_rlci->occlusion;
577  unsigned char fixed_mask = first_rlci->transparency_mask;
578  rlc->level = fixed_occ;
579  rlc->transparency_mask = fixed_mask;
580  for (rlci = first_rlci->next; rlci; rlci = next_rlci) {
581  next_rlci = rlci->next;
582  if (rlci->occlusion != fixed_occ || rlci->transparency_mask != fixed_mask) {
583  if (next_rlci) {
584  if (lineart_point_overlapping(next_rlci, rlci->pos[0], rlci->pos[1], 1e-5)) {
585  continue;
586  }
587  }
588  else {
589  /* Set the same occlusion level for the end vertex, so when further connection is needed
590  * the backwards occlusion info is also correct. */
591  rlci->occlusion = fixed_occ;
592  rlci->transparency_mask = fixed_mask;
593  /* No need to split at the last point anyway. */
594  break;
595  }
596  new_rlc = lineart_chain_create(rb);
597  new_rlc->chain.first = rlci;
598  new_rlc->chain.last = rlc->chain.last;
599  rlc->chain.last = rlci->prev;
600  ((LineartLineChainItem *)rlc->chain.last)->next = 0;
601  rlci->prev = 0;
602 
603  /* End the previous one. */
605  rlc,
606  rlci->pos,
607  rlci->gpos,
608  rlci->normal,
609  rlci->line_type,
610  fixed_occ,
611  fixed_mask,
612  rlci->index);
613  new_rlc->object_ref = rlc->object_ref;
614  new_rlc->type = rlc->type;
615  rlc = new_rlc;
616  fixed_occ = rlci->occlusion;
617  fixed_mask = rlci->transparency_mask;
618  rlc->level = fixed_occ;
619  rlc->transparency_mask = fixed_mask;
620  }
621  }
622  }
623  LISTBASE_FOREACH (LineartLineChain *, irlc, &rb->chains) {
625  }
626 }
627 
632  LineartLineChain *onto,
633  LineartLineChain *sub,
634  int reverse_1,
635  int reverse_2)
636 {
637  LineartLineChainItem *rlci;
638  if (onto->type == LRT_EDGE_FLAG_INTERSECTION) {
639  if (sub->object_ref) {
640  onto->object_ref = sub->object_ref;
641  onto->type = LRT_EDGE_FLAG_CONTOUR;
642  }
643  }
644  else if (sub->type == LRT_EDGE_FLAG_INTERSECTION) {
645  if (onto->type != LRT_EDGE_FLAG_INTERSECTION) {
646  onto->type = LRT_EDGE_FLAG_CONTOUR;
647  }
648  }
649  if (!reverse_1) { /* L--R L-R. */
650  if (reverse_2) { /* L--R R-L. */
652  }
653  rlci = sub->chain.first;
654  if (lineart_point_overlapping(onto->chain.last, rlci->pos[0], rlci->pos[1], 1e-5)) {
655  BLI_pophead(&sub->chain);
656  if (sub->chain.first == NULL) {
657  return;
658  }
659  }
660  ((LineartLineChainItem *)onto->chain.last)->next = sub->chain.first;
661  ((LineartLineChainItem *)sub->chain.first)->prev = onto->chain.last;
662  onto->chain.last = sub->chain.last;
663  }
664  else { /* L-R L--R. */
665  if (!reverse_2) { /* R-L L--R. */
667  }
668  rlci = onto->chain.first;
669  if (lineart_point_overlapping(sub->chain.last, rlci->pos[0], rlci->pos[1], 1e-5)) {
670  BLI_pophead(&onto->chain);
671  if (onto->chain.first == NULL) {
672  return;
673  }
674  }
675  ((LineartLineChainItem *)sub->chain.last)->next = onto->chain.first;
676  ((LineartLineChainItem *)onto->chain.first)->prev = sub->chain.last;
677  onto->chain.first = sub->chain.first;
678  }
679 }
680 
683  LineartLineChain *rlc,
684  LineartLineChainItem *rlci,
685  int occlusion,
686  unsigned char transparency_mask,
687  float dist,
688  float *result_new_len,
689  LineartBoundingArea *caller_ba)
690 {
691 
692  LineartChainRegisterEntry *closest_cre = NULL;
693 
694  /* Keep using for loop because `cre` could be removed from the iteration before getting to the
695  * next one. */
697  if (cre->rlc->object_ref != rlc->object_ref) {
698  if (!rb->fuzzy_everything) {
699  if (rb->fuzzy_intersections) {
700  /* If none of those are intersection lines... */
701  if ((!(cre->rlc->type & LRT_EDGE_FLAG_INTERSECTION)) &&
702  (!(rlc->type & LRT_EDGE_FLAG_INTERSECTION))) {
703  continue; /* We don't want to chain along different objects at the moment. */
704  }
705  }
706  else {
707  continue;
708  }
709  }
710  }
711  if (cre->rlc->picked || cre->picked) {
712  continue;
713  }
714  if (cre->rlc == rlc || (!cre->rlc->chain.first) || (cre->rlc->level != occlusion) ||
715  (cre->rlc->transparency_mask != transparency_mask)) {
716  continue;
717  }
718  if (!rb->fuzzy_everything) {
719  if (cre->rlc->type != rlc->type) {
720  if (rb->fuzzy_intersections) {
721  if (!(cre->rlc->type == LRT_EDGE_FLAG_INTERSECTION ||
722  rlc->type == LRT_EDGE_FLAG_INTERSECTION)) {
723  continue; /* Fuzzy intersections but no intersection line found. */
724  }
725  }
726  else { /* Line type different but no fuzzy. */
727  continue;
728  }
729  }
730  }
731 
732  float new_len = len_v2v2(cre->rlci->pos, rlci->pos);
733  if (new_len < dist) {
734  closest_cre = cre;
735  dist = new_len;
736  if (result_new_len) {
737  (*result_new_len) = new_len;
738  }
739  }
740  }
741 
742  /* We want a closer point anyway. So using modified dist is fine. */
743  float adjacent_new_len = dist;
744  LineartChainRegisterEntry *adjacent_closest;
745 
746 #define LRT_TEST_ADJACENT_AREAS(dist_to, list) \
747  if (dist_to < dist && dist_to > 0) { \
748  LISTBASE_FOREACH (LinkData *, ld, list) { \
749  LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \
750  adjacent_closest = lineart_chain_get_closest_cre( \
751  rb, sba, rlc, rlci, occlusion, transparency_mask, dist, &adjacent_new_len, ba); \
752  if (adjacent_new_len < dist) { \
753  dist = adjacent_new_len; \
754  closest_cre = adjacent_closest; \
755  } \
756  } \
757  }
758  if (!caller_ba) {
759  LRT_TEST_ADJACENT_AREAS(rlci->pos[0] - ba->l, &ba->lp);
760  LRT_TEST_ADJACENT_AREAS(ba->r - rlci->pos[0], &ba->rp);
761  LRT_TEST_ADJACENT_AREAS(ba->u - rlci->pos[1], &ba->up);
762  LRT_TEST_ADJACENT_AREAS(rlci->pos[1] - ba->b, &ba->bp);
763  }
764  if (result_new_len) {
765  (*result_new_len) = dist;
766  }
767  return closest_cre;
768 }
769 
776 {
777  LineartLineChain *rlc;
778  LineartLineChainItem *rlci_l, *rlci_r;
779  LineartBoundingArea *ba_l, *ba_r;
780  LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
781  float dist = rb->chaining_image_threshold;
782  float dist_l, dist_r;
783  int occlusion, reverse_main;
784  unsigned char transparency_mask;
785  ListBase swap = {0};
786 
787  if (rb->chaining_image_threshold < 0.0001) {
788  return;
789  }
790 
791  swap.first = rb->chains.first;
792  swap.last = rb->chains.last;
793 
794  rb->chains.last = rb->chains.first = NULL;
795 
796  while ((rlc = BLI_pophead(&swap)) != NULL) {
797  rlc->next = rlc->prev = NULL;
798  if (rlc->picked) {
799  continue;
800  }
801  BLI_addtail(&rb->chains, rlc);
802 
803  occlusion = rlc->level;
804  transparency_mask = rlc->transparency_mask;
805 
806  rlci_l = rlc->chain.first;
807  rlci_r = rlc->chain.last;
808  while ((ba_l = lineart_bounding_area_get_end_point(rb, rlci_l)) &&
809  (ba_r = lineart_bounding_area_get_end_point(rb, rlci_r))) {
810  closest_cre_l = lineart_chain_get_closest_cre(
811  rb, ba_l, rlc, rlci_l, occlusion, transparency_mask, dist, &dist_l, NULL);
812  closest_cre_r = lineart_chain_get_closest_cre(
813  rb, ba_r, rlc, rlci_r, occlusion, transparency_mask, dist, &dist_r, NULL);
814  if (closest_cre_l && closest_cre_r) {
815  if (dist_l < dist_r) {
816  closest_cre = closest_cre_l;
817  reverse_main = 1;
818  }
819  else {
820  closest_cre = closest_cre_r;
821  reverse_main = 0;
822  }
823  }
824  else if (closest_cre_l) {
825  closest_cre = closest_cre_l;
826  reverse_main = 1;
827  }
828  else if (closest_cre_r) {
829  closest_cre = closest_cre_r;
830  BLI_remlink(&ba_r->linked_chains, closest_cre_r);
831  reverse_main = 0;
832  }
833  else {
834  break;
835  }
836  closest_cre->picked = 1;
837  closest_cre->rlc->picked = 1;
838  if (closest_cre->is_left) {
839  lineart_chain_connect(rb, rlc, closest_cre->rlc, reverse_main, 0);
840  }
841  else {
842  lineart_chain_connect(rb, rlc, closest_cre->rlc, reverse_main, 1);
843  }
844  BLI_remlink(&swap, closest_cre->rlc);
845  rlci_l = rlc->chain.first;
846  rlci_r = rlc->chain.last;
847  }
848  rlc->picked = 1;
849  }
850 }
851 
856 {
857  LineartLineChainItem *rlci;
858  float offset_accum = 0;
859  float dist;
860  float last_point[2];
861 
862  rlci = rlc->chain.first;
863  copy_v2_v2(last_point, rlci->pos);
864  for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
865  dist = len_v2v2(rlci->pos, last_point);
866  offset_accum += dist;
867  copy_v2_v2(last_point, rlci->pos);
868  }
869  return offset_accum;
870 }
871 
872 void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
873 {
874  LineartLineChain *rlc, *next_rlc;
875  for (rlc = rb->chains.first; rlc; rlc = next_rlc) {
876  next_rlc = rlc->next;
877  if (MOD_lineart_chain_compute_length(rlc) < threshold) {
878  BLI_remlink(&rb->chains, rlc);
879  }
880  }
881 }
882 
884 {
885  int count = 0;
886  LISTBASE_FOREACH (LineartLineChainItem *, rlci, &rlc->chain) {
887  count++;
888  }
889  return count;
890 }
891 
893 {
894  if (rb == NULL) {
895  return;
896  }
897  LISTBASE_FOREACH (LineartLineChain *, rlc, &rb->chains) {
898  rlc->picked = 0;
899  }
900 }
901 
906 void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
907 {
908  LineartLineChain *rlc, *new_rlc;
909  LineartLineChainItem *rlci, *next_rlci, *prev_rlci;
910  ListBase swap = {0};
911 
912  swap.first = rb->chains.first;
913  swap.last = rb->chains.last;
914 
915  rb->chains.last = rb->chains.first = NULL;
916 
917  while ((rlc = BLI_pophead(&swap)) != NULL) {
918  rlc->next = rlc->prev = NULL;
919  BLI_addtail(&rb->chains, rlc);
921  for (rlci = first_rlci->next; rlci; rlci = next_rlci) {
922  next_rlci = rlci->next;
923  prev_rlci = rlci->prev;
924  float angle = M_PI;
925  if (next_rlci && prev_rlci) {
926  angle = angle_v2v2v2(prev_rlci->pos, rlci->pos, next_rlci->pos);
927  }
928  else {
929  break; /* No need to split at the last point anyway.*/
930  }
931  if (angle < angle_threshold_rad) {
932  new_rlc = lineart_chain_create(rb);
933  new_rlc->chain.first = rlci;
934  new_rlc->chain.last = rlc->chain.last;
935  rlc->chain.last = rlci->prev;
936  ((LineartLineChainItem *)rlc->chain.last)->next = 0;
937  rlci->prev = 0;
938 
939  /* End the previous one. */
941  rlc,
942  rlci->pos,
943  rlci->gpos,
944  rlci->normal,
945  rlci->line_type,
946  rlc->level,
947  rlci->transparency_mask,
948  rlci->index);
949  new_rlc->object_ref = rlc->object_ref;
950  new_rlc->type = rlc->type;
951  new_rlc->level = rlc->level;
952  new_rlc->transparency_mask = rlc->transparency_mask;
953  rlc = new_rlc;
954  }
955  }
956  }
957 }
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void void void void void void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1)
Definition: listbase.c:871
#define M_PI
Definition: BLI_math_base.h:38
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:453
MINLINE float normalize_v3(float r[3])
void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], const double t)
Definition: math_vector.c:1456
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
#define UNUSED(x)
void swap(T &a, T &b)
Definition: Common.h:33
@ LRT_EDGE_FLAG_INTERSECTION
@ LRT_EDGE_FLAG_CHAIN_PICKED
@ LRT_EDGE_FLAG_CONTOUR
#define LRT_EDGE_FLAG_ALL_TYPE
_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
_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
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
IconTextureDrawCall normal
int count
#define POS_TO_FLOAT(lpos, gpos)
static LineartBoundingArea * lineart_bounding_area_get_end_point(LineartRenderBuffer *rb, LineartLineChainItem *rlci)
#define IN_BOUND(ba, rlci)
static bool lineart_point_overlapping(LineartLineChainItem *rlci, float x, float y, double threshold)
Definition: lineart_chain.c:84
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
#define VERT_COORD_TO_FLOAT(a)
void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
int MOD_lineart_chain_count(const LineartLineChain *rlc)
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartLineChain *rlc)
#define LRT_TEST_ADJACENT_AREAS(dist_to, list)
static LineartBoundingArea * lineart_bounding_area_get_rlci_recursive(LineartRenderBuffer *rb, LineartBoundingArea *root, LineartLineChainItem *rlci)
static LineartLineChainItem * lineart_chain_prepend_point(LineartRenderBuffer *rb, LineartLineChain *rlc, float *fbcoord, float *gpos, float *normal, char type, int level, unsigned char transparency_mask, size_t index)
static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb), LineartLineChain *onto, LineartLineChain *sub, int reverse_1, int reverse_2)
void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
void MOD_lineart_chain_clear_picked_flag(LineartRenderBuffer *rb)
static LineartLineChainItem * lineart_chain_append_point(LineartRenderBuffer *rb, LineartLineChain *rlc, float *fbcoord, float *gpos, float *normal, char type, int level, unsigned char transparency_mask, size_t index)
Definition: lineart_chain.c:99
static LineartEdge * lineart_line_get_connected(LineartBoundingArea *ba, LineartVert *rv, LineartVert **new_rv, int match_flag)
Definition: lineart_chain.c:38
static LineartLineChain * lineart_chain_create(LineartRenderBuffer *rb)
Definition: lineart_chain.c:74
float MOD_lineart_chain_compute_length(LineartLineChain *rlc)
static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb, LineartBoundingArea *root, LineartLineChain *rlc, LineartLineChainItem *rlci)
#define LRT_OTHER_RV(e, rv)
Definition: lineart_chain.c:34
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
static LineartChainRegisterEntry * lineart_chain_get_closest_cre(LineartRenderBuffer *rb, LineartBoundingArea *ba, LineartLineChain *rlc, LineartLineChainItem *rlci, int occlusion, unsigned char transparency_mask, float dist, float *result_new_len, LineartBoundingArea *caller_ba)
LineartBoundingArea * MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb, double x, double y)
Definition: lineart_cpu.c:3268
LineartBoundingArea * MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
Definition: lineart_cpu.c:3342
void * lineart_list_append_pointer_pool_sized(ListBase *h, struct LineartStaticMemPool *smp, void *data, int size)
Definition: lineart_util.c:51
void * lineart_mem_aquire(struct LineartStaticMemPool *smp, size_t size)
Definition: lineart_util.c:95
#define LRT_ITER_ALL_LINES_END
#define LRT_ITER_ALL_LINES_NEXT
#define LRT_ITER_ALL_LINES_BEGIN
params N
struct LineartBoundingArea * child
Definition: MOD_lineart.h:381
ListBase linked_chains
Definition: MOD_lineart.h:394
LineartLineChain * rlc
Definition: MOD_lineart.h:199
LineartLineChainItem * rlci
Definition: MOD_lineart.h:200
struct LineartVert * v2
Definition: MOD_lineart.h:143
ListBase segments
Definition: MOD_lineart.h:150
unsigned char flags
Definition: MOD_lineart.h:154
struct LineartTriangle * t2
Definition: MOD_lineart.h:149
struct LineartTriangle * t1
Definition: MOD_lineart.h:149
struct LineartVert * v1
Definition: MOD_lineart.h:143
struct LineartLineChainItem * next
Definition: MOD_lineart.h:185
struct LineartLineChainItem * prev
Definition: MOD_lineart.h:185
unsigned char transparency_mask
Definition: MOD_lineart.h:193
struct LineartLineChain * next
Definition: MOD_lineart.h:167
struct LineartLineChain * prev
Definition: MOD_lineart.h:167
unsigned char transparency_mask
Definition: MOD_lineart.h:179
struct Object * object_ref
Definition: MOD_lineart.h:181
struct LineartLineSegment * prev
Definition: MOD_lineart.h:97
struct LineartLineSegment * next
Definition: MOD_lineart.h:97
unsigned char transparency_mask
Definition: MOD_lineart.h:109
unsigned char occlusion
Definition: MOD_lineart.h:101
LineartStaticMemPool render_data_pool
Definition: MOD_lineart.h:231
float chaining_image_threshold
Definition: MOD_lineart.h:298
double gn[3]
Definition: MOD_lineart.h:52
double fbcoord[4]
Definition: MOD_lineart.h:114
double gloc[3]
Definition: MOD_lineart.h:113
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47