Blender  V3.3
lineart_cpu.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 
4 /* \file
5  * \ingroup editors
6  */
7 
8 #include "MOD_gpencil_lineart.h"
9 #include "MOD_lineart.h"
10 
11 #include "BLI_edgehash.h"
12 #include "BLI_linklist.h"
13 #include "BLI_listbase.h"
14 #include "BLI_math.h"
15 #include "BLI_task.h"
16 #include "BLI_utildefines.h"
17 
18 #include "PIL_time.h"
19 
20 #include "BKE_camera.h"
21 #include "BKE_collection.h"
22 #include "BKE_customdata.h"
23 #include "BKE_deform.h"
24 #include "BKE_duplilist.h"
25 #include "BKE_editmesh.h"
26 #include "BKE_global.h"
27 #include "BKE_gpencil.h"
28 #include "BKE_gpencil_geom.h"
29 #include "BKE_gpencil_modifier.h"
30 #include "BKE_lib_id.h"
31 #include "BKE_material.h"
32 #include "BKE_mesh.h"
33 #include "BKE_mesh_mapping.h"
34 #include "BKE_mesh_runtime.h"
35 #include "BKE_object.h"
36 #include "BKE_pointcache.h"
37 #include "BKE_scene.h"
38 #include "DEG_depsgraph_query.h"
39 #include "DNA_camera_types.h"
40 #include "DNA_collection_types.h"
41 #include "DNA_gpencil_types.h"
42 #include "DNA_light_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_modifier_types.h"
47 #include "DNA_scene_types.h"
48 #include "MEM_guardedalloc.h"
49 
50 #include "lineart_intern.h"
51 
52 typedef struct LineartIsecSingle {
53  double v1[3], v2[3];
56 
57 typedef struct LineartIsecThread {
58  int thread_id;
59 
60  /* Scheduled work range. */
64  int index_to;
65 
66  /* Thread intersection result data. */
68  int current;
69  int max;
71 
72  /* For individual thread reference.*/
75 
76 typedef struct LineartIsecData {
81 
83  LineartBoundingArea *root_ba,
84  LineartEdge *e);
85 
87  LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend);
88 
90  const LineartEdge *e,
91  const double *override_camera_loc,
92  const bool override_cam_is_persp,
93  const bool allow_overlapping_edges,
94  const double m_view_projection[4][4],
95  const double camera_dir[3],
96  const float cam_shift_x,
97  const float cam_shift_y,
98  double *from,
99  double *to);
100 
102  LineartBoundingArea *root_ba,
103  LineartTriangle *tri,
104  double l_r_u_b[4],
105  int recursive,
106  int recursive_level,
107  bool do_intersection,
108  struct LineartIsecThread *th);
109 
110 static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive);
111 
113 
114 static LineartCache *lineart_init_cache(void);
115 
117 {
118  BLI_spin_lock(&ld->lock_cuts);
119 
120  memset(es, 0, sizeof(LineartEdgeSegment));
121 
122  /* Storing the node for potentially reuse the memory for new segment data.
123  * Line Art data is not freed after all calculations are done. */
124  BLI_addtail(&ld->wasted_cuts, es);
125 
127 }
128 
130 {
131  BLI_spin_lock(&ld->lock_cuts);
132 
133  /* See if there is any already allocated memory we can reuse. */
134  if (ld->wasted_cuts.first) {
137  memset(es, 0, sizeof(LineartEdgeSegment));
138  return es;
139  }
141 
142  /* Otherwise allocate some new memory. */
144  sizeof(LineartEdgeSegment));
145 }
146 
151  LineartEdge *e,
152  double start,
153  double end,
154  uchar material_mask_bits,
155  uchar mat_occlusion,
156  uint32_t shadow_bits)
157 {
158  LineartEdgeSegment *seg, *i_seg, *next_seg, *prev_seg;
159  LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0;
160  LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0;
161  int untouched = 0;
162 
163  /* If for some reason the occlusion function may give a result that has zero length, or reversed
164  * in direction, or NAN, we take care of them here. */
165  if (LRT_DOUBLE_CLOSE_ENOUGH(start, end)) {
166  return;
167  }
168  if (LRT_DOUBLE_CLOSE_ENOUGH(start, 1) || LRT_DOUBLE_CLOSE_ENOUGH(end, 0)) {
169  return;
170  }
171  if (UNLIKELY(start != start)) {
172  start = 0;
173  }
174  if (UNLIKELY(end != end)) {
175  end = 0;
176  }
177 
178  if (start > end) {
179  double t = start;
180  start = end;
181  end = t;
182  }
183 
184  /* Begin looking for starting position of the segment. */
185  /* Not using a list iteration macro because of it more clear when using for loops to iterate
186  * through the segments. */
187  for (seg = e->segments.first; seg; seg = seg->next) {
188  if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, start)) {
189  cut_start_before = seg;
190  new_seg1 = cut_start_before;
191  break;
192  }
193  if (seg->next == NULL) {
194  break;
195  }
196  i_seg = seg->next;
197  if (i_seg->ratio > start + 1e-09 && start > seg->ratio) {
198  cut_start_before = i_seg;
199  new_seg1 = lineart_give_segment(ld);
200  break;
201  }
202  }
203  if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
204  untouched = 1;
205  }
206  for (seg = cut_start_before; seg; seg = seg->next) {
207  /* We tried to cut ratio existing cutting point (e.g. where the line's occluded by a triangle
208  * strip). */
209  if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, end)) {
210  cut_end_before = seg;
211  new_seg2 = cut_end_before;
212  break;
213  }
214  /* This check is to prevent `es->ratio == 1.0` (where we don't need to cut because we are ratio
215  * the end point). */
216  if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
217  cut_end_before = seg;
218  new_seg2 = cut_end_before;
219  untouched = 1;
220  break;
221  }
222  /* When an actual cut is needed in the line. */
223  if (seg->ratio > end) {
224  cut_end_before = seg;
225  new_seg2 = lineart_give_segment(ld);
226  break;
227  }
228  }
229 
230  /* When we still can't find any existing cut in the line, we allocate new ones. */
231  if (new_seg1 == NULL) {
232  new_seg1 = lineart_give_segment(ld);
233  }
234  if (new_seg2 == NULL) {
235  if (untouched) {
236  new_seg2 = new_seg1;
237  cut_end_before = new_seg2;
238  }
239  else {
240  new_seg2 = lineart_give_segment(ld);
241  }
242  }
243 
244  if (cut_start_before) {
245  if (cut_start_before != new_seg1) {
246  /* Insert cutting points for when a new cut is needed. */
247  i_seg = cut_start_before->prev ? cut_start_before->prev : NULL;
248  if (i_seg) {
249  new_seg1->occlusion = i_seg->occlusion;
250  new_seg1->material_mask_bits = i_seg->material_mask_bits;
251  new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits;
252  }
253  BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1);
254  }
255  /* Otherwise we already found a existing cutting point, no need to insert a new one. */
256  }
257  else {
258  /* We have yet to reach a existing cutting point even after we searched the whole line, so we
259  * append the new cut to the end. */
260  i_seg = e->segments.last;
261  new_seg1->occlusion = i_seg->occlusion;
262  new_seg1->material_mask_bits = i_seg->material_mask_bits;
263  new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits;
264  BLI_addtail(&e->segments, new_seg1);
265  }
266  if (cut_end_before) {
267  /* The same manipulation as on "cut_start_before". */
268  if (cut_end_before != new_seg2) {
269  i_seg = cut_end_before->prev ? cut_end_before->prev : NULL;
270  if (i_seg) {
271  new_seg2->occlusion = i_seg->occlusion;
272  new_seg2->material_mask_bits = i_seg->material_mask_bits;
273  new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits;
274  }
275  BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2);
276  }
277  }
278  else {
279  i_seg = e->segments.last;
280  new_seg2->occlusion = i_seg->occlusion;
281  new_seg2->material_mask_bits = i_seg->material_mask_bits;
282  new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits;
283  if (!untouched) {
284  BLI_addtail(&e->segments, new_seg2);
285  }
286  }
287 
288  /* If we touched the cut list, we assign the new cut position based on new cut position,
289  * this way we accommodate precision lost due to multiple cut inserts. */
290  new_seg1->ratio = start;
291  if (!untouched) {
292  new_seg2->ratio = end;
293  }
294  else {
295  /* For the convenience of the loop below. */
296  new_seg2 = new_seg2->next;
297  }
298 
299  /* Register 1 level of occlusion for all touched segments. */
300  for (seg = new_seg1; seg && seg != new_seg2; seg = seg->next) {
301  seg->occlusion += mat_occlusion;
302  seg->material_mask_bits |= material_mask_bits;
303 
304  /* The enclosed shape flag will override regular lit/shaded
305  * flags. See LineartEdgeSegment::shadow_mask_bits for details. */
306  if (shadow_bits == LRT_SHADOW_MASK_ENCLOSED_SHAPE) {
308  e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
310  }
311  else if (seg->shadow_mask_bits & LRT_SHADOW_MASK_SHADED) {
313  }
314  }
315  else {
316  seg->shadow_mask_bits |= shadow_bits;
317  }
318  }
319 
320  /* Reduce adjacent cutting points of the same level, which saves memory. */
321  int8_t min_occ = 127;
322  prev_seg = NULL;
323  for (seg = e->segments.first; seg; seg = next_seg) {
324  next_seg = seg->next;
325 
326  if (prev_seg && prev_seg->occlusion == seg->occlusion &&
327  prev_seg->material_mask_bits == seg->material_mask_bits &&
328  prev_seg->shadow_mask_bits == seg->shadow_mask_bits) {
329  BLI_remlink(&e->segments, seg);
330  /* This puts the node back to the render buffer, if more cut happens, these unused nodes get
331  * picked first. */
332  lineart_discard_segment(ld, seg);
333  continue;
334  }
335 
336  min_occ = MIN2(min_occ, seg->occlusion);
337 
338  prev_seg = seg;
339  }
340  e->min_occ = min_occ;
341 }
342 
347 {
348  return (((e->target_reference & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference) ||
349  (((e->target_reference >> 32) & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference));
350 }
351 
353 {
354  ba->max_triangle_count *= 2;
356  sizeof(LineartTriangle *) * ba->max_triangle_count);
357 }
358 
360 {
361  /* In case of too many lines concentrating in one point, do not add anymore, these lines will
362  * be either shorter than a single pixel, or will still be added into the list of other less
363  * dense areas. */
364  if (ba->line_count >= 65535) {
365  return;
366  }
367  if (ba->line_count >= ba->max_line_count) {
368  LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * ba->max_line_count * 2,
369  "new ba_line_array");
370  memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count);
371  ba->max_line_count *= 2;
372  MEM_freeN(ba->linked_lines);
373  ba->linked_lines = new_array;
374  }
375  ba->linked_lines[ba->line_count] = e;
376  ba->line_count++;
377 }
378 
380 {
382  double l, r;
383  LRT_EDGE_BA_MARCHING_BEGIN(e->v1->fbcoord, e->v2->fbcoord)
384  {
385  for (int i = 0; i < nba->triangle_count; i++) {
386  tri = (LineartTriangleThread *)nba->linked_triangles[i];
387  /* If we are already testing the line in this thread, then don't do it. */
389  /* Ignore this triangle if an intersection line directly comes from it, */
391  /* Or if this triangle isn't effectively occluding anything nor it's providing a
392  * material flag. */
393  ((!tri->base.mat_occlusion) && (!tri->base.material_mask_bits))) {
394  continue;
395  }
396  tri->testing_e[thread_id] = e;
398  e,
399  ld->conf.camera_pos,
400  ld->conf.cam_is_persp,
402  ld->conf.view_projection,
403  ld->conf.view_vector,
404  ld->conf.shift_x,
405  ld->conf.shift_y,
406  &l,
407  &r)) {
408  lineart_edge_cut(ld, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion, 0);
409  if (e->min_occ > ld->conf.max_occlusion_level) {
410  /* No need to calculate any longer on this line because no level more than set value is
411  * going to show up in the rendered result. */
412  return;
413  }
414  }
415  }
416  LRT_EDGE_BA_MARCHING_NEXT(e->v1->fbcoord, e->v2->fbcoord)
417  }
419 }
420 
422 {
423  int res = 0;
424  int starting_index;
425 
426  BLI_spin_lock(&ld->lock_task);
427 
428  starting_index = ld->scheduled_count;
430 
432 
433  if (starting_index >= ld->pending_edges.next) {
434  res = 0;
435  }
436  else {
437  rti->pending_edges.array = &ld->pending_edges.array[starting_index];
438  int remaining = ld->pending_edges.next - starting_index;
439  rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT);
440  res = 1;
441  }
442 
443  return res;
444 }
445 
447 {
448  LineartData *ld = rti->ld;
449  LineartEdge *eip;
450 
451  while (lineart_occlusion_make_task_info(ld, rti)) {
452  for (int i = 0; i < rti->pending_edges.max; i++) {
453  eip = rti->pending_edges.array[i];
455  }
456  }
457 }
458 
465 {
466  int thread_count = ld->thread_count;
467  LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count,
468  "Task Pool");
469  int i;
470 
472 
473  for (i = 0; i < thread_count; i++) {
474  rti[i].thread_id = i;
475  rti[i].ld = ld;
477  }
479  BLI_task_pool_free(tp);
480 
481  MEM_freeN(rti);
482 }
483 
491 static bool lineart_point_inside_triangle(const double v[2],
492  const double v0[2],
493  const double v1[2],
494  const double v2[2])
495 {
496  double cl, c, cl0;
497 
498  cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
499  c = cl0 = cl;
500 
501  cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
502  if (c * cl <= 0) {
503  return false;
504  }
505 
506  c = cl;
507 
508  cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
509  if (c * cl <= 0) {
510  return false;
511  }
512 
513  c = cl;
514 
515  if (c * cl0 <= 0) {
516  return false;
517  }
518 
519  return true;
520 }
521 
522 static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2])
523 {
524  /* `c1 != c2` by default. */
525  double c1 = 1, c2 = 0;
526  double l0[2], l1[2];
527 
528  sub_v2_v2v2_db(l0, v, v0);
529  sub_v2_v2v2_db(l1, v, v1);
530 
531  if (v1[0] == v0[0] && v1[1] == v0[1]) {
532  return 0;
533  }
534 
535  if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[0], v0[0])) {
536  c1 = ratiod(v0[0], v1[0], v[0]);
537  }
538  else {
539  if (LRT_DOUBLE_CLOSE_ENOUGH(v[0], v1[0])) {
540  c2 = ratiod(v0[1], v1[1], v[1]);
541  return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM);
542  }
543  return false;
544  }
545 
546  if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) {
547  c2 = ratiod(v0[1], v1[1], v[1]);
548  }
549  else {
550  if (LRT_DOUBLE_CLOSE_ENOUGH(v[1], v1[1])) {
551  c1 = ratiod(v0[0], v1[0], v[0]);
552  return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM);
553  }
554  return false;
555  }
556 
557  if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
558  return 1;
559  }
560 
561  return 0;
562 }
563 
568 };
569 
574 static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[2], double v2[2])
575 {
576  double cl, c;
577  double r;
580  return LRT_ON_TRIANGLE;
581  }
582 
583  cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
584  c = cl;
585 
586  cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
587  if ((r = c * cl) < 0) {
588  return LRT_OUTSIDE_TRIANGLE;
589  }
590 
591  c = cl;
592 
593  cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
594  if ((r = c * cl) < 0) {
595  return LRT_OUTSIDE_TRIANGLE;
596  }
597 
598  c = cl;
599 
600  cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
601  if ((r = c * cl) < 0) {
602  return LRT_OUTSIDE_TRIANGLE;
603  }
604 
605  if (r == 0) {
606  return LRT_ON_TRIANGLE;
607  }
608 
609  return LRT_INSIDE_TRIANGLE;
610 }
611 
616 static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1[3], double v2[3])
617 {
618  double l[3], r[3];
619  double N1[3], N2[3];
620  double d;
621 
622  sub_v3_v3v3_db(l, v1, v0);
623  sub_v3_v3v3_db(r, v, v1);
624  cross_v3_v3v3_db(N1, l, r);
625 
626  sub_v3_v3v3_db(l, v2, v1);
627  sub_v3_v3v3_db(r, v, v2);
628  cross_v3_v3v3_db(N2, l, r);
629 
630  if ((d = dot_v3v3_db(N1, N2)) < 0) {
631  return false;
632  }
633 
634  sub_v3_v3v3_db(l, v0, v2);
635  sub_v3_v3v3_db(r, v, v0);
636  cross_v3_v3v3_db(N1, l, r);
637 
638  if ((d = dot_v3v3_db(N1, N2)) < 0) {
639  return false;
640  }
641 
642  sub_v3_v3v3_db(l, v1, v0);
643  sub_v3_v3v3_db(r, v, v1);
644  cross_v3_v3v3_db(N2, l, r);
645 
646  if ((d = dot_v3v3_db(N1, N2)) < 0) {
647  return false;
648  }
649 
650  return true;
651 }
652 
658 {
660 
661  /* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles
662  * are relatively small. */
663  LineartTriangle *render_triangles = lineart_mem_acquire(&ld->render_data_pool,
664  64 * ld->sizeof_triangle);
665 
667  &ld->render_data_pool,
668  render_triangles,
669  sizeof(LineartElementLinkNode));
670  eln->element_count = 64;
672 
673  return eln;
674 }
675 
677 {
679 
680  LineartVert *render_vertices = lineart_mem_acquire(&ld->render_data_pool,
681  sizeof(LineartVert) * 64);
682 
684  &ld->render_data_pool,
685  render_vertices,
686  sizeof(LineartElementLinkNode));
687  eln->element_count = 64;
689 
690  return eln;
691 }
692 
694 {
696 
697  LineartEdge *render_edges = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * 64);
698 
700  ld->edge_data_pool,
701  render_edges,
702  sizeof(LineartElementLinkNode));
703  eln->element_count = 64;
706 
707  return eln;
708 }
709 
711 {
712  /* Just re-assign normal and set cull flag. */
713  copy_v3_v3_db(tri->gn, orig->gn);
714  tri->flags = LRT_CULL_GENERATED;
717  tri->mat_occlusion = orig->mat_occlusion;
719  tri->target_reference = orig->target_reference;
720 }
721 
723 {
724  uchar intersection_only = (tri->flags & LRT_TRIANGLE_INTERSECTION_ONLY);
725  tri->flags = flag;
726  tri->flags |= intersection_only;
727 }
728 
729 static bool lineart_edge_match(LineartTriangle *tri, LineartEdge *e, int v1, int v2)
730 {
731  return ((tri->v[v1] == e->v1 && tri->v[v2] == e->v2) ||
732  (tri->v[v2] == e->v1 && tri->v[v1] == e->v2));
733 }
734 
736 {
737  LineartEdge *e = old_e;
738  while (e->flags & LRT_EDGE_FLAG_NEXT_IS_DUPLICATION) {
739  e++;
740  e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
741  }
742 }
743 
749  LineartTriangle *tri,
750  int in0,
751  int in1,
752  int in2,
753  double cam_pos[3],
754  double view_dir[3],
755  bool allow_boundaries,
756  double m_view_projection[4][4],
757  Object *ob,
758  int *r_v_count,
759  int *r_e_count,
760  int *r_t_count,
761  LineartElementLinkNode *v_eln,
762  LineartElementLinkNode *e_eln,
763  LineartElementLinkNode *t_eln)
764 {
765  double span_v1[3], span_v2[3], dot_v1, dot_v2;
766  double a;
767  int v_count = *r_v_count;
768  int e_count = *r_e_count;
769  int t_count = *r_t_count;
770  uint16_t new_flag = 0;
771 
772  LineartEdge *new_e, *e, *old_e;
773  LineartEdgeSegment *es;
774  LineartTriangleAdjacent *tri_adj;
775 
777  return;
778  }
779 
780  /* See definition of tri->intersecting_verts and the usage in
781  * lineart_geometry_object_load() for details. */
782  tri_adj = (void *)tri->intersecting_verts;
783 
784  LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count];
785  LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count);
786  LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) +
787  ld->sizeof_triangle * (t_count + 1));
788 
789  new_e = &((LineartEdge *)e_eln->pointer)[e_count];
790  /* Init `edge` to the last `edge` entry. */
791  e = new_e;
792 
793 #define INCREASE_EDGE \
794  new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \
795  e_count++; \
796  e = new_e; \
797  es = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment)); \
798  BLI_addtail(&e->segments, es);
799 
800 #define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \
801  if (tri_adj->e[e_num]) { \
802  old_e = tri_adj->e[e_num]; \
803  new_flag = old_e->flags; \
804  old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
805  lineart_discard_duplicated_edges(old_e); \
806  INCREASE_EDGE \
807  e->v1 = (v1_link); \
808  e->v2 = (v2_link); \
809  e->v1->index = (v1_link)->index; \
810  e->v2->index = (v1_link)->index; \
811  e->flags = new_flag; \
812  e->object_ref = ob; \
813  e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
814  e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
815  lineart_add_edge_to_array(&ld->pending_edges, e); \
816  }
817 
818 #define RELINK_EDGE(e_num, new_tri) \
819  if (tri_adj->e[e_num]) { \
820  old_e = tri_adj->e[e_num]; \
821  old_e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
822  old_e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
823  }
824 
825 #define REMOVE_TRIANGLE_EDGE \
826  if (tri_adj->e[0]) { \
827  tri_adj->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
828  lineart_discard_duplicated_edges(tri_adj->e[0]); \
829  } \
830  if (tri_adj->e[1]) { \
831  tri_adj->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
832  lineart_discard_duplicated_edges(tri_adj->e[1]); \
833  } \
834  if (tri_adj->e[2]) { \
835  tri_adj->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
836  lineart_discard_duplicated_edges(tri_adj->e[2]); \
837  }
838 
839  switch (in0 + in1 + in2) {
840  case 0: /* Triangle is visible. Ignore this triangle. */
841  return;
842  case 3:
843  /* Triangle completely behind near plane, throw it away
844  * also remove render lines form being computed. */
847  return;
848  case 2:
849  /* Two points behind near plane, cut those and
850  * generate 2 new points, 3 lines and 1 triangle. */
852 
873  if (!in0) {
874 
875  /* Cut point for line 2---|-----0. */
876  sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
877  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
878  dot_v1 = dot_v3v3_db(span_v1, view_dir);
879  dot_v2 = dot_v3v3_db(span_v2, view_dir);
880  a = dot_v1 / (dot_v1 + dot_v2);
881  /* Assign it to a new point. */
882  interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
883  mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
884  vt[0].index = tri->v[2]->index;
885 
886  /* Cut point for line 1---|-----0. */
887  sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
888  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
889  dot_v1 = dot_v3v3_db(span_v1, view_dir);
890  dot_v2 = dot_v3v3_db(span_v2, view_dir);
891  a = dot_v1 / (dot_v1 + dot_v2);
892  /* Assign it to another new point. */
893  interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
894  mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
895  vt[1].index = tri->v[1]->index;
896 
897  /* New line connecting two new points. */
899  if (allow_boundaries) {
900  e->flags = LRT_EDGE_FLAG_CONTOUR;
902  }
903  /* NOTE: inverting `e->v1/v2` (left/right point) doesn't matter as long as
904  * `tri->edge` and `tri->v` has the same sequence. and the winding direction
905  * can be either CW or CCW but needs to be consistent throughout the calculation. */
906  e->v1 = &vt[1];
907  e->v2 = &vt[0];
908  /* Only one adjacent triangle, because the other side is the near plane. */
909  /* Use `tl` or `tr` doesn't matter. */
910  e->t1 = tri1;
911  e->object_ref = ob;
912 
913  /* New line connecting original point 0 and a new point, only when it's a selected line. */
914  SELECT_EDGE(2, tri->v[0], &vt[0], tri1)
915  /* New line connecting original point 0 and another new point. */
916  SELECT_EDGE(0, tri->v[0], &vt[1], tri1)
917 
918  /* Re-assign triangle point array to two new points. */
919  tri1->v[0] = tri->v[0];
920  tri1->v[1] = &vt[1];
921  tri1->v[2] = &vt[0];
922 
923  lineart_triangle_post(tri1, tri);
924 
925  v_count += 2;
926  t_count += 1;
927  }
928  else if (!in2) {
929  sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
930  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
931  dot_v1 = dot_v3v3_db(span_v1, view_dir);
932  dot_v2 = dot_v3v3_db(span_v2, view_dir);
933  a = dot_v1 / (dot_v1 + dot_v2);
934  interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
935  mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
936  vt[0].index = tri->v[0]->index;
937 
938  sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
939  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
940  dot_v1 = dot_v3v3_db(span_v1, view_dir);
941  dot_v2 = dot_v3v3_db(span_v2, view_dir);
942  a = dot_v1 / (dot_v1 + dot_v2);
943  interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
944  mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
945  vt[1].index = tri->v[1]->index;
946 
948  if (allow_boundaries) {
949  e->flags = LRT_EDGE_FLAG_CONTOUR;
951  }
952  e->v1 = &vt[0];
953  e->v2 = &vt[1];
954  e->t1 = tri1;
955  e->object_ref = ob;
956 
957  SELECT_EDGE(2, tri->v[2], &vt[0], tri1)
958  SELECT_EDGE(1, tri->v[2], &vt[1], tri1)
959 
960  tri1->v[0] = &vt[0];
961  tri1->v[1] = &vt[1];
962  tri1->v[2] = tri->v[2];
963 
964  lineart_triangle_post(tri1, tri);
965 
966  v_count += 2;
967  t_count += 1;
968  }
969  else if (!in1) {
970  sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
971  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
972  dot_v1 = dot_v3v3_db(span_v1, view_dir);
973  dot_v2 = dot_v3v3_db(span_v2, view_dir);
974  a = dot_v1 / (dot_v1 + dot_v2);
975  interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
976  mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
977  vt[0].index = tri->v[2]->index;
978 
979  sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
980  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
981  dot_v1 = dot_v3v3_db(span_v1, view_dir);
982  dot_v2 = dot_v3v3_db(span_v2, view_dir);
983  a = dot_v1 / (dot_v1 + dot_v2);
984  interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
985  mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
986  vt[1].index = tri->v[0]->index;
987 
989  if (allow_boundaries) {
990  e->flags = LRT_EDGE_FLAG_CONTOUR;
992  }
993  e->v1 = &vt[1];
994  e->v2 = &vt[0];
995  e->t1 = tri1;
996  e->object_ref = ob;
997 
998  SELECT_EDGE(1, tri->v[1], &vt[0], tri1)
999  SELECT_EDGE(0, tri->v[1], &vt[1], tri1)
1000 
1001  tri1->v[0] = &vt[0];
1002  tri1->v[1] = tri->v[1];
1003  tri1->v[2] = &vt[1];
1004 
1005  lineart_triangle_post(tri1, tri);
1006 
1007  v_count += 2;
1008  t_count += 1;
1009  }
1010  break;
1011  case 1:
1012  /* One point behind near plane, cut those and
1013  * generate 2 new points, 4 lines and 2 triangles. */
1015 
1039  if (in0) {
1040  /* Cut point for line 0---|------1. */
1041  sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
1042  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
1043  dot_v1 = dot_v3v3_db(span_v1, view_dir);
1044  dot_v2 = dot_v3v3_db(span_v2, view_dir);
1045  a = dot_v2 / (dot_v1 + dot_v2);
1046  /* Assign to a new point. */
1047  interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
1048  mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
1049  vt[0].index = tri->v[0]->index;
1050 
1051  /* Cut point for line 0---|------2. */
1052  sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
1053  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
1054  dot_v1 = dot_v3v3_db(span_v1, view_dir);
1055  dot_v2 = dot_v3v3_db(span_v2, view_dir);
1056  a = dot_v2 / (dot_v1 + dot_v2);
1057  /* Assign to other new point. */
1058  interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
1059  mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
1060  vt[1].index = tri->v[0]->index;
1061 
1062  /* New line connects two new points. */
1064  if (allow_boundaries) {
1065  e->flags = LRT_EDGE_FLAG_CONTOUR;
1067  }
1068  e->v1 = &vt[1];
1069  e->v2 = &vt[0];
1070  e->t1 = tri1;
1071  e->object_ref = ob;
1072 
1073  /* New line connects new point 0 and old point 1,
1074  * this is a border line. */
1075 
1076  SELECT_EDGE(0, tri->v[1], &vt[0], tri1)
1077  SELECT_EDGE(2, tri->v[2], &vt[1], tri2)
1078  RELINK_EDGE(1, tri2)
1079 
1080  /* We now have one triangle closed. */
1081  tri1->v[0] = tri->v[1];
1082  tri1->v[1] = &vt[1];
1083  tri1->v[2] = &vt[0];
1084  /* Close the second triangle. */
1085  tri2->v[0] = &vt[1];
1086  tri2->v[1] = tri->v[1];
1087  tri2->v[2] = tri->v[2];
1088 
1089  lineart_triangle_post(tri1, tri);
1090  lineart_triangle_post(tri2, tri);
1091 
1092  v_count += 2;
1093  t_count += 2;
1094  }
1095  else if (in1) {
1096 
1097  sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
1098  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
1099  dot_v1 = dot_v3v3_db(span_v1, view_dir);
1100  dot_v2 = dot_v3v3_db(span_v2, view_dir);
1101  a = dot_v1 / (dot_v1 + dot_v2);
1102  interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
1103  mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
1104  vt[0].index = tri->v[1]->index;
1105 
1106  sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
1107  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
1108  dot_v1 = dot_v3v3_db(span_v1, view_dir);
1109  dot_v2 = dot_v3v3_db(span_v2, view_dir);
1110  a = dot_v1 / (dot_v1 + dot_v2);
1111  interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
1112  mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
1113  vt[1].index = tri->v[1]->index;
1114 
1116  if (allow_boundaries) {
1117  e->flags = LRT_EDGE_FLAG_CONTOUR;
1119  }
1120  e->v1 = &vt[1];
1121  e->v2 = &vt[0];
1122 
1123  e->t1 = tri1;
1124  e->object_ref = ob;
1125 
1126  SELECT_EDGE(1, tri->v[2], &vt[0], tri1)
1127  SELECT_EDGE(0, tri->v[0], &vt[1], tri2)
1128  RELINK_EDGE(2, tri2)
1129 
1130  tri1->v[0] = tri->v[2];
1131  tri1->v[1] = &vt[1];
1132  tri1->v[2] = &vt[0];
1133 
1134  tri2->v[0] = &vt[1];
1135  tri2->v[1] = tri->v[2];
1136  tri2->v[2] = tri->v[0];
1137 
1138  lineart_triangle_post(tri1, tri);
1139  lineart_triangle_post(tri2, tri);
1140 
1141  v_count += 2;
1142  t_count += 2;
1143  }
1144  else if (in2) {
1145 
1146  sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
1147  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
1148  dot_v1 = dot_v3v3_db(span_v1, view_dir);
1149  dot_v2 = dot_v3v3_db(span_v2, view_dir);
1150  a = dot_v1 / (dot_v1 + dot_v2);
1151  interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
1152  mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
1153  vt[0].index = tri->v[2]->index;
1154 
1155  sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
1156  sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
1157  dot_v1 = dot_v3v3_db(span_v1, view_dir);
1158  dot_v2 = dot_v3v3_db(span_v2, view_dir);
1159  a = dot_v1 / (dot_v1 + dot_v2);
1160  interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
1161  mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
1162  vt[1].index = tri->v[2]->index;
1163 
1165  if (allow_boundaries) {
1166  e->flags = LRT_EDGE_FLAG_CONTOUR;
1168  }
1169  e->v1 = &vt[1];
1170  e->v2 = &vt[0];
1171 
1172  e->t1 = tri1;
1173  e->object_ref = ob;
1174 
1175  SELECT_EDGE(2, tri->v[0], &vt[0], tri1)
1176  SELECT_EDGE(1, tri->v[1], &vt[1], tri2)
1177  RELINK_EDGE(0, tri2)
1178 
1179  tri1->v[0] = tri->v[0];
1180  tri1->v[1] = &vt[1];
1181  tri1->v[2] = &vt[0];
1182 
1183  tri2->v[0] = &vt[1];
1184  tri2->v[1] = tri->v[0];
1185  tri2->v[2] = tri->v[1];
1186 
1187  lineart_triangle_post(tri1, tri);
1188  lineart_triangle_post(tri2, tri);
1189 
1190  v_count += 2;
1191  t_count += 2;
1192  }
1193  break;
1194  }
1195  *r_v_count = v_count;
1196  *r_e_count = e_count;
1197  *r_t_count = t_count;
1198 
1199 #undef INCREASE_EDGE
1200 #undef SELECT_EDGE
1201 #undef RELINK_EDGE
1202 #undef REMOVE_TRIANGLE_EDGE
1203 }
1204 
1212 {
1213  LineartTriangle *tri;
1214  LineartElementLinkNode *v_eln, *t_eln, *e_eln;
1215  double(*m_view_projection)[4] = ld->conf.view_projection;
1216  int i;
1217  int v_count = 0, t_count = 0, e_count = 0;
1218  Object *ob;
1219  bool allow_boundaries = ld->conf.allow_boundaries;
1220  double cam_pos[3];
1221  double clip_start = ld->conf.near_clip, clip_end = ld->conf.far_clip;
1222  double view_dir[3], clip_advance[3];
1223 
1224  copy_v3_v3_db(view_dir, ld->conf.view_vector);
1225  copy_v3_v3_db(clip_advance, ld->conf.view_vector);
1226  copy_v3_v3_db(cam_pos, ld->conf.camera_pos);
1227 
1228  if (clip_far) {
1229  /* Move starting point to end plane. */
1230  mul_v3db_db(clip_advance, -clip_end);
1231  add_v3_v3_db(cam_pos, clip_advance);
1232 
1233  /* "reverse looking". */
1234  mul_v3db_db(view_dir, -1.0f);
1235  }
1236  else {
1237  /* Clip Near. */
1238  mul_v3db_db(clip_advance, -clip_start);
1239  add_v3_v3_db(cam_pos, clip_advance);
1240  }
1241 
1242  v_eln = lineart_memory_get_vert_space(ld);
1244  e_eln = lineart_memory_get_edge_space(ld);
1245 
1246  /* Additional memory space for storing generated points and triangles. */
1247 #define LRT_CULL_ENSURE_MEMORY \
1248  if (v_count > 60) { \
1249  v_eln->element_count = v_count; \
1250  v_eln = lineart_memory_get_vert_space(ld); \
1251  v_count = 0; \
1252  } \
1253  if (t_count > 60) { \
1254  t_eln->element_count = t_count; \
1255  t_eln = lineart_memory_get_triangle_space(ld); \
1256  t_count = 0; \
1257  } \
1258  if (e_count > 60) { \
1259  e_eln->element_count = e_count; \
1260  e_eln = lineart_memory_get_edge_space(ld); \
1261  e_count = 0; \
1262  }
1263 
1264 #define LRT_CULL_DECIDE_INSIDE \
1265  /* These three represents points that are in the clipping range or not. */ \
1266  in0 = 0, in1 = 0, in2 = 0; \
1267  if (clip_far) { \
1268  /* Point outside far plane. */ \
1269  if (tri->v[0]->fbcoord[use_w] > clip_end) { \
1270  in0 = 1; \
1271  } \
1272  if (tri->v[1]->fbcoord[use_w] > clip_end) { \
1273  in1 = 1; \
1274  } \
1275  if (tri->v[2]->fbcoord[use_w] > clip_end) { \
1276  in2 = 1; \
1277  } \
1278  } \
1279  else { \
1280  /* Point inside near plane. */ \
1281  if (tri->v[0]->fbcoord[use_w] < clip_start) { \
1282  in0 = 1; \
1283  } \
1284  if (tri->v[1]->fbcoord[use_w] < clip_start) { \
1285  in1 = 1; \
1286  } \
1287  if (tri->v[2]->fbcoord[use_w] < clip_start) { \
1288  in2 = 1; \
1289  } \
1290  }
1291 
1292  int use_w = 3;
1293  int in0 = 0, in1 = 0, in2 = 0;
1294 
1295  if (!ld->conf.cam_is_persp) {
1296  clip_start = -1;
1297  clip_end = 1;
1298  use_w = 2;
1299  }
1300 
1301  /* Then go through all the other triangles. */
1303  if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) {
1304  continue;
1305  }
1306  ob = eln->object_ref;
1307  for (i = 0; i < eln->element_count; i++) {
1308  /* Select the triangle in the array. */
1309  tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i);
1310 
1311  if (tri->flags & LRT_CULL_DISCARD) {
1312  continue;
1313  }
1314 
1318  tri,
1319  in0,
1320  in1,
1321  in2,
1322  cam_pos,
1323  view_dir,
1324  allow_boundaries,
1325  m_view_projection,
1326  ob,
1327  &v_count,
1328  &e_count,
1329  &t_count,
1330  v_eln,
1331  e_eln,
1332  t_eln);
1333  }
1334  t_eln->element_count = t_count;
1335  v_eln->element_count = v_count;
1336  }
1337 
1338 #undef LRT_CULL_ENSURE_MEMORY
1339 #undef LRT_CULL_DECIDE_INSIDE
1340 }
1341 
1347 {
1348  LinkData *link;
1349  while ((link = BLI_pophead(&ld->geom.triangle_adjacent_pointers)) != NULL) {
1350  MEM_freeN(link->data);
1351  }
1353  LineartTriangle *tri = eln->pointer;
1354  int i;
1355  for (i = 0; i < eln->element_count; i++) {
1356  /* See definition of tri->intersecting_verts and the usage in
1357  * lineart_geometry_object_load() for detailed. */
1358  tri->intersecting_verts = NULL;
1359  tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle);
1360  }
1361  }
1362 }
1363 
1365 {
1366  LineartVert *vt;
1367  int i;
1368 
1370  vt = eln->pointer;
1371  for (i = 0; i < eln->element_count; i++) {
1372  if (ld->conf.cam_is_persp) {
1373  /* Do not divide Z, we use Z to back transform cut points in later chaining process. */
1374  vt[i].fbcoord[0] /= vt[i].fbcoord[3];
1375  vt[i].fbcoord[1] /= vt[i].fbcoord[3];
1376  /* Re-map z into (0-1) range, because we no longer need NDC (Normalized Device Coordinates)
1377  * at the moment.
1378  * The algorithm currently doesn't need Z for operation, we use W instead. If Z is needed
1379  * in the future, the line below correctly transforms it to view space coordinates. */
1380  // `vt[i].fbcoord[2] = -2 * vt[i].fbcoord[2] / (far - near) - (far + near) / (far - near);
1381  }
1382  /* Shifting is always needed. */
1383  vt[i].fbcoord[0] -= ld->conf.shift_x * 2;
1384  vt[i].fbcoord[1] -= ld->conf.shift_y * 2;
1385  }
1386  }
1387 }
1388 
1390 {
1391  LineartEdge *e;
1392  int i;
1393 
1394 #define LRT_VERT_OUT_OF_BOUND(v) \
1395  (v && (v->fbcoord[0] < -1 || v->fbcoord[0] > 1 || v->fbcoord[1] < -1 || v->fbcoord[1] > 1))
1396 
1398  e = (LineartEdge *)eln->pointer;
1399  for (i = 0; i < eln->element_count; i++) {
1400  if ((LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2))) {
1401  e[i].flags = LRT_EDGE_FLAG_CHAIN_PICKED;
1402  }
1403  }
1404  }
1405 }
1406 
1407 typedef struct LineartEdgeNeighbor {
1408  int e;
1410  int v1, v2;
1412 
1413 typedef struct VertData {
1419 
1420 static void lineart_mvert_transform_task(void *__restrict userdata,
1421  const int i,
1422  const TaskParallelTLS *__restrict UNUSED(tls))
1423 {
1424  VertData *vert_task_data = (VertData *)userdata;
1425  MVert *m_v = &vert_task_data->mvert[i];
1426  double co[4];
1427  LineartVert *v = &vert_task_data->v_arr[i];
1428  copy_v3db_v3fl(co, m_v->co);
1429  mul_v3_m4v3_db(v->gloc, vert_task_data->model_view, co);
1430  mul_v4_m4v3_db(v->fbcoord, vert_task_data->model_view_proj, co);
1431  v->index = i;
1432 }
1433 
1434 static const int LRT_MESH_EDGE_TYPES[] = {
1441 };
1442 
1443 #define LRT_MESH_EDGE_TYPES_COUNT 6
1444 
1446 {
1447  int count = 0;
1448  /* See eLineartEdgeFlag for details. */
1449  for (int i = 0; i < LRT_MESH_EDGE_TYPES_COUNT; i++) {
1450  if (eflag & LRT_MESH_EDGE_TYPES[i]) {
1451  count++;
1452  }
1453  }
1454  return count;
1455 }
1456 
1462  LineartTriangle *rt_array,
1463  int index)
1464 {
1465  int8_t *b = (int8_t *)rt_array;
1466  b += (index * ld->sizeof_triangle);
1467  return (LineartTriangle *)b;
1468 }
1469 
1470 typedef struct EdgeFeatData {
1473  Object *ob_eval; /* For evaluated materials. */
1485 
1486 typedef struct EdgeFeatReduceData {
1489 
1490 static void feat_data_sum_reduce(const void *__restrict UNUSED(userdata),
1491  void *__restrict chunk_join,
1492  void *__restrict chunk)
1493 {
1494  EdgeFeatReduceData *feat_chunk_join = (EdgeFeatReduceData *)chunk_join;
1495  EdgeFeatReduceData *feat_chunk = (EdgeFeatReduceData *)chunk;
1496  feat_chunk_join->feat_edges += feat_chunk->feat_edges;
1497 }
1498 
1499 static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
1500  const int i,
1501  const TaskParallelTLS *__restrict tls)
1502 {
1503  EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
1504  EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
1505  Mesh *me = e_feat_data->me;
1506  Object *ob_eval = e_feat_data->ob_eval;
1507  LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
1508  const MLoopTri *mlooptri = e_feat_data->mlooptri;
1509 
1510  uint16_t edge_flag_result = 0;
1511 
1512  /* Because the edge neighbor array contains loop edge pairs, we only need to process the first
1513  * edge in the pair. Otherwise we would add the same edge that the loops represent twice. */
1514  if (i < edge_nabr[i].e) {
1515  return;
1516  }
1517 
1518  bool face_mark_filtered = false;
1519  bool enable_face_mark = (e_feat_data->use_freestyle_face &&
1520  e_feat_data->ld->conf.filter_face_mark);
1521  bool only_contour = false;
1522  if (enable_face_mark) {
1523  FreestyleFace *ff1, *ff2;
1524  int index = e_feat_data->freestyle_face_index;
1525  if (index > -1) {
1526  ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly];
1527  }
1528  if (edge_nabr[i].e > -1) {
1529  ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly];
1530  }
1531  else {
1532  /* Handle mesh boundary cases: We want mesh boundaries to respect
1533  * `filter_face_mark_boundaries` option the same way as face mark boundaries, and the code
1534  * path is simper when it's assuming both ff1 and ff2 not NULL. */
1535  ff2 = ff1;
1536  }
1537  if (e_feat_data->ld->conf.filter_face_mark_boundaries ^
1538  e_feat_data->ld->conf.filter_face_mark_invert) {
1539  if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) {
1540  face_mark_filtered = true;
1541  }
1542  }
1543  else {
1544  if ((ff1->flag & FREESTYLE_FACE_MARK) && (ff2->flag & FREESTYLE_FACE_MARK) && (ff2 != ff1)) {
1545  face_mark_filtered = true;
1546  }
1547  }
1548  if (e_feat_data->ld->conf.filter_face_mark_invert) {
1549  face_mark_filtered = !face_mark_filtered;
1550  }
1551  if (!face_mark_filtered) {
1552  edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT;
1553  if (e_feat_data->ld->conf.filter_face_mark_keep_contour) {
1554  only_contour = true;
1555  }
1556  }
1557  }
1558 
1559  if (enable_face_mark && !face_mark_filtered && !only_contour) {
1560  return;
1561  }
1562 
1563  /* Mesh boundary */
1564  if (edge_nabr[i].e == -1) {
1565  edge_nabr[i].flags = LRT_EDGE_FLAG_CONTOUR;
1566  reduce_data->feat_edges += 1;
1567  return;
1568  }
1569 
1570  LineartTriangle *tri1, *tri2;
1571  LineartVert *vert;
1572  LineartData *ld = e_feat_data->ld;
1573 
1574  int f1 = i / 3, f2 = edge_nabr[i].e / 3;
1575 
1576  /* The mesh should already be triangulated now, so we can assume each face is a triangle. */
1577  tri1 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f1);
1578  tri2 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f2);
1579 
1580  vert = &e_feat_data->v_array[edge_nabr[i].v1];
1581 
1582  double view_vector_persp[3];
1583  double *view_vector = view_vector_persp;
1584  double dot_v1 = 0, dot_v2 = 0;
1585  double result;
1586  bool material_back_face = ((tri1->flags | tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING);
1587 
1588  if (ld->conf.use_contour || ld->conf.use_back_face_culling || material_back_face) {
1589  if (ld->conf.cam_is_persp) {
1590  sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, vert->gloc);
1591  }
1592  else {
1593  view_vector = ld->conf.view_vector;
1594  }
1595 
1596  dot_v1 = dot_v3v3_db(view_vector, tri1->gn);
1597  dot_v2 = dot_v3v3_db(view_vector, tri2->gn);
1598 
1599  if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) {
1600  edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
1601  }
1602 
1603  if (ld->conf.use_back_face_culling) {
1604  if (dot_v1 < 0) {
1605  tri1->flags |= LRT_CULL_DISCARD;
1606  }
1607  if (dot_v2 < 0) {
1608  tri2->flags |= LRT_CULL_DISCARD;
1609  }
1610  }
1611  if (material_back_face) {
1612  if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v1 < 0) {
1613  tri1->flags |= LRT_CULL_DISCARD;
1614  }
1615  if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v2 < 0) {
1616  tri2->flags |= LRT_CULL_DISCARD;
1617  }
1618  }
1619  }
1620 
1621  if (ld->conf.use_contour_secondary) {
1622  view_vector = view_vector_persp;
1623  if (ld->conf.cam_is_persp_secondary) {
1624  sub_v3_v3v3_db(view_vector, vert->gloc, ld->conf.camera_pos_secondary);
1625  }
1626  else {
1627  view_vector = ld->conf.view_vector_secondary;
1628  }
1629 
1630  dot_v1 = dot_v3v3_db(view_vector, tri1->gn);
1631  dot_v2 = dot_v3v3_db(view_vector, tri2->gn);
1632 
1633  if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) {
1634  edge_flag_result |= LRT_EDGE_FLAG_CONTOUR_SECONDARY;
1635  }
1636  }
1637 
1638  if (!only_contour) {
1639 
1640  if (ld->conf.use_crease) {
1641  bool do_crease = true;
1642  if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth &&
1643  (me->mpoly[mlooptri[f1].poly].flag & ME_SMOOTH) &&
1644  (me->mpoly[mlooptri[f2].poly].flag & ME_SMOOTH)) {
1645  do_crease = false;
1646  }
1647  if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) {
1648  edge_flag_result |= LRT_EDGE_FLAG_CREASE;
1649  }
1650  }
1651 
1652  int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr;
1653  int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr;
1654 
1655  if (mat1 != mat2) {
1656  Material *m1 = BKE_object_material_get_eval(ob_eval, mat1 + 1);
1657  Material *m2 = BKE_object_material_get_eval(ob_eval, mat2 + 1);
1658  if (m1 && m2 &&
1659  ((m1->lineart.mat_occlusion == 0 && m2->lineart.mat_occlusion != 0) ||
1660  (m2->lineart.mat_occlusion == 0 && m1->lineart.mat_occlusion != 0))) {
1661  if (ld->conf.use_contour) {
1662  edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
1663  }
1664  }
1665  if (ld->conf.use_material) {
1666  edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
1667  }
1668  }
1669  }
1670  else { /* only_contour */
1671  if (!edge_flag_result) { /* Other edge types inhibited */
1672  return;
1673  }
1674  }
1675 
1676  int real_edges[3];
1677  BKE_mesh_looptri_get_real_edges(me, &mlooptri[i / 3], real_edges);
1678 
1679  if (real_edges[i % 3] >= 0) {
1680  MEdge *medge = &me->medge[real_edges[i % 3]];
1681 
1682  if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) {
1683  edge_flag_result |= LRT_EDGE_FLAG_CREASE;
1684  }
1685 
1686  if (ld->conf.use_edge_marks && e_feat_data->use_freestyle_edge) {
1687  FreestyleEdge *fe;
1688  int index = e_feat_data->freestyle_edge_index;
1689  fe = &((FreestyleEdge *)me->edata.layers[index].data)[real_edges[i % 3]];
1690  if (fe->flag & FREESTYLE_EDGE_MARK) {
1691  edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK;
1692  }
1693  }
1694  }
1695 
1696  edge_nabr[i].flags = edge_flag_result;
1697 
1698  if (edge_flag_result) {
1699  /* Only allocate for feature edge (instead of all edges) to save memory.
1700  * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
1701  */
1702  reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ?
1703  lineart_edge_type_duplication_count(edge_flag_result) :
1704  1;
1705  }
1706 }
1707 
1708 typedef struct LooseEdgeData {
1714 
1716 {
1717  MEdge **new_arr = MEM_callocN(sizeof(MEdge *) * count, "loose edge array");
1718  if (loose_data->loose_array) {
1719  memcpy(new_arr, loose_data->loose_array, sizeof(MEdge *) * loose_data->loose_max);
1720  MEM_freeN(loose_data->loose_array);
1721  }
1722  loose_data->loose_max = count;
1723  loose_data->loose_array = new_arr;
1724 }
1725 
1726 static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData *to_be_joined)
1727 {
1728  if (!to_be_joined->loose_array) {
1729  return;
1730  }
1731  int new_count = loose_data->loose_count + to_be_joined->loose_count;
1732  if (new_count >= loose_data->loose_max) {
1733  lineart_loose_data_reallocate(loose_data, new_count);
1734  }
1735  memcpy(&loose_data->loose_array[loose_data->loose_count],
1736  to_be_joined->loose_array,
1737  sizeof(MEdge *) * to_be_joined->loose_count);
1738  loose_data->loose_count += to_be_joined->loose_count;
1739  MEM_freeN(to_be_joined->loose_array);
1740  to_be_joined->loose_array = NULL;
1741 }
1742 
1743 static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
1744 {
1745  if (loose_data->loose_count >= loose_data->loose_max) {
1746  int min_amount = MAX2(100, loose_data->loose_count * 2);
1747  lineart_loose_data_reallocate(loose_data, min_amount);
1748  }
1749  loose_data->loose_array[loose_data->loose_count] = e;
1750  loose_data->loose_count++;
1751 }
1752 
1753 static void lineart_identify_loose_edges(void *__restrict UNUSED(userdata),
1754  const int i,
1755  const TaskParallelTLS *__restrict tls)
1756 {
1757  LooseEdgeData *loose_data = (LooseEdgeData *)tls->userdata_chunk;
1758  Mesh *me = loose_data->me;
1759 
1760  if (me->medge[i].flag & ME_LOOSEEDGE) {
1761  lineart_add_loose_edge(loose_data, &me->medge[i]);
1762  }
1763 }
1764 
1765 static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata),
1766  void *__restrict chunk_join,
1767  void *__restrict chunk)
1768 {
1769  LooseEdgeData *final = (LooseEdgeData *)chunk_join;
1770  LooseEdgeData *loose_chunk = (LooseEdgeData *)chunk;
1771  lineart_join_loose_edge_arr(final, loose_chunk);
1772 }
1773 
1775 {
1776  if (pe->next >= pe->max || !pe->max) {
1777  if (!pe->max) {
1778  pe->max = 1000;
1779  }
1780 
1781  LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * pe->max * 2,
1782  "LineartPendingEdges array");
1783  if (LIKELY(pe->array)) {
1784  memcpy(new_array, pe->array, sizeof(LineartEdge *) * pe->max);
1785  MEM_freeN(pe->array);
1786  }
1787  pe->max *= 2;
1788  pe->array = new_array;
1789  }
1790  pe->array[pe->next] = e;
1791  pe->next++;
1792 }
1794 {
1796 }
1797 
1798 /* NOTE: For simplicity, this function doesn't actually do anything if you already have data in
1799  * #pe. */
1801 {
1802  if (pe->max || pe->array || count == 0) {
1803  return;
1804  }
1805 
1806  pe->max = count;
1807  LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * pe->max,
1808  "LineartPendingEdges array final");
1809  pe->array = new_array;
1810 }
1811 
1813 {
1814  /* In case of line art "occlusion only" or contour not enabled, it's possible for an object to
1815  * not produce any feature lines. */
1816  if (!obi->pending_edges.array) {
1817  return;
1818  }
1819  memcpy(&pe->array[pe->next],
1820  obi->pending_edges.array,
1821  sizeof(LineartEdge *) * obi->pending_edges.next);
1823  pe->next += obi->pending_edges.next;
1824 }
1825 
1827  LineartTriangleAdjacent *tri_adj,
1828  LineartEdge *e)
1829 {
1830  if (lineart_edge_match(tri, e, 0, 1)) {
1831  tri_adj->e[0] = e;
1832  }
1833  else if (lineart_edge_match(tri, e, 1, 2)) {
1834  tri_adj->e[1] = e;
1835  }
1836  else if (lineart_edge_match(tri, e, 2, 0)) {
1837  tri_adj->e[2] = e;
1838  }
1839 }
1840 
1841 typedef struct TriData {
1849 
1850 static void lineart_load_tri_task(void *__restrict userdata,
1851  const int i,
1852  const TaskParallelTLS *__restrict UNUSED(tls))
1853 {
1854  TriData *tri_task_data = (TriData *)userdata;
1855  Mesh *me = tri_task_data->ob_info->original_me;
1856  LineartObjectInfo *ob_info = tri_task_data->ob_info;
1857  const MLoopTri *mlooptri = &tri_task_data->mlooptri[i];
1858  LineartVert *vert_arr = tri_task_data->vert_arr;
1859  LineartTriangle *tri = tri_task_data->tri_arr;
1860 
1861  tri = (LineartTriangle *)(((uchar *)tri) + tri_task_data->lineart_triangle_size * i);
1862 
1863  int v1 = me->mloop[mlooptri->tri[0]].v;
1864  int v2 = me->mloop[mlooptri->tri[1]].v;
1865  int v3 = me->mloop[mlooptri->tri[2]].v;
1866 
1867  tri->v[0] = &vert_arr[v1];
1868  tri->v[1] = &vert_arr[v2];
1869  tri->v[2] = &vert_arr[v3];
1870 
1871  /* Material mask bits and occlusion effectiveness assignment. */
1873  me->mpoly[mlooptri->poly].mat_nr + 1);
1874  tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
1876  0);
1877  tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
1878  tri->intersection_priority = ((mat && (mat->lineart.flags &
1881  ob_info->intersection_priority);
1882  tri->flags |= (mat && (mat->blend_flag & MA_BL_CULL_BACKFACE)) ?
1884  0;
1885 
1887 
1888  tri->target_reference = (ob_info->obindex | (i & LRT_OBINDEX_LOWER));
1889 
1890  double gn[3];
1891  float no[3];
1892  normal_tri_v3(no, me->mvert[v1].co, me->mvert[v2].co, me->mvert[v3].co);
1893  copy_v3db_v3fl(gn, no);
1894  mul_v3_mat3_m4v3_db(tri->gn, ob_info->normal, gn);
1895  normalize_v3_db(tri->gn);
1896 
1897  if (ob_info->usage == OBJECT_LRT_INTERSECTION_ONLY) {
1899  }
1900  else if (ob_info->usage == OBJECT_LRT_FORCE_INTERSECTION) {
1902  }
1903  else if (ob_info->usage == OBJECT_LRT_NO_INTERSECTION ||
1904  ob_info->usage == OBJECT_LRT_OCCLUSION_ONLY) {
1906  }
1907 
1908  /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
1909  tri->intersecting_verts = (void *)&tri_task_data->tri_adj[i];
1910 }
1911 typedef struct EdgeNeighborData {
1917 
1918 static void lineart_edge_neighbor_init_task(void *__restrict userdata,
1919  const int i,
1920  const TaskParallelTLS *__restrict UNUSED(tls))
1921 {
1922  EdgeNeighborData *en_data = (EdgeNeighborData *)userdata;
1923  LineartAdjacentEdge *adj_e = &en_data->adj_e[i];
1924  MLoopTri *looptri = &en_data->mlooptri[i / 3];
1925  LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i];
1926  MLoop *mloop = en_data->mloop;
1927 
1928  adj_e->e = i;
1929  adj_e->v1 = mloop[looptri->tri[i % 3]].v;
1930  adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v;
1931  if (adj_e->v1 > adj_e->v2) {
1932  SWAP(uint32_t, adj_e->v1, adj_e->v2);
1933  }
1934  edge_nabr->e = -1;
1935 
1936  edge_nabr->v1 = adj_e->v1;
1937  edge_nabr->v2 = adj_e->v2;
1938  edge_nabr->flags = 0;
1939 }
1940 
1942 {
1943  /* Because the mesh is triangulated, so `me->totedge` should be reliable? */
1944  LineartAdjacentEdge *adj_e = MEM_mallocN(sizeof(LineartAdjacentEdge) * total_edges,
1945  "LineartAdjacentEdge arr");
1946  LineartEdgeNeighbor *edge_nabr = MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges,
1947  "LineartEdgeNeighbor arr");
1948 
1949  MLoopTri *mlooptri = me->runtime.looptris.array;
1950 
1951  TaskParallelSettings en_settings;
1953  /* Set the minimum amount of edges a thread has to process. */
1954  en_settings.min_iter_per_thread = 50000;
1955 
1956  EdgeNeighborData en_data;
1957  en_data.adj_e = adj_e;
1958  en_data.edge_nabr = edge_nabr;
1959  en_data.mlooptri = mlooptri;
1960  en_data.mloop = me->mloop;
1961 
1962  BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings);
1963 
1964  lineart_sort_adjacent_items(adj_e, total_edges);
1965 
1966  for (int i = 0; i < total_edges - 1; i++) {
1967  if (adj_e[i].v1 == adj_e[i + 1].v1 && adj_e[i].v2 == adj_e[i + 1].v2) {
1968  edge_nabr[adj_e[i].e].e = adj_e[i + 1].e;
1969  edge_nabr[adj_e[i + 1].e].e = adj_e[i].e;
1970  }
1971  }
1972 
1973  MEM_freeN(adj_e);
1974 
1975  return edge_nabr;
1976 }
1977 
1979  LineartData *la_data,
1980  ListBase *shadow_elns)
1981 {
1982  LineartElementLinkNode *elem_link_node;
1983  LineartVert *la_v_arr;
1984  LineartEdge *la_edge_arr;
1985  LineartEdgeSegment *la_seg_arr;
1986  LineartTriangle *la_tri_arr;
1987 
1988  Mesh *me = ob_info->original_me;
1989 
1990  if (!me->totedge) {
1991  return;
1992  }
1993 
1994  /* Triangulate. */
1995  const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
1996  const int tot_tri = BKE_mesh_runtime_looptri_len(me);
1997 
1998  /* Check if we should look for custom data tags like Freestyle edges or faces. */
1999  bool can_find_freestyle_edge = false;
2001  if (layer_index != -1) {
2002  can_find_freestyle_edge = true;
2003  }
2004 
2005  bool can_find_freestyle_face = false;
2007  if (layer_index != -1) {
2008  can_find_freestyle_face = true;
2009  }
2010 
2011  /* If we allow duplicated edges, one edge should get added multiple times if is has been
2012  * classified as more than one edge type. This is so we can create multiple different line type
2013  * chains containing the same edge. */
2014  la_v_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
2015  sizeof(LineartVert) * me->totvert);
2016  la_tri_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
2017  tot_tri * la_data->sizeof_triangle);
2018 
2019  Object *orig_ob = ob_info->original_ob;
2020 
2021  BLI_spin_lock(&la_data->lock_task);
2023  &la_data->geom.vertex_buffer_pointers,
2024  &la_data->render_data_pool,
2025  la_v_arr,
2026  sizeof(LineartElementLinkNode));
2027  BLI_spin_unlock(&la_data->lock_task);
2028 
2029  elem_link_node->obindex = ob_info->obindex;
2030  elem_link_node->element_count = me->totvert;
2031  elem_link_node->object_ref = orig_ob;
2032  ob_info->v_eln = elem_link_node;
2033 
2034  bool use_auto_smooth = false;
2035  float crease_angle = 0;
2036  if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
2037  crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold);
2038  }
2039  else if (ob_info->original_me->flag & ME_AUTOSMOOTH) {
2040  crease_angle = cosf(ob_info->original_me->smoothresh);
2041  use_auto_smooth = true;
2042  }
2043  else {
2044  crease_angle = la_data->conf.crease_threshold;
2045  }
2046 
2047  /* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
2048  * erroneous detection on creases. Future configuration should allow options. */
2049  if (orig_ob->type == OB_FONT) {
2050  elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY;
2051  }
2052 
2053  BLI_spin_lock(&la_data->lock_task);
2055  &la_data->geom.triangle_buffer_pointers,
2056  &la_data->render_data_pool,
2057  la_tri_arr,
2058  sizeof(LineartElementLinkNode));
2059  BLI_spin_unlock(&la_data->lock_task);
2060 
2061  int usage = ob_info->usage;
2062 
2063  elem_link_node->element_count = tot_tri;
2064  elem_link_node->object_ref = orig_ob;
2065  elem_link_node->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
2066 
2067  /* Note this memory is not from pool, will be deleted after culling. */
2068  LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri,
2069  "LineartTriangleAdjacent");
2070  /* Link is minimal so we use pool anyway. */
2071  BLI_spin_lock(&la_data->lock_task);
2073  &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj);
2074  BLI_spin_unlock(&la_data->lock_task);
2075 
2076  /* Convert all vertices to lineart verts. */
2077  TaskParallelSettings vert_settings;
2078  BLI_parallel_range_settings_defaults(&vert_settings);
2079  /* Set the minimum amount of verts a thread has to process. */
2080  vert_settings.min_iter_per_thread = 4000;
2081 
2082  VertData vert_data;
2083  vert_data.mvert = me->mvert;
2084  vert_data.v_arr = la_v_arr;
2085  vert_data.model_view = ob_info->model_view;
2086  vert_data.model_view_proj = ob_info->model_view_proj;
2087 
2089  0, me->totvert, &vert_data, lineart_mvert_transform_task, &vert_settings);
2090 
2091  /* Convert all mesh triangles into lineart triangles.
2092  * Also create an edge map to get connectivity between edges and triangles. */
2093  TaskParallelSettings tri_settings;
2094  BLI_parallel_range_settings_defaults(&tri_settings);
2095  /* Set the minimum amount of triangles a thread has to process. */
2096  tri_settings.min_iter_per_thread = 4000;
2097 
2098  TriData tri_data;
2099  tri_data.ob_info = ob_info;
2100  tri_data.mlooptri = mlooptri;
2101  tri_data.vert_arr = la_v_arr;
2102  tri_data.tri_arr = la_tri_arr;
2103  tri_data.lineart_triangle_size = la_data->sizeof_triangle;
2104  tri_data.tri_adj = tri_adj;
2105 
2106  uint32_t total_edges = tot_tri * 3;
2107 
2108  BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
2109 
2110  /* Check for contour lines in the mesh.
2111  * IE check if the triangle edges lies in area where the triangles go from front facing to back
2112  * facing.
2113  */
2114  EdgeFeatReduceData edge_reduce = {0};
2115  TaskParallelSettings edge_feat_settings;
2116  BLI_parallel_range_settings_defaults(&edge_feat_settings);
2117  /* Set the minimum amount of edges a thread has to process. */
2118  edge_feat_settings.min_iter_per_thread = 4000;
2119  edge_feat_settings.userdata_chunk = &edge_reduce;
2120  edge_feat_settings.userdata_chunk_size = sizeof(EdgeFeatReduceData);
2121  edge_feat_settings.func_reduce = feat_data_sum_reduce;
2122 
2123  EdgeFeatData edge_feat_data = {0};
2124  edge_feat_data.ld = la_data;
2125  edge_feat_data.me = me;
2126  edge_feat_data.ob_eval = ob_info->original_ob_eval;
2127  edge_feat_data.mlooptri = mlooptri;
2128  edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
2129  edge_feat_data.tri_array = la_tri_arr;
2130  edge_feat_data.v_array = la_v_arr;
2131  edge_feat_data.crease_threshold = crease_angle;
2132  edge_feat_data.use_auto_smooth = use_auto_smooth;
2133  edge_feat_data.use_freestyle_face = can_find_freestyle_face;
2134  edge_feat_data.use_freestyle_edge = can_find_freestyle_edge;
2135  if (edge_feat_data.use_freestyle_face) {
2138  }
2139  if (edge_feat_data.use_freestyle_edge) {
2142  }
2143 
2145  total_edges,
2146  &edge_feat_data,
2148  &edge_feat_settings);
2149 
2150  LooseEdgeData loose_data = {0};
2151  if (la_data->conf.use_loose) {
2152  /* Only identifying floating edges at this point because other edges has been taken care of
2153  * inside #lineart_identify_mlooptri_feature_edges function. */
2154  TaskParallelSettings edge_loose_settings;
2155  BLI_parallel_range_settings_defaults(&edge_loose_settings);
2156  edge_loose_settings.min_iter_per_thread = 4000;
2157  edge_loose_settings.func_reduce = loose_data_sum_reduce;
2158  edge_loose_settings.userdata_chunk = &loose_data;
2159  edge_loose_settings.userdata_chunk_size = sizeof(LooseEdgeData);
2160  loose_data.me = me;
2162  0, me->totedge, &loose_data, lineart_identify_loose_edges, &edge_loose_settings);
2163  }
2164 
2165  int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count;
2166 
2167  la_edge_arr = lineart_mem_acquire_thread(la_data->edge_data_pool,
2168  sizeof(LineartEdge) * allocate_la_e);
2169  la_seg_arr = lineart_mem_acquire_thread(la_data->edge_data_pool,
2170  sizeof(LineartEdgeSegment) * allocate_la_e);
2171  BLI_spin_lock(&la_data->lock_task);
2173  &la_data->geom.line_buffer_pointers,
2174  la_data->edge_data_pool,
2175  la_edge_arr,
2176  sizeof(LineartElementLinkNode));
2177  BLI_spin_unlock(&la_data->lock_task);
2178  elem_link_node->element_count = allocate_la_e;
2179  elem_link_node->object_ref = orig_ob;
2180  elem_link_node->obindex = ob_info->obindex;
2181 
2182  LineartElementLinkNode *shadow_eln = NULL;
2183  if (shadow_elns) {
2184  shadow_eln = lineart_find_matching_eln(shadow_elns, ob_info->obindex);
2185  }
2186 
2187  /* Start of the edge/seg arr */
2188  LineartEdge *la_edge;
2189  LineartEdgeSegment *la_seg;
2190  la_edge = la_edge_arr;
2191  la_seg = la_seg_arr;
2192 
2193  for (int i = 0; i < total_edges; i++) {
2194  LineartEdgeNeighbor *edge_nabr = &edge_feat_data.edge_nabr[i];
2195 
2196  if (i < edge_nabr->e) {
2197  continue;
2198  }
2199 
2200  /* Not a feature line, so we skip. */
2201  if (edge_nabr->flags == 0) {
2202  continue;
2203  }
2204 
2205  LineartEdge *edge_added = NULL;
2206 
2207  /* See eLineartEdgeFlag for details. */
2208  for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) {
2209  int use_type = LRT_MESH_EDGE_TYPES[flag_bit];
2210  if (!(use_type & edge_nabr->flags)) {
2211  continue;
2212  }
2213 
2214  la_edge->v1 = &la_v_arr[edge_nabr->v1];
2215  la_edge->v2 = &la_v_arr[edge_nabr->v2];
2216  int findex = i / 3;
2217  la_edge->t1 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
2218  if (!edge_added) {
2219  lineart_triangle_adjacent_assign(la_edge->t1, &tri_adj[findex], la_edge);
2220  }
2221  if (edge_nabr->e != -1) {
2222  findex = edge_nabr->e / 3;
2223  la_edge->t2 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
2224  if (!edge_added) {
2225  lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge);
2226  }
2227  }
2228  la_edge->flags = use_type;
2229  la_edge->object_ref = orig_ob;
2230  la_edge->edge_identifier = LRT_EDGE_IDENTIFIER(ob_info, la_edge);
2231  BLI_addtail(&la_edge->segments, la_seg);
2232 
2233  if (shadow_eln) {
2234  /* TODO(Yiming): It's gonna be faster to do this operation after second stage occlusion if
2235  * we only need visible segments to have shadow info, however that way we lose information
2236  * on "shadow behind transparency window" type of region. */
2237  LineartEdge *shadow_e = lineart_find_matching_edge(shadow_eln, la_edge->edge_identifier);
2238  if (shadow_e) {
2239  lineart_register_shadow_cuts(la_data, la_edge, shadow_e);
2240  }
2241  }
2242 
2243  if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
2245  lineart_add_edge_to_array_thread(ob_info, la_edge);
2246  }
2247 
2248  if (edge_added) {
2250  }
2251 
2252  edge_added = la_edge;
2253 
2254  la_edge++;
2255  la_seg++;
2256 
2257  if (!la_data->conf.allow_duplicated_types) {
2258  break;
2259  }
2260  }
2261  }
2262 
2263  if (loose_data.loose_array) {
2264  for (int i = 0; i < loose_data.loose_count; i++) {
2265  la_edge->v1 = &la_v_arr[loose_data.loose_array[i]->v1];
2266  la_edge->v2 = &la_v_arr[loose_data.loose_array[i]->v2];
2267  la_edge->flags = LRT_EDGE_FLAG_LOOSE;
2268  la_edge->object_ref = orig_ob;
2269  la_edge->edge_identifier = LRT_EDGE_IDENTIFIER(ob_info, la_edge);
2270  BLI_addtail(&la_edge->segments, la_seg);
2271  if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
2273  lineart_add_edge_to_array_thread(ob_info, la_edge);
2274  if (shadow_eln) {
2275  LineartEdge *shadow_e = lineart_find_matching_edge(shadow_eln, la_edge->edge_identifier);
2276  if (shadow_e) {
2277  lineart_register_shadow_cuts(la_data, la_edge, shadow_e);
2278  }
2279  }
2280  }
2281  la_edge++;
2282  la_seg++;
2283  }
2284  MEM_freeN(loose_data.loose_array);
2285  }
2286 
2287  MEM_freeN(edge_feat_data.edge_nabr);
2288 
2289  if (ob_info->free_use_mesh) {
2290  BKE_id_free(NULL, me);
2291  }
2292 }
2293 
2296 {
2297  for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) {
2298  lineart_geometry_object_load(obi, olti->ld, olti->shadow_elns);
2299  }
2300 }
2301 
2303 {
2304  LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
2305  uchar result = lineart_intersection_mask_check(cc->collection, ob);
2306  if (result) {
2307  return result;
2308  }
2309  }
2310 
2311  if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
2312  if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
2313  return c->lineart_intersection_mask;
2314  }
2315  }
2316 
2317  return 0;
2318 }
2319 
2321 {
2323  return ob->lineart.intersection_priority;
2324  }
2325 
2326  LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
2327  uchar result = lineart_intersection_priority_check(cc->collection, ob);
2328  if (result) {
2329  return result;
2330  }
2331  }
2332  if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
2333  if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_PRIORITY) {
2334  return c->lineart_intersection_priority;
2335  }
2336  }
2337  return 0;
2338 }
2339 
2344 static int lineart_usage_check(Collection *c, Object *ob, bool is_render)
2345 {
2346 
2347  if (!c) {
2348  return OBJECT_LRT_INHERIT;
2349  }
2350 
2351  int object_has_special_usage = (ob->lineart.usage != OBJECT_LRT_INHERIT);
2352 
2353  if (object_has_special_usage) {
2354  return ob->lineart.usage;
2355  }
2356 
2357  if (c->gobject.first) {
2358  if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
2359  if ((is_render && (c->flag & COLLECTION_HIDE_RENDER)) ||
2360  ((!is_render) && (c->flag & COLLECTION_HIDE_VIEWPORT))) {
2361  return OBJECT_LRT_EXCLUDE;
2362  }
2363  if (ob->lineart.usage == OBJECT_LRT_INHERIT) {
2364  switch (c->lineart_usage) {
2368  return OBJECT_LRT_EXCLUDE;
2375  }
2376  return OBJECT_LRT_INHERIT;
2377  }
2378  return ob->lineart.usage;
2379  }
2380  }
2381 
2382  LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
2383  int result = lineart_usage_check(cc->collection, ob, is_render);
2384  if (result > OBJECT_LRT_INHERIT) {
2385  return result;
2386  }
2387  }
2388 
2389  return OBJECT_LRT_INHERIT;
2390 }
2391 
2393  LineartObjectInfo *obi,
2394  int thread_count,
2395  int this_face_count)
2396 {
2397  LineartObjectLoadTaskInfo *use_olti = olti_list;
2398  uint64_t min_face = use_olti->total_faces;
2399  for (int i = 0; i < thread_count; i++) {
2400  if (olti_list[i].total_faces < min_face) {
2401  min_face = olti_list[i].total_faces;
2402  use_olti = &olti_list[i];
2403  }
2404  }
2405 
2406  use_olti->total_faces += this_face_count;
2407  obi->next = use_olti->pending;
2408  use_olti->pending = obi;
2409 }
2410 
2411 static bool lineart_geometry_check_visible(double model_view_proj[4][4],
2412  double shift_x,
2413  double shift_y,
2414  Mesh *use_mesh)
2415 {
2416  if (!use_mesh) {
2417  return false;
2418  }
2419  float mesh_min[3], mesh_max[3];
2420  INIT_MINMAX(mesh_min, mesh_max);
2421  BKE_mesh_minmax(use_mesh, mesh_min, mesh_max);
2422  BoundBox bb = {0};
2423  BKE_boundbox_init_from_minmax(&bb, mesh_min, mesh_max);
2424 
2425  double co[8][4];
2426  double tmp[3];
2427  for (int i = 0; i < 8; i++) {
2428  copy_v3db_v3fl(co[i], bb.vec[i]);
2429  copy_v3_v3_db(tmp, co[i]);
2430  mul_v4_m4v3_db(co[i], model_view_proj, tmp);
2431  co[i][0] -= shift_x * 2 * co[i][3];
2432  co[i][1] -= shift_y * 2 * co[i][3];
2433  }
2434 
2435  bool cond[6] = {true, true, true, true, true, true};
2436  /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if
2437  * all verts falls to the same side of the clip space border, we know it's outside view. */
2438  for (int i = 0; i < 8; i++) {
2439  cond[0] &= (co[i][0] < -co[i][3]);
2440  cond[1] &= (co[i][0] > co[i][3]);
2441  cond[2] &= (co[i][1] < -co[i][3]);
2442  cond[3] &= (co[i][1] > co[i][3]);
2443  cond[4] &= (co[i][2] < -co[i][3]);
2444  cond[5] &= (co[i][2] > co[i][3]);
2445  }
2446  for (int i = 0; i < 6; i++) {
2447  if (cond[i]) {
2448  return false;
2449  }
2450  }
2451  return true;
2452 }
2453 
2456  Scene *scene,
2457  Object *ob,
2458  Object *ref_ob,
2459  float use_mat[4][4],
2460  bool is_render,
2462  int thread_count,
2463  int obindex)
2464 {
2466  obi->usage = lineart_usage_check(scene->master_collection, ob, is_render);
2469  Mesh *use_mesh;
2470 
2471  if (obi->usage == OBJECT_LRT_EXCLUDE) {
2472  return;
2473  }
2474 
2475  obi->obindex = obindex << LRT_OBINDEX_SHIFT;
2476 
2477  /* Prepare the matrix used for transforming this specific object (instance). This has to be
2478  * done before mesh boundbox check because the function needs that. */
2480  mul_m4db_m4db_m4fl_uniq(obi->model_view, ld->conf.view, use_mat);
2481 
2483  return;
2484  }
2485  if (ob->type == OB_MESH) {
2486  use_mesh = BKE_object_get_evaluated_mesh(ob);
2487  if ((!use_mesh) || use_mesh->edit_mesh) {
2488  /* If the object is being edited, then the mesh is not evaluated fully into the final
2489  * result, do not load them. This could be caused by incorrect evaluation order due to
2490  * the way line art uses depsgraph.See T102612 for explaination of this workaround. */
2491  return;
2492  }
2493  }
2494  else {
2495  use_mesh = BKE_mesh_new_from_object(depsgraph, ob, true, true);
2496  }
2497 
2498  /* In case we still can not get any mesh geometry data from the object, same as above. */
2499  if (!use_mesh) {
2500  return;
2501  }
2502 
2504  obi->model_view_proj, ld->conf.shift_x, ld->conf.shift_y, use_mesh)) {
2505  return;
2506  }
2507 
2508  if (ob->type != OB_MESH) {
2509  obi->free_use_mesh = true;
2510  }
2511 
2512  /* Make normal matrix. */
2513  float imat[4][4];
2514  invert_m4_m4(imat, use_mat);
2515  transpose_m4(imat);
2516  copy_m4d_m4(obi->normal, imat);
2517 
2518  obi->original_me = use_mesh;
2519  obi->original_ob = (ref_ob->id.orig_id ? (Object *)ref_ob->id.orig_id : (Object *)ref_ob);
2521  lineart_geometry_load_assign_thread(olti, obi, thread_count, use_mesh->totpoly);
2522 }
2523 
2525  Scene *scene,
2526  Object *camera /* Still use camera arg for convenience. */,
2527  LineartData *ld,
2528  bool allow_duplicates,
2529  bool do_shadow_casting,
2530  ListBase *shadow_elns)
2531 {
2532  double proj[4][4], view[4][4], result[4][4];
2533  float inv[4][4];
2534 
2535  if (!do_shadow_casting) {
2536  Camera *cam = camera->data;
2537  float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
2538  int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h);
2539  double asp = ((double)ld->w / (double)ld->h);
2540  if (cam->type == CAM_PERSP) {
2541  if (fit == CAMERA_SENSOR_FIT_VERT && asp > 1) {
2542  sensor *= asp;
2543  }
2544  if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) {
2545  sensor /= asp;
2546  }
2547  const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor);
2548  lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
2549  }
2550  else if (cam->type == CAM_ORTHO) {
2551  const double w = cam->ortho_scale / 2;
2552  lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
2553  }
2554 
2555  invert_m4_m4(inv, ld->conf.cam_obmat);
2556  mul_m4db_m4db_m4fl_uniq(result, proj, inv);
2557  copy_m4_m4_db(proj, result);
2558  copy_m4_m4_db(ld->conf.view_projection, proj);
2559 
2560  unit_m4_db(view);
2561  copy_m4_m4_db(ld->conf.view, view);
2562  }
2563 
2566 
2567  double t_start;
2568  if (G.debug_value == 4000) {
2569  t_start = PIL_check_seconds_timer();
2570  }
2571 
2572  int thread_count = ld->thread_count;
2573  int bound_box_discard_count = 0;
2574  int obindex = 0;
2575 
2576  /* This memory is in render buffer memory pool. So we don't need to free those after loading. */
2578  &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
2579 
2580  eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
2581  bool is_render = eval_mode == DAG_EVAL_RENDER;
2582 
2585 
2586  /* Instance duplicated & particles. */
2587  if (allow_duplicates) {
2588  flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
2589  }
2590 
2591  /* XXX(@Yiming): Temporary solution, this iterator is technically unsafe to use *during*
2592  * depsgraph evaluation, see D14997 for detailed explanations. */
2593  DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
2594 
2595  obindex++;
2596 
2597  Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
2598 
2599  if (!eval_ob) {
2600  continue;
2601  }
2602 
2603  /* DEG_OBJECT_ITER_BEGIN will include the instanced mesh of these curve object types, so don't
2604  * load them twice. */
2605  if (allow_duplicates && ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
2606  continue;
2607  }
2608 
2609  if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) {
2611  depsgraph,
2612  scene,
2613  eval_ob,
2614  eval_ob,
2615  eval_ob->obmat,
2616  is_render,
2617  olti,
2618  thread_count,
2619  obindex);
2620  }
2621  }
2623 
2625 
2626  if (G.debug_value == 4000) {
2627  printf("thread count: %d\n", thread_count);
2628  }
2629  for (int i = 0; i < thread_count; i++) {
2630  olti[i].ld = ld;
2631  olti[i].shadow_elns = shadow_elns;
2632  olti[i].thread_id = i;
2634  }
2636  BLI_task_pool_free(tp);
2637 
2638  /* The step below is to serialize vertex index in the whole scene, so
2639  * lineart_triangle_share_edge() can work properly from the lack of triangle adjacent info. */
2640  int global_i = 0;
2641 
2642  int edge_count = 0;
2643  for (int i = 0; i < thread_count; i++) {
2644  for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
2645  if (!obi->v_eln) {
2646  continue;
2647  }
2648  edge_count += obi->pending_edges.next;
2649  }
2650  }
2652 
2653  for (int i = 0; i < thread_count; i++) {
2654  for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
2655  if (!obi->v_eln) {
2656  continue;
2657  }
2658  LineartVert *v = (LineartVert *)obi->v_eln->pointer;
2659  int v_count = obi->v_eln->element_count;
2660  obi->v_eln->global_index_offset = global_i;
2661  for (int vi = 0; vi < v_count; vi++) {
2662  v[vi].index += global_i;
2663  }
2664  /* Register a global index increment. See #lineart_triangle_share_edge() and
2665  * #lineart_main_load_geometries() for detailed. It's okay that global_vindex might
2666  * eventually overflow, in such large scene it's virtually impossible for two vertex of the
2667  * same numeric index to come close together. */
2668  obi->global_i_offset = global_i;
2669  global_i += v_count;
2671  }
2672  }
2673 
2674  if (G.debug_value == 4000) {
2675  double t_elapsed = PIL_check_seconds_timer() - t_start;
2676  printf("Line art loading time: %lf\n", t_elapsed);
2677  printf("Discarded %d object from bound box check\n", bound_box_discard_count);
2678  }
2679 }
2680 
2686  const LineartVert *vt,
2687  LineartVert **l,
2688  LineartVert **r)
2689 {
2690  if (tri->v[0] == vt) {
2691  *l = tri->v[1];
2692  *r = tri->v[2];
2693  return true;
2694  }
2695  if (tri->v[1] == vt) {
2696  *l = tri->v[2];
2697  *r = tri->v[0];
2698  return true;
2699  }
2700  if (tri->v[2] == vt) {
2701  *l = tri->v[0];
2702  *r = tri->v[1];
2703  return true;
2704  }
2705  return false;
2706 }
2707 
2709  const LineartEdge *e,
2710  bool allow_overlapping_edges)
2711 {
2712  const LineartEdge *use_e = e;
2713  if (e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
2714  if (((e->target_reference & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference) ||
2715  (((e->target_reference >> 32) & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference)) {
2716  return true;
2717  }
2718  }
2719  else {
2720  /* Normally we just determine from identifiers of adjacent triangles. */
2721  if ((use_e->t1 && use_e->t1->target_reference == tri->target_reference) ||
2722  (use_e->t2 && use_e->t2->target_reference == tri->target_reference)) {
2723  return true;
2724  }
2725  }
2726 
2727  /* If allows overlapping, then we compare the vertex coordinates one by one to determine if one
2728  * edge is from specific triangle. This is slower but can handle edge split cases very well. */
2729  if (allow_overlapping_edges) {
2730 #define LRT_TRI_SAME_POINT(tri, i, pt) \
2731  ((LRT_DOUBLE_CLOSE_ENOUGH(tri->v[i]->gloc[0], pt->gloc[0]) && \
2732  LRT_DOUBLE_CLOSE_ENOUGH(tri->v[i]->gloc[1], pt->gloc[1]) && \
2733  LRT_DOUBLE_CLOSE_ENOUGH(tri->v[i]->gloc[2], pt->gloc[2])) || \
2734  (LRT_DOUBLE_CLOSE_ENOUGH(tri->v[i]->gloc[0], pt->gloc[0]) && \
2735  LRT_DOUBLE_CLOSE_ENOUGH(tri->v[i]->gloc[1], pt->gloc[1]) && \
2736  LRT_DOUBLE_CLOSE_ENOUGH(tri->v[i]->gloc[2], pt->gloc[2])))
2737  if ((LRT_TRI_SAME_POINT(tri, 0, e->v1) || LRT_TRI_SAME_POINT(tri, 1, e->v1) ||
2738  LRT_TRI_SAME_POINT(tri, 2, e->v1)) &&
2739  (LRT_TRI_SAME_POINT(tri, 0, e->v2) || LRT_TRI_SAME_POINT(tri, 1, e->v2) ||
2740  LRT_TRI_SAME_POINT(tri, 2, e->v2))) {
2741  return true;
2742  }
2743 #undef LRT_TRI_SAME_POINT
2744  }
2745  return false;
2746 }
2747 
2748 /* Sorting three intersection points from min to max,
2749  * the order for each intersection is set in `lst[0]` to `lst[2]`. */
2750 #define INTERSECT_SORT_MIN_TO_MAX_3(ia, ib, ic, lst) \
2751  { \
2752  lst[0] = LRT_MIN3_INDEX(ia, ib, ic); \
2753  lst[1] = (((ia <= ib && ib <= ic) || (ic <= ib && ib <= ia)) ? \
2754  1 : \
2755  (((ic <= ia && ia <= ib) || (ib < ia && ia <= ic)) ? 0 : 2)); \
2756  lst[2] = LRT_MAX3_INDEX(ia, ib, ic); \
2757  }
2758 
2759 /* `ia ib ic` are ordered. */
2760 #define INTERSECT_JUST_GREATER(is, order, num, index) \
2761  { \
2762  index = (num < is[order[0]] ? \
2763  order[0] : \
2764  (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : -1))); \
2765  }
2766 
2767 /* `ia ib ic` are ordered. */
2768 #define INTERSECT_JUST_SMALLER(is, order, num, index) \
2769  { \
2770  index = (num > is[order[2]] ? \
2771  order[2] : \
2772  (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \
2773  }
2774 
2775 #define LRT_ISEC(index) (index == 0 ? isec_e1 : (index == 1 ? isec_e2 : isec_e3))
2776 #define LRT_PARALLEL(index) (index == 0 ? para_e1 : (index == 1 ? para_e2 : para_e3))
2777 
2801  const LineartEdge *e,
2802  const double *override_camera_loc,
2803  const bool override_cam_is_persp,
2804  const bool allow_overlapping_edges,
2805  const double m_view_projection[4][4],
2806  const double camera_dir[3],
2807  const float cam_shift_x,
2808  const float cam_shift_y,
2809  double *from,
2810  double *to)
2811 {
2812  double cross_ratios[3] = {0};
2813  int cross_order[3];
2814  int cross_v1 = -1, cross_v2 = -1;
2815  /* If the edge intersects with the triangle edges (including extensions). */
2816  int isec_e1, isec_e2, isec_e3;
2817  /* If edge is parallel to one of the edges in the triangle. */
2818  bool para_e1, para_e2, para_e3;
2819  enum LineartPointTri state_v1 = LRT_OUTSIDE_TRIANGLE, state_v2 = LRT_OUTSIDE_TRIANGLE;
2820 
2821  double dir_v1[3];
2822  double dir_v2[3];
2823  double view_vector[4];
2824  double dir_cam[3];
2825  double dot_v1, dot_v2, dot_v1a, dot_v2a;
2826  double dot_f;
2827  double gloc[4], trans[4];
2828  double cut = -1;
2829 
2830  double *LFBC = e->v1->fbcoord, *RFBC = e->v2->fbcoord, *FBC0 = tri->v[0]->fbcoord,
2831  *FBC1 = tri->v[1]->fbcoord, *FBC2 = tri->v[2]->fbcoord;
2832 
2833  /* Overlapping not possible, return early. */
2834  if ((MAX3(FBC0[0], FBC1[0], FBC2[0]) < MIN2(LFBC[0], RFBC[0])) ||
2835  (MIN3(FBC0[0], FBC1[0], FBC2[0]) > MAX2(LFBC[0], RFBC[0])) ||
2836  (MAX3(FBC0[1], FBC1[1], FBC2[1]) < MIN2(LFBC[1], RFBC[1])) ||
2837  (MIN3(FBC0[1], FBC1[1], FBC2[1]) > MAX2(LFBC[1], RFBC[1])) ||
2838  (MIN3(FBC0[3], FBC1[3], FBC2[3]) > MAX2(LFBC[3], RFBC[3]))) {
2839  return false;
2840  }
2841 
2842  /* If the line is one of the edge in the triangle, then it's not occluded. */
2843  if (lineart_edge_from_triangle(tri, e, allow_overlapping_edges)) {
2844  return false;
2845  }
2846 
2847  /* Check if the line visually crosses one of the edge in the triangle. */
2848  isec_e1 = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &cross_ratios[0], &para_e1);
2849  isec_e2 = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &cross_ratios[1], &para_e2);
2850  isec_e3 = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &cross_ratios[2], &para_e3);
2851 
2852  /* Sort the intersection distance. */
2853  INTERSECT_SORT_MIN_TO_MAX_3(cross_ratios[0], cross_ratios[1], cross_ratios[2], cross_order);
2854 
2855  sub_v3_v3v3_db(dir_v1, e->v1->gloc, tri->v[0]->gloc);
2856  sub_v3_v3v3_db(dir_v2, e->v2->gloc, tri->v[0]->gloc);
2857 
2858  copy_v3_v3_db(dir_cam, camera_dir);
2859  copy_v3_v3_db(view_vector, override_camera_loc);
2860  if (override_cam_is_persp) {
2861  sub_v3_v3v3_db(dir_cam, view_vector, tri->v[0]->gloc);
2862  }
2863 
2864  dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
2865  dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
2866  dot_f = dot_v3v3_db(dir_cam, tri->gn);
2867 
2868  if ((e->flags & LRT_EDGE_FLAG_PROJECTED_SHADOW) &&
2869  (e->target_reference == tri->target_reference)) {
2870  if (((dot_f > 0) && (e->flags & LRT_EDGE_FLAG_SHADOW_FACING_LIGHT)) ||
2871  ((dot_f < 0) && (!(e->flags & LRT_EDGE_FLAG_SHADOW_FACING_LIGHT)))) {
2872  *from = 0.0f;
2873  *to = 1.0f;
2874  return true;
2875  }
2876 
2877  return false;
2878  }
2879 
2880  /* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_
2881  * faces in perspective mode would get erroneously caught in this condition where they really
2882  * are legit faces that would produce occlusion, but haven't encountered those yet in my test
2883  * files.
2884  */
2885  if (fabs(dot_f) < FLT_EPSILON) {
2886  return false;
2887  }
2888 
2889  /* Whether two end points are inside/on_the_edge/outside of the triangle. */
2890  state_v1 = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
2891  state_v2 = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
2892 
2893  /* If the edge doesn't visually cross any edge of the triangle... */
2894  if (!isec_e1 && !isec_e2 && !isec_e3) {
2895  /* And if both end point from the edge is outside of the triangle... */
2896  if ((!state_v1) && (!state_v2)) {
2897  return 0; /* We don't have any occlusion. */
2898  }
2899  }
2900 
2901  /* Determine the cut position. */
2902 
2903  dot_v1a = fabs(dot_v1);
2904  if (dot_v1a < DBL_EPSILON) {
2905  dot_v1a = 0;
2906  dot_v1 = 0;
2907  }
2908  dot_v2a = fabs(dot_v2);
2909  if (dot_v2a < DBL_EPSILON) {
2910  dot_v2a = 0;
2911  dot_v2 = 0;
2912  }
2913  if (dot_v1 - dot_v2 == 0) {
2914  cut = 100000;
2915  }
2916  else if (dot_v1 * dot_v2 <= 0) {
2917  cut = dot_v1a / fabs(dot_v1 - dot_v2);
2918  }
2919  else {
2920  cut = fabs(dot_v2 + dot_v1) / fabs(dot_v1 - dot_v2);
2921  cut = dot_v2a > dot_v1a ? 1 - cut : cut;
2922  }
2923 
2924  /* Transform the cut from geometry space to image space. */
2925  if (override_cam_is_persp) {
2926  interp_v3_v3v3_db(gloc, e->v1->gloc, e->v2->gloc, cut);
2927  mul_v4_m4v3_db(trans, m_view_projection, gloc);
2928  mul_v3db_db(trans, (1 / trans[3]));
2929  trans[0] -= cam_shift_x * 2;
2930  trans[1] -= cam_shift_y * 2;
2931  /* To accommodate `k=0` and `k=inf` (vertical) lines. here the cut is in image space. */
2932  if (fabs(e->v1->fbcoord[0] - e->v2->fbcoord[0]) >
2933  fabs(e->v1->fbcoord[1] - e->v2->fbcoord[1])) {
2934  cut = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], trans[0]);
2935  }
2936  else {
2937  cut = ratiod(e->v1->fbcoord[1], e->v2->fbcoord[1], trans[1]);
2938  }
2939  }
2940 
2941 #define LRT_GUARD_NOT_FOUND \
2942  if (cross_v1 < 0 || cross_v2 < 0) { \
2943  return false; \
2944  }
2945 
2946  /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment
2947  * indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
2948  * tolerance. */
2949 
2950  if (state_v1 == LRT_INSIDE_TRIANGLE) {
2951  /* Left side is in the triangle. */
2952  if (state_v2 == LRT_INSIDE_TRIANGLE) {
2953  /* | l---r | */
2954  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
2955  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
2956  }
2957  else if (state_v2 == LRT_ON_TRIANGLE) {
2958  /* | l------r| */
2959  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
2960  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
2961  }
2962  else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
2963  /* | l-------|------r */
2964  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
2965  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 0, cross_v2);
2966  }
2967  }
2968  else if (state_v1 == LRT_ON_TRIANGLE) {
2969  /* Left side is on some edge of the triangle. */
2970  if (state_v2 == LRT_INSIDE_TRIANGLE) {
2971  /* |l------r | */
2972  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
2973  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
2974  }
2975  else if (state_v2 == LRT_ON_TRIANGLE) {
2976  /* |l---------r| */
2977  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
2978  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
2979  }
2980  else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
2981  /* |l----------|-------r (crossing the triangle) [OR]
2982  * r---------|l | (not crossing the triangle) */
2983  INTERSECT_JUST_GREATER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
2984  if (cross_v2 >= 0 && LRT_ISEC(cross_v2) && cross_ratios[cross_v2] > (DBL_TRIANGLE_LIM)) {
2985  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
2986  }
2987  else {
2988  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
2989  if (cross_v2 > 0) {
2990  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, cross_ratios[cross_v2], cross_v1);
2991  }
2992  }
2994  /* We could have the edge being completely parallel to the triangle where there isn't a
2995  * viable occlusion result. */
2996  if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
2997  (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
2998  return false;
2999  }
3000  }
3001  }
3002  else if (state_v1 == LRT_OUTSIDE_TRIANGLE) {
3003  /* Left side is outside of the triangle. */
3004  if (state_v2 == LRT_INSIDE_TRIANGLE) {
3005  /* l---|---r | */
3006  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
3007  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
3008  }
3009  else if (state_v2 == LRT_ON_TRIANGLE) {
3010  /* |r----------|-------l (crossing the triangle) [OR]
3011  * l---------|r | (not crossing the triangle) */
3012  INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
3013  if (cross_v1 >= 0 && LRT_ISEC(cross_v1) && cross_ratios[cross_v1] < (1 - DBL_TRIANGLE_LIM)) {
3014  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
3015  }
3016  else {
3017  INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
3018  if (cross_v1 > 0) {
3019  INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
3020  }
3021  }
3023  /* The same logic applies as above case. */
3024  if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
3025  (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
3026  return false;
3027  }
3028  }
3029  else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
3030  /* l---|----|----r (crossing the triangle) [OR]
3031  * l----r | | (not crossing the triangle) */
3032  INTERSECT_JUST_GREATER(cross_ratios, cross_order, -DBL_TRIANGLE_LIM, cross_v1);
3033  if (cross_v1 >= 0 && LRT_ISEC(cross_v1)) {
3034  INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
3035  }
3036  else {
3037  if (cross_v1 >= 0) {
3038  INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v1);
3039  if (cross_v1 >= 0) {
3040  INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
3041  }
3042  }
3043  }
3044  }
3045  }
3046 
3048 
3049  double dot_1f = dot_v1 * dot_f, dot_2f = dot_v2 * dot_f;
3050 
3051  /* Determine the start and end point of image space cut on a line. */
3052  if (dot_1f <= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
3053  *from = MAX2(0, cross_ratios[cross_v1]);
3054  *to = MIN2(1, cross_ratios[cross_v2]);
3055  if (*from >= *to) {
3056  return false;
3057  }
3058  return true;
3059  }
3060  if (dot_1f >= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
3061  *from = MAX2(cut, cross_ratios[cross_v1]);
3062  *to = MIN2(1, cross_ratios[cross_v2]);
3063  if (*from >= *to) {
3064  return false;
3065  }
3066  return true;
3067  }
3068  if (dot_1f <= 0 && dot_2f >= 0 && (dot_v1 || dot_v2)) {
3069  *from = MAX2(0, cross_ratios[cross_v1]);
3070  *to = MIN2(cut, cross_ratios[cross_v2]);
3071  if (*from >= *to) {
3072  return false;
3073  }
3074  return true;
3075  }
3076 
3077  /* Unlikely, but here's the default failed value if anything fall through. */
3078  return false;
3079 }
3080 
3081 #undef INTERSECT_SORT_MIN_TO_MAX_3
3082 #undef INTERSECT_JUST_GREATER
3083 #undef INTERSECT_JUST_SMALLER
3084 #undef LRT_ISEC
3085 #undef LRT_PARALLEL
3086 
3092 {
3093  if (l->v[0]->index == r->v[0]->index) {
3094  if (l->v[1]->index == r->v[1]->index || l->v[1]->index == r->v[2]->index ||
3095  l->v[2]->index == r->v[2]->index || l->v[2]->index == r->v[1]->index) {
3096  return true;
3097  }
3098  }
3099  if (l->v[0]->index == r->v[1]->index) {
3100  if (l->v[1]->index == r->v[0]->index || l->v[1]->index == r->v[2]->index ||
3101  l->v[2]->index == r->v[2]->index || l->v[2]->index == r->v[0]->index) {
3102  return true;
3103  }
3104  }
3105  if (l->v[0]->index == r->v[2]->index) {
3106  if (l->v[1]->index == r->v[1]->index || l->v[1]->index == r->v[0]->index ||
3107  l->v[2]->index == r->v[0]->index || l->v[2]->index == r->v[1]->index) {
3108  return true;
3109  }
3110  }
3111  if (l->v[1]->index == r->v[0]->index) {
3112  if (l->v[2]->index == r->v[1]->index || l->v[2]->index == r->v[2]->index ||
3113  l->v[0]->index == r->v[2]->index || l->v[0]->index == r->v[1]->index) {
3114  return true;
3115  }
3116  }
3117  if (l->v[1]->index == r->v[1]->index) {
3118  if (l->v[2]->index == r->v[0]->index || l->v[2]->index == r->v[2]->index ||
3119  l->v[0]->index == r->v[2]->index || l->v[0]->index == r->v[0]->index) {
3120  return true;
3121  }
3122  }
3123  if (l->v[1]->index == r->v[2]->index) {
3124  if (l->v[2]->index == r->v[1]->index || l->v[2]->index == r->v[0]->index ||
3125  l->v[0]->index == r->v[0]->index || l->v[0]->index == r->v[1]->index) {
3126  return true;
3127  }
3128  }
3129 
3130  /* Otherwise not possible. */
3131  return false;
3132 }
3133 
3135  const LineartTriangle *r)
3136 {
3137  if (l->v[0] == r->v[0]) {
3138  return r->v[0];
3139  }
3140  if (l->v[0] == r->v[1]) {
3141  return r->v[1];
3142  }
3143  if (l->v[0] == r->v[2]) {
3144  return r->v[2];
3145  }
3146  if (l->v[1] == r->v[0]) {
3147  return r->v[0];
3148  }
3149  if (l->v[1] == r->v[1]) {
3150  return r->v[1];
3151  }
3152  if (l->v[1] == r->v[2]) {
3153  return r->v[2];
3154  }
3155  if (l->v[2] == r->v[0]) {
3156  return r->v[0];
3157  }
3158  if (l->v[2] == r->v[1]) {
3159  return r->v[1];
3160  }
3161  if (l->v[2] == r->v[2]) {
3162  return r->v[2];
3163  }
3164  return NULL;
3165 }
3166 
3168  LineartVert *v1, LineartVert *v2, LineartTriangle *tri, const double *last, double *rv)
3169 {
3170  /* Direction vectors for the edge verts. We will check if the verts are on the same side of the
3171  * triangle or not. */
3172  double dir_v1[3], dir_v2[3];
3173  double dot_v1, dot_v2;
3174  double gloc[3];
3175 
3176  sub_v3_v3v3_db(dir_v1, v1->gloc, tri->v[0]->gloc);
3177  sub_v3_v3v3_db(dir_v2, v2->gloc, tri->v[0]->gloc);
3178 
3179  dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
3180  dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
3181 
3182  if (dot_v1 * dot_v2 > 0 || (!dot_v1 && !dot_v2)) {
3183  return false;
3184  }
3185 
3186  dot_v1 = fabs(dot_v1);
3187  dot_v2 = fabs(dot_v2);
3188 
3189  interp_v3_v3v3_db(gloc, v1->gloc, v2->gloc, dot_v1 / (dot_v1 + dot_v2));
3190 
3191  /* Due to precision issue, we might end up with the same point as the one we already detected. */
3192  if (last && LRT_DOUBLE_CLOSE_ENOUGH(last[0], gloc[0]) &&
3193  LRT_DOUBLE_CLOSE_ENOUGH(last[1], gloc[1]) && LRT_DOUBLE_CLOSE_ENOUGH(last[2], gloc[2])) {
3194  return false;
3195  }
3196 
3198  gloc, tri->v[0]->gloc, tri->v[1]->gloc, tri->v[2]->gloc))) {
3199  return false;
3200  }
3201 
3202  copy_v3_v3_db(rv, gloc);
3203 
3204  return true;
3205 }
3206 
3208  LineartTriangle *t2,
3209  double *v1,
3210  double *v2)
3211 {
3212  double *next = v1, *last = NULL;
3213  LineartVert *sv1, *sv2;
3214 
3215  LineartVert *share = lineart_triangle_share_point(t2, tri);
3216 
3217  if (share) {
3218  /* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc`
3219  * against `acd` or `cd` against `abc`. */
3220 
3221  lineart_triangle_get_other_verts(tri, share, &sv1, &sv2);
3222 
3223  copy_v3_v3_db(v1, share->gloc);
3224 
3225  if (!lineart_triangle_2v_intersection_math(sv1, sv2, t2, 0, v2)) {
3226  lineart_triangle_get_other_verts(t2, share, &sv1, &sv2);
3227  if (lineart_triangle_2v_intersection_math(sv1, sv2, tri, 0, v2)) {
3228  return true;
3229  }
3230  }
3231  }
3232  else {
3233  /* If not sharing any points, then we need to try all the possibilities. */
3234 
3235  if (lineart_triangle_2v_intersection_math(tri->v[0], tri->v[1], t2, 0, v1)) {
3236  next = v2;
3237  last = v1;
3238  }
3239 
3240  if (lineart_triangle_2v_intersection_math(tri->v[1], tri->v[2], t2, last, next)) {
3241  if (last) {
3242  return true;
3243  }
3244  next = v2;
3245  last = v1;
3246  }
3247  if (lineart_triangle_2v_intersection_math(tri->v[2], tri->v[0], t2, last, next)) {
3248  if (last) {
3249  return true;
3250  }
3251  next = v2;
3252  last = v1;
3253  }
3254 
3255  if (lineart_triangle_2v_intersection_math(t2->v[0], t2->v[1], tri, last, next)) {
3256  if (last) {
3257  return true;
3258  }
3259  next = v2;
3260  last = v1;
3261  }
3262  if (lineart_triangle_2v_intersection_math(t2->v[1], t2->v[2], tri, last, next)) {
3263  if (last) {
3264  return true;
3265  }
3266  next = v2;
3267  last = v1;
3268  }
3269  if (lineart_triangle_2v_intersection_math(t2->v[2], t2->v[0], tri, last, next)) {
3270  if (last) {
3271  return true;
3272  }
3273  next = v2;
3274  last = v1;
3275  }
3276  }
3277  return false;
3278 }
3279 
3281  const double *v1,
3282  const double *v2,
3283  LineartTriangle *tri1,
3284  LineartTriangle *tri2)
3285 {
3286  if (th->current == th->max) {
3287 
3288  LineartIsecSingle *new_array = MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2,
3289  "LineartIsecSingle");
3290  memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max);
3291  th->max *= 2;
3292  MEM_freeN(th->array);
3293  th->array = new_array;
3294  }
3295  LineartIsecSingle *isec_single = &th->array[th->current];
3296  copy_v3_v3_db(isec_single->v1, v1);
3297  copy_v3_v3_db(isec_single->v2, v2);
3298  isec_single->tri1 = tri1;
3299  isec_single->tri2 = tri2;
3300  if (tri1->target_reference > tri2->target_reference) {
3301  SWAP(LineartTriangle *, isec_single->tri1, isec_single->tri2);
3302  }
3303  th->current++;
3304 }
3305 
3306 #define LRT_ISECT_TRIANGLE_PER_THREAD 4096
3307 
3309 {
3310  LineartData *ld = th->ld;
3311  int remaining = LRT_ISECT_TRIANGLE_PER_THREAD;
3312 
3313  BLI_spin_lock(&ld->lock_task);
3315 
3316  if (!eln) {
3317  BLI_spin_unlock(&ld->lock_task);
3318  return false;
3319  }
3320 
3321  th->pending_from = eln;
3323 
3324  while (remaining > 0 && eln) {
3325  int remaining_this_eln = eln->element_count - ld->isect_scheduled_up_to_index;
3326  int added_count = MIN2(remaining, remaining_this_eln);
3327  remaining -= added_count;
3328  if (remaining || added_count == remaining_this_eln) {
3329  eln = eln->next;
3330  ld->isect_scheduled_up_to = eln;
3332  }
3333  else {
3334  ld->isect_scheduled_up_to_index += added_count;
3335  }
3336  }
3337 
3338  th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last;
3340 
3341  BLI_spin_unlock(&ld->lock_task);
3342 
3343  return true;
3344 }
3345 
3346 /* This function initializes two things:
3347  * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler.
3348  * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will
3349  * be finalized by #lineart_create_edges_from_isec_data
3350  */
3351 static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count)
3352 {
3353  d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr");
3354  d->ld = ld;
3355  d->thread_count = thread_count;
3356 
3359 
3360  for (int i = 0; i < thread_count; i++) {
3361  LineartIsecThread *it = &d->threads[i];
3362  it->array = MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr");
3363  it->max = 100;
3364  it->current = 0;
3365  it->thread_id = i;
3366  it->ld = ld;
3367  }
3368 }
3369 
3371 {
3372  for (int i = 0; i < d->thread_count; i++) {
3373  LineartIsecThread *it = &d->threads[i];
3374  MEM_freeN(it->array);
3375  }
3376  MEM_freeN(d->threads);
3377 }
3378 
3380  LineartBoundingArea *ba,
3381  LineartIsecThread *th,
3382  int up_to)
3383 {
3384  BLI_assert(th != NULL);
3385 
3386  if (!th) {
3387  return;
3388  }
3389 
3390  double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
3391 
3392  /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */
3393  for (int i = 0; i < up_to; i++) {
3394  /* Testing_triangle->testing[0] is used to store pairing triangle reference.
3395  * See definition of LineartTriangleThread for more info. */
3396  LineartTriangle *testing_triangle = ba->linked_triangles[i];
3397  LineartTriangleThread *tt = (LineartTriangleThread *)testing_triangle;
3398 
3399  if (testing_triangle == tri || tt->testing_e[th->thread_id] == (LineartEdge *)tri) {
3400  continue;
3401  }
3402  tt->testing_e[th->thread_id] = (LineartEdge *)tri;
3403 
3404  if (!((testing_triangle->flags | tri->flags) & LRT_TRIANGLE_FORCE_INTERSECTION)) {
3405  if (((testing_triangle->flags | tri->flags) & LRT_TRIANGLE_NO_INTERSECTION) ||
3406  (testing_triangle->flags & tri->flags & LRT_TRIANGLE_INTERSECTION_ONLY)) {
3407  continue;
3408  }
3409  }
3410 
3411  double *RG0 = testing_triangle->v[0]->gloc, *RG1 = testing_triangle->v[1]->gloc,
3412  *RG2 = testing_triangle->v[2]->gloc;
3413 
3414  /* Bounding box not overlapping or triangles share edges, not potential of intersecting. */
3415  if ((MIN3(G0[2], G1[2], G2[2]) > MAX3(RG0[2], RG1[2], RG2[2])) ||
3416  (MAX3(G0[2], G1[2], G2[2]) < MIN3(RG0[2], RG1[2], RG2[2])) ||
3417  (MIN3(G0[0], G1[0], G2[0]) > MAX3(RG0[0], RG1[0], RG2[0])) ||
3418  (MAX3(G0[0], G1[0], G2[0]) < MIN3(RG0[0], RG1[0], RG2[0])) ||
3419  (MIN3(G0[1], G1[1], G2[1]) > MAX3(RG0[1], RG1[1], RG2[1])) ||
3420  (MAX3(G0[1], G1[1], G2[1]) < MIN3(RG0[1], RG1[1], RG2[1])) ||
3421  lineart_triangle_share_edge(tri, testing_triangle)) {
3422  continue;
3423  }
3424 
3425  /* If we do need to compute intersection, then finally do it. */
3426 
3427  double iv1[3], iv2[3];
3428  if (lineart_triangle_intersect_math(tri, testing_triangle, iv1, iv2)) {
3429  lineart_add_isec_thread(th, iv1, iv2, tri, testing_triangle);
3430  }
3431  }
3432 }
3433 
3438 {
3439  float direction[3] = {0, 0, 1};
3440  float trans[3];
3441  float inv[4][4];
3442  float obmat_no_scale[4][4];
3443 
3444  copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat);
3445  normalize_v3(obmat_no_scale[0]);
3446  normalize_v3(obmat_no_scale[1]);
3447  normalize_v3(obmat_no_scale[2]);
3448  invert_m4_m4(inv, obmat_no_scale);
3449  transpose_m4(inv);
3450  mul_v3_mat3_m4v3(trans, inv, direction);
3451  copy_m4_m4(ld->conf.cam_obmat, obmat_no_scale);
3452  copy_v3db_v3fl(ld->conf.view_vector, trans);
3453 
3454  if (ld->conf.light_reference_available) {
3455  copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat_secondary);
3456  normalize_v3(obmat_no_scale[0]);
3457  normalize_v3(obmat_no_scale[1]);
3458  normalize_v3(obmat_no_scale[2]);
3459  invert_m4_m4(inv, obmat_no_scale);
3460  transpose_m4(inv);
3461  mul_v3_mat3_m4v3(trans, inv, direction);
3462  copy_m4_m4(ld->conf.cam_obmat_secondary, obmat_no_scale);
3464  }
3465 }
3466 
3468 {
3469  BLI_spin_end(&ba->lock);
3470  if (ba->child) {
3471  for (int i = 0; i < 4; i++) {
3473  }
3474  }
3475 }
3476 
3478 {
3479  if (ld == NULL) {
3480  return;
3481  }
3482 
3483  BLI_listbase_clear(&ld->chains);
3485 
3489 
3490  if (ld->pending_edges.array) {
3492  }
3493 
3494  for (int i = 0; i < ld->qtree.initial_tile_count; i++) {
3496  }
3498 
3500 }
3501 
3503 {
3504  if (ld == NULL) {
3505  return;
3506  }
3507 
3508  BLI_spin_end(&ld->lock_task);
3509  BLI_spin_end(&ld->lock_cuts);
3511 
3513 
3515 }
3516 
3518 {
3519  LineartData *ld = lmd->la_data_ptr;
3520 
3522 
3523  if (ld) {
3524  MEM_freeN(ld);
3525  lmd->la_data_ptr = NULL;
3526  }
3527 
3528  if (G.debug_value == 4000) {
3529  printf("LRT: Destroyed render data.\n");
3530  }
3531 }
3532 
3534 {
3535  LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache");
3536  return lc;
3537 }
3538 
3540 {
3541  if (!(*lc)) {
3542  return;
3543  }
3544  lineart_mem_destroy(&((*lc)->chain_data_pool));
3545  MEM_freeN(*lc);
3546  (*lc) = NULL;
3547 }
3548 
3551  Object *camera,
3552  Object *active_camera,
3553  LineartCache *lc)
3554 {
3555  LineartData *ld = MEM_callocN(sizeof(LineartData), "Line Art render buffer");
3556 
3557  lmd->cache = lc;
3558  lmd->la_data_ptr = ld;
3560 
3561  if (!scene || !camera || !lc) {
3562  return NULL;
3563  }
3564  Camera *c = camera->data;
3565  double clipping_offset = 0;
3566 
3568  /* This way the clipped lines are "stably visible" by prevents depth buffer artifacts. */
3569  clipping_offset = 0.0001;
3570  }
3571 
3572  copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]);
3573  if (active_camera) {
3574  copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->obmat[3]);
3575  }
3576  copy_m4_m4(ld->conf.cam_obmat, camera->obmat);
3577  /* Make sure none of the scaling factor makes in, line art expects no scaling on cameras and
3578  * lights. */
3579  normalize_v3(ld->conf.cam_obmat[0]);
3580  normalize_v3(ld->conf.cam_obmat[1]);
3581  normalize_v3(ld->conf.cam_obmat[2]);
3582 
3583  ld->conf.cam_is_persp = (c->type == CAM_PERSP);
3584  ld->conf.near_clip = c->clip_start + clipping_offset;
3585  ld->conf.far_clip = c->clip_end - clipping_offset;
3586  ld->w = scene->r.xsch;
3587  ld->h = scene->r.ysch;
3588 
3589  if (ld->conf.cam_is_persp) {
3591  }
3592  else {
3594  }
3595 
3596  double asp = ((double)ld->w / (double)ld->h);
3597  int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h);
3598  ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
3599  ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
3600 
3601  ld->conf.overscan = lmd->overscan;
3602 
3603  ld->conf.shift_x /= (1 + ld->conf.overscan);
3604  ld->conf.shift_y /= (1 + ld->conf.overscan);
3605 
3606  if (lmd->light_contour_object) {
3607  Object *light_obj = lmd->light_contour_object;
3608  copy_v3db_v3fl(ld->conf.camera_pos_secondary, light_obj->obmat[3]);
3609  copy_m4_m4(ld->conf.cam_obmat_secondary, light_obj->obmat);
3610  /* Make sure none of the scaling factor makes in, line art expects no scaling on cameras and
3611  * lights. */
3615  ld->conf.light_reference_available = true;
3616  if (light_obj->type == OB_LAMP) {
3617  ld->conf.cam_is_persp_secondary = ((Light *)light_obj->data)->type != LA_SUN;
3618  }
3619  }
3620 
3625 
3634 
3635  /* See lineart_edge_from_triangle() for how this option may impact performance. */
3637 
3639 
3642 
3644 
3645  /* This is used to limit calculation to a certain level to save time, lines who have higher
3646  * occlusion levels will get ignored. */
3648 
3649  int16_t edge_types = lmd->edge_types_override;
3650 
3651  /* lmd->edge_types_override contains all used flags in the modifier stack. */
3652  ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
3653  ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
3654  ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
3655  ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
3656  ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
3657  ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
3658  ld->conf.use_light_contour = ((edge_types & LRT_EDGE_FLAG_LIGHT_CONTOUR) != 0 &&
3659  (lmd->light_contour_object != NULL));
3660  ld->conf.use_shadow = ((edge_types & LRT_EDGE_FLAG_PROJECTED_SHADOW) != 0 &&
3661  (lmd->light_contour_object != NULL));
3662 
3667 
3669 
3676 
3677  ld->chain_data_pool = &lc->chain_data_pool;
3678 
3679  /* See #LineartData::edge_data_pool for explanation. */
3680  ld->edge_data_pool = &ld->render_data_pool;
3681 
3682  BLI_spin_init(&ld->lock_task);
3683  BLI_spin_init(&ld->lock_cuts);
3685 
3687 
3688  return ld;
3689 }
3690 
3692 {
3693  return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (ld->thread_count));
3694 }
3695 
3697 {
3698  /* Initial tile split is defined as 4 (subdivided as 4*4), increasing the value allows the
3699  * algorithm to build the acceleration structure for bigger scenes a little faster but not as
3700  * efficient at handling medium to small scenes. */
3701  int sp_w = LRT_BA_ROWS;
3702  int sp_h = LRT_BA_ROWS;
3703  int row, col;
3704  LineartBoundingArea *ba;
3705 
3706  /* Always make sure the shortest side has at least LRT_BA_ROWS tiles. */
3707  if (ld->w > ld->h) {
3708  sp_w = sp_h * ld->w / ld->h;
3709  }
3710  else {
3711  sp_h = sp_w * ld->h / ld->w;
3712  }
3713 
3714  /* Because NDC (Normalized Device Coordinates) range is (-1,1),
3715  * so the span for each initial tile is double of that in the (0,1) range. */
3716  double span_w = (double)1 / sp_w * 2.0;
3717  double span_h = (double)1 / sp_h * 2.0;
3718 
3719  ld->qtree.count_x = sp_w;
3720  ld->qtree.count_y = sp_h;
3721  ld->qtree.tile_width = span_w;
3722  ld->qtree.tile_height = span_h;
3723 
3724  ld->qtree.initial_tile_count = sp_w * sp_h;
3727  for (int i = 0; i < ld->qtree.initial_tile_count; i++) {
3728  BLI_spin_init(&ld->qtree.initials[i].lock);
3729  }
3730 
3731  /* Initialize tiles. */
3732  for (row = 0; row < sp_h; row++) {
3733  for (col = 0; col < sp_w; col++) {
3734  ba = &ld->qtree.initials[row * ld->qtree.count_x + col];
3735 
3736  /* Set the four direction limits. */
3737  ba->l = span_w * col - 1.0;
3738  ba->r = (col == sp_w - 1) ? 1.0 : (span_w * (col + 1) - 1.0);
3739  ba->u = 1.0 - span_h * row;
3740  ba->b = (row == sp_h - 1) ? -1.0 : (1.0 - span_h * (row + 1));
3741 
3742  ba->cx = (ba->l + ba->r) / 2;
3743  ba->cy = (ba->u + ba->b) / 2;
3744 
3745  /* Init linked_triangles array. */
3749  "ba_linked_triangles");
3750  ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count,
3751  "ba_linked_lines");
3752 
3753  BLI_spin_init(&ba->lock);
3754  }
3755  }
3756 }
3757 
3762 {
3763  LineartBoundingArea *ba = root->child, *tba;
3764  LinkData *lip2, *next_lip;
3766 
3767  /* Inter-connection with newly created 4 child bounding areas. */
3768  lineart_list_append_pointer_pool(&ba[1].rp, mph, &ba[0]);
3769  lineart_list_append_pointer_pool(&ba[0].lp, mph, &ba[1]);
3770  lineart_list_append_pointer_pool(&ba[1].bp, mph, &ba[2]);
3771  lineart_list_append_pointer_pool(&ba[2].up, mph, &ba[1]);
3772  lineart_list_append_pointer_pool(&ba[2].rp, mph, &ba[3]);
3773  lineart_list_append_pointer_pool(&ba[3].lp, mph, &ba[2]);
3774  lineart_list_append_pointer_pool(&ba[3].up, mph, &ba[0]);
3775  lineart_list_append_pointer_pool(&ba[0].bp, mph, &ba[3]);
3776 
3777  /* Connect 4 child bounding areas to other areas that are
3778  * adjacent to their original parents. */
3779  LISTBASE_FOREACH (LinkData *, lip, &root->lp) {
3780 
3781  /* For example, we are dealing with parent's left side
3782  * "tba" represents each adjacent neighbor of the parent. */
3783  tba = lip->data;
3784 
3785  /* if this neighbor is adjacent to
3786  * the two new areas on the left side of the parent,
3787  * then add them to the adjacent list as well. */
3788  if (ba[1].u > tba->b && ba[1].b < tba->u) {
3789  lineart_list_append_pointer_pool(&ba[1].lp, mph, tba);
3790  lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]);
3791  }
3792  if (ba[2].u > tba->b && ba[2].b < tba->u) {
3793  lineart_list_append_pointer_pool(&ba[2].lp, mph, tba);
3794  lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]);
3795  }
3796  }
3797  LISTBASE_FOREACH (LinkData *, lip, &root->rp) {
3798  tba = lip->data;
3799  if (ba[0].u > tba->b && ba[0].b < tba->u) {
3800  lineart_list_append_pointer_pool(&ba[0].rp, mph, tba);
3801  lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]);
3802  }
3803  if (ba[3].u > tba->b && ba[3].b < tba->u) {
3804  lineart_list_append_pointer_pool(&ba[3].rp, mph, tba);
3805  lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]);
3806  }
3807  }
3808  LISTBASE_FOREACH (LinkData *, lip, &root->up) {
3809  tba = lip->data;
3810  if (ba[0].r > tba->l && ba[0].l < tba->r) {
3811  lineart_list_append_pointer_pool(&ba[0].up, mph, tba);
3812  lineart_list_append_pointer_pool(&tba->bp, mph, &ba[0]);
3813  }
3814  if (ba[1].r > tba->l && ba[1].l < tba->r) {
3815  lineart_list_append_pointer_pool(&ba[1].up, mph, tba);
3816  lineart_list_append_pointer_pool(&tba->bp, mph, &ba[1]);
3817  }
3818  }
3819  LISTBASE_FOREACH (LinkData *, lip, &root->bp) {
3820  tba = lip->data;
3821  if (ba[2].r > tba->l && ba[2].l < tba->r) {
3822  lineart_list_append_pointer_pool(&ba[2].bp, mph, tba);
3823  lineart_list_append_pointer_pool(&tba->up, mph, &ba[2]);
3824  }
3825  if (ba[3].r > tba->l && ba[3].l < tba->r) {
3826  lineart_list_append_pointer_pool(&ba[3].bp, mph, tba);
3827  lineart_list_append_pointer_pool(&tba->up, mph, &ba[3]);
3828  }
3829  }
3830 
3831  /* Then remove the parent bounding areas from
3832  * their original adjacent areas. */
3833  LISTBASE_FOREACH (LinkData *, lip, &root->lp) {
3834  for (lip2 = ((LineartBoundingArea *)lip->data)->rp.first; lip2; lip2 = next_lip) {
3835  next_lip = lip2->next;
3836  tba = lip2->data;
3837  if (tba == root) {
3839  if (ba[1].u > tba->b && ba[1].b < tba->u) {
3840  lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]);
3841  }
3842  if (ba[2].u > tba->b && ba[2].b < tba->u) {
3843  lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]);
3844  }
3845  }
3846  }
3847  }
3848  LISTBASE_FOREACH (LinkData *, lip, &root->rp) {
3849  for (lip2 = ((LineartBoundingArea *)lip->data)->lp.first; lip2; lip2 = next_lip) {
3850  next_lip = lip2->next;
3851  tba = lip2->data;
3852  if (tba == root) {
3854  if (ba[0].u > tba->b && ba[0].b < tba->u) {
3855  lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]);
3856  }
3857  if (ba[3].u > tba->b && ba[3].b < tba->u) {
3858  lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]);
3859  }
3860  }
3861  }
3862  }
3863  LISTBASE_FOREACH (LinkData *, lip, &root->up) {
3864  for (lip2 = ((LineartBoundingArea *)lip->data)->bp.first; lip2; lip2 = next_lip) {
3865  next_lip = lip2->next;
3866  tba = lip2->data;
3867  if (tba == root) {
3869  if (ba[0].r > tba->l && ba[0].l < tba->r) {
3870  lineart_list_append_pointer_pool(&tba->up, mph, &ba[0]);
3871  }
3872  if (ba[1].r > tba->l && ba[1].l < tba->r) {
3873  lineart_list_append_pointer_pool(&tba->up, mph, &ba[1]);
3874  }
3875  }
3876  }
3877  }
3878  LISTBASE_FOREACH (LinkData *, lip, &root->bp) {
3879  for (lip2 = ((LineartBoundingArea *)lip->data)->up.first; lip2; lip2 = next_lip) {
3880  next_lip = lip2->next;
3881  tba = lip2->data;
3882  if (tba == root) {
3884  if (ba[2].r > tba->l && ba[2].l < tba->r) {
3885  lineart_list_append_pointer_pool(&tba->bp, mph, &ba[2]);
3886  }
3887  if (ba[3].r > tba->l && ba[3].l < tba->r) {
3888  lineart_list_append_pointer_pool(&tba->bp, mph, &ba[3]);
3889  }
3890  }
3891  }
3892  }
3893 
3894  /* Finally clear parent's adjacent list. */
3895  BLI_listbase_clear(&root->lp);
3896  BLI_listbase_clear(&root->rp);
3897  BLI_listbase_clear(&root->up);
3898  BLI_listbase_clear(&root->bp);
3899 }
3900 
3902 {
3903  if (root->child) {
3905  for (int i = 0; i < 4; i++) {
3907  }
3908  }
3909 }
3910 
3912 {
3913  int total_tile_initial = ld->qtree.count_x * ld->qtree.count_y;
3914  int tiles_per_row = ld->qtree.count_x;
3915 
3916  for (int row = 0; row < ld->qtree.count_y; row++) {
3917  for (int col = 0; col < ld->qtree.count_x; col++) {
3918  LineartBoundingArea *ba = &ld->qtree.initials[row * tiles_per_row + col];
3919  /* Link adjacent ones. */
3920  if (row) {
3922  &ba->up, &ld->render_data_pool, &ld->qtree.initials[(row - 1) * tiles_per_row + col]);
3923  }
3924  if (col) {
3926  &ba->lp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col - 1]);
3927  }
3928  if (row != ld->qtree.count_y - 1) {
3930  &ba->bp, &ld->render_data_pool, &ld->qtree.initials[(row + 1) * tiles_per_row + col]);
3931  }
3932  if (col != ld->qtree.count_x - 1) {
3934  &ba->rp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col + 1]);
3935  }
3936  }
3937  }
3938  for (int i = 0; i < total_tile_initial; i++) {
3940  }
3941 }
3942 
3948  LineartBoundingArea *root,
3949  int recursive_level)
3950 {
3951 
3953  sizeof(LineartBoundingArea) * 4);
3954  ba[0].l = root->cx;
3955  ba[0].r = root->r;
3956  ba[0].u = root->u;
3957  ba[0].b = root->cy;
3958  ba[0].cx = (ba[0].l + ba[0].r) / 2;
3959  ba[0].cy = (ba[0].u + ba[0].b) / 2;
3960 
3961  ba[1].l = root->l;
3962  ba[1].r = root->cx;
3963  ba[1].u = root->u;
3964  ba[1].b = root->cy;
3965  ba[1].cx = (ba[1].l + ba[1].r) / 2;
3966  ba[1].cy = (ba[1].u + ba[1].b) / 2;
3967 
3968  ba[2].l = root->l;
3969  ba[2].r = root->cx;
3970  ba[2].u = root->cy;
3971  ba[2].b = root->b;
3972  ba[2].cx = (ba[2].l + ba[2].r) / 2;
3973  ba[2].cy = (ba[2].u + ba[2].b) / 2;
3974 
3975  ba[3].l = root->cx;
3976  ba[3].r = root->r;
3977  ba[3].u = root->cy;
3978  ba[3].b = root->b;
3979  ba[3].cx = (ba[3].l + ba[3].r) / 2;
3980  ba[3].cy = (ba[3].u + ba[3].b) / 2;
3981 
3982  /* Init linked_triangles array and locks. */
3983  for (int i = 0; i < 4; i++) {
3986  ba[i].linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count,
3987  "ba_linked_triangles");
3988  ba[i].linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count,
3989  "ba_linked_lines");
3990  BLI_spin_init(&ba[i].lock);
3991  }
3992 
3993  for (uint32_t i = 0; i < root->triangle_count; i++) {
3994  LineartTriangle *tri = root->linked_triangles[i];
3995 
3996  double b[4];
3997  b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
3998  b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
3999  b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
4000  b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
4001 
4002  /* Re-link triangles into child tiles, not doing intersection lines during this because this
4003  * batch of triangles are all tested with each other for intersections. */
4004  if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) {
4005  lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL);
4006  }
4007  if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) {
4008  lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL);
4009  }
4010  if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) {
4011  lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL);
4012  }
4013  if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) {
4014  lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL);
4015  }
4016  }
4017 
4018  /* At this point the child tiles are fully initialized and it's safe for new triangles to be
4019  * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */
4020  root->child = ba;
4021 }
4022 
4024  const double l[2],
4025  const double r[2],
4026  LineartBoundingArea *ba)
4027 {
4028  double dx, dy;
4029  double converted[4];
4030  double c1, c;
4031 
4032  if (((converted[0] = ba->l) > MAX2(l[0], r[0])) || ((converted[1] = ba->r) < MIN2(l[0], r[0])) ||
4033  ((converted[2] = ba->b) > MAX2(l[1], r[1])) || ((converted[3] = ba->u) < MIN2(l[1], r[1]))) {
4034  return false;
4035  }
4036 
4037  dx = l[0] - r[0];
4038  dy = l[1] - r[1];
4039 
4040  c1 = dx * (converted[2] - l[1]) - dy * (converted[0] - l[0]);
4041  c = c1;
4042 
4043  c1 = dx * (converted[2] - l[1]) - dy * (converted[1] - l[0]);
4044  if (c1 * c <= 0) {
4045  return true;
4046  }
4047  c = c1;
4048 
4049  c1 = dx * (converted[3] - l[1]) - dy * (converted[0] - l[0]);
4050  if (c1 * c <= 0) {
4051  return true;
4052  }
4053  c = c1;
4054 
4055  c1 = dx * (converted[3] - l[1]) - dy * (converted[1] - l[0]);
4056  if (c1 * c <= 0) {
4057  return true;
4058  }
4059  c = c1;
4060 
4061  return false;
4062 }
4063 
4065  LineartTriangle *tri,
4066  LineartBoundingArea *ba,
4067  bool *r_triangle_vert_inside)
4068 {
4069  double p1[2], p2[2], p3[2], p4[2];
4070  double *FBC1 = tri->v[0]->fbcoord, *FBC2 = tri->v[1]->fbcoord, *FBC3 = tri->v[2]->fbcoord;
4071 
4072  p3[0] = p1[0] = ba->l;
4073  p2[1] = p1[1] = ba->b;
4074  p2[0] = p4[0] = ba->r;
4075  p3[1] = p4[1] = ba->u;
4076 
4077  if ((FBC1[0] >= p1[0] && FBC1[0] <= p2[0] && FBC1[1] >= p1[1] && FBC1[1] <= p3[1]) ||
4078  (FBC2[0] >= p1[0] && FBC2[0] <= p2[0] && FBC2[1] >= p1[1] && FBC2[1] <= p3[1]) ||
4079  (FBC3[0] >= p1[0] && FBC3[0] <= p2[0] && FBC3[1] >= p1[1] && FBC3[1] <= p3[1])) {
4080  *r_triangle_vert_inside = true;
4081  return true;
4082  }
4083 
4084  *r_triangle_vert_inside = false;
4085 
4086  if (lineart_point_inside_triangle(p1, FBC1, FBC2, FBC3) ||
4087  lineart_point_inside_triangle(p2, FBC1, FBC2, FBC3) ||
4088  lineart_point_inside_triangle(p3, FBC1, FBC2, FBC3) ||
4089  lineart_point_inside_triangle(p4, FBC1, FBC2, FBC3)) {
4090  return true;
4091  }
4092 
4093  if (lineart_bounding_area_edge_intersect(fb, FBC1, FBC2, ba) ||
4094  lineart_bounding_area_edge_intersect(fb, FBC2, FBC3, ba) ||
4095  lineart_bounding_area_edge_intersect(fb, FBC3, FBC1, ba)) {
4096  return true;
4097  }
4098 
4099  return false;
4100 }
4101 
4116  LineartBoundingArea *root_ba,
4117  LineartTriangle *tri,
4118  double l_r_u_b[4],
4119  int recursive,
4120  int recursive_level,
4121  bool do_intersection,
4122  struct LineartIsecThread *th)
4123 {
4124  bool triangle_vert_inside;
4125  if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba, &triangle_vert_inside)) {
4126  return;
4127  }
4128 
4129  LineartBoundingArea *old_ba = root_ba;
4130 
4131  if (old_ba->child) {
4132  /* If old_ba->child is not NULL, then tile splitting is fully finished, safe to directly insert
4133  * into child tiles. */
4134  double *B1 = l_r_u_b;
4135  double b[4];
4136  if (!l_r_u_b) {
4137  b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
4138  b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
4139  b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
4140  b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
4141  B1 = b;
4142  }
4143  for (int iba = 0; iba < 4; iba++) {
4144  if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) {
4146  ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th);
4147  }
4148  }
4149  return;
4150  }
4151 
4152  /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is NULL
4153  * in that situation. */
4154  if (th) {
4155  BLI_spin_lock(&old_ba->lock);
4156  }
4157 
4158  /* If there are still space left in this tile for insertion. */
4159  if (old_ba->triangle_count < old_ba->max_triangle_count) {
4160  const uint32_t old_tri_count = old_ba->triangle_count;
4161 
4162  old_ba->linked_triangles[old_tri_count] = tri;
4163 
4164  if (triangle_vert_inside) {
4165  old_ba->insider_triangle_count++;
4166  }
4167  old_ba->triangle_count++;
4168 
4169  /* Do intersections in place. */
4170  if (do_intersection && ld->conf.use_intersections) {
4171  lineart_triangle_intersect_in_bounding_area(tri, old_ba, th, old_tri_count);
4172  }
4173 
4174  if (th) {
4175  BLI_spin_unlock(&old_ba->lock);
4176  }
4177  }
4178  else { /* We need to wait for either splitting or array extension to be done. */
4179 
4180  if (recursive_level < ld->qtree.recursive_level &&
4182  if (!old_ba->child) {
4183  /* old_ba->child==NULL, means we are the thread that's doing the splitting. */
4184  lineart_bounding_area_split(ld, old_ba, recursive_level);
4185  } /* Otherwise other thread has completed the splitting process. */
4186  }
4187  else {
4188  if (old_ba->triangle_count == old_ba->max_triangle_count) {
4189  /* Means we are the thread that's doing the extension. */
4191  } /* Otherwise other thread has completed the extending the array. */
4192  }
4193 
4194  /* Unlock before going into recursive call. */
4195  if (th) {
4196  BLI_spin_unlock(&old_ba->lock);
4197  }
4198 
4199  /* Of course we still have our own triangle needs to be added. */
4201  ld, root_ba, tri, l_r_u_b, recursive, recursive_level, do_intersection, th);
4202  }
4203 }
4204 
4206 {
4207  BLI_spin_end(&ba->lock);
4208  if (ba->linked_lines) {
4209  MEM_freeN(ba->linked_lines);
4210  }
4211  if (ba->linked_triangles) {
4213  }
4214  if (recursive && ba->child) {
4215  for (int i = 0; i < 4; i++) {
4216  lineart_free_bounding_area_memory(&ba->child[i], recursive);
4217  }
4218  }
4219 }
4221 {
4222  for (int i = 0; i < ld->qtree.count_y; i++) {
4223  for (int j = 0; j < ld->qtree.count_x; j++) {
4225  }
4226  }
4227 }
4228 
4230  LineartBoundingArea *root_ba,
4231  LineartEdge *e)
4232 {
4233  if (root_ba->child == NULL) {
4235  }
4236  else {
4238  ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
4239  lineart_bounding_area_link_edge(ld, &root_ba->child[0], e);
4240  }
4242  ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
4243  lineart_bounding_area_link_edge(ld, &root_ba->child[1], e);
4244  }
4246  ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
4247  lineart_bounding_area_link_edge(ld, &root_ba->child[2], e);
4248  }
4250  ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
4251  lineart_bounding_area_link_edge(ld, &root_ba->child[3], e);
4252  }
4253  }
4254 }
4255 
4257 {
4258  if (root_ba->child) {
4259  for (int i = 0; i < 4; i++) {
4260  lineart_clear_linked_edges_recursive(ld, &root_ba->child[i]);
4261  }
4262  }
4263  if (root_ba->linked_lines) {
4264  MEM_freeN(root_ba->linked_lines);
4265  }
4266  root_ba->line_count = 0;
4267  root_ba->max_line_count = 128;
4268  root_ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * root_ba->max_line_count,
4269  "cleared lineart edges");
4270 }
4272 {
4274  for (int i = 0; i < ld->qtree.count_y; i++) {
4275  for (int j = 0; j < ld->qtree.count_x; j++) {
4276  lineart_clear_linked_edges_recursive(ld, &ba[i * ld->qtree.count_x + j]);
4277  }
4278  }
4279 }
4280 
4285 {
4287  {
4288  int r1, r2, c1, c2, row, col;
4289  if (lineart_get_edge_bounding_areas(ld, e, &r1, &r2, &c1, &c2)) {
4290  for (row = r1; row != r2 + 1; row++) {
4291  for (col = c1; col != c2 + 1; col++) {
4293  ld, &ld->qtree.initials[row * ld->qtree.count_x + col], e);
4294  }
4295  }
4296  }
4297  }
4299 }
4300 
4302  uint8_t max_occlusion)
4303 {
4304  if (ba->child) {
4305  for (int i = 0; i < 4; i++) {
4306  lineart_main_remove_unused_lines_recursive(&ba->child[i], max_occlusion);
4307  }
4308  return;
4309  }
4310 
4311  if (!ba->line_count) {
4312  return;
4313  }
4314 
4315  int usable_count = 0;
4316  for (int i = 0; i < ba->line_count; i++) {
4317  LineartEdge *e = ba->linked_lines[i];
4318  if (e->min_occ > max_occlusion) {
4319  continue;
4320  }
4321  usable_count++;
4322  }
4323 
4324  if (!usable_count) {
4325  ba->line_count = 0;
4326  return;
4327  }
4328 
4329  LineartEdge **new_array = MEM_callocN(sizeof(LineartEdge *) * usable_count,
4330  "cleaned lineart edge array");
4331 
4332  int new_i = 0;
4333  for (int i = 0; i < ba->line_count; i++) {
4334  LineartEdge *e = ba->linked_lines[i];
4335  if (e->min_occ > max_occlusion) {
4336  continue;
4337  }
4338  new_array[new_i] = e;
4339  new_i++;
4340  }
4341 
4342  MEM_freeN(ba->linked_lines);
4343  ba->linked_lines = new_array;
4344  ba->max_line_count = ba->line_count = usable_count;
4345 }
4346 
4348 {
4349  for (int row = 0; row < ld->qtree.count_y; row++) {
4350  for (int col = 0; col < ld->qtree.count_x; col++) {
4352  &ld->qtree.initials[row * ld->qtree.count_x + col], ld->conf.max_occlusion_level);
4353  }
4354  }
4355 }
4356 
4358  LineartData *ld, LineartTriangle *tri, int *rowbegin, int *rowend, int *colbegin, int *colend)
4359 {
4360  double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
4361  double b[4];
4362 
4363  if (!tri->v[0] || !tri->v[1] || !tri->v[2]) {
4364  return false;
4365  }
4366 
4367  b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
4368  b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
4369  b[2] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
4370  b[3] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
4371 
4372  if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) {
4373  return false;
4374  }
4375 
4376  (*colbegin) = (int)((b[0] + 1.0) / sp_w);
4377  (*colend) = (int)((b[1] + 1.0) / sp_w);
4378  (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
4379  (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
4380 
4381  if ((*colend) >= ld->qtree.count_x) {
4382  (*colend) = ld->qtree.count_x - 1;
4383  }
4384  if ((*rowend) >= ld->qtree.count_y) {
4385  (*rowend) = ld->qtree.count_y - 1;
4386  }
4387  if ((*colbegin) < 0) {
4388  (*colbegin) = 0;
4389  }
4390  if ((*rowbegin) < 0) {
4391  (*rowbegin) = 0;
4392  }
4393 
4394  return true;
4395 }
4396 
4398  LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend)
4399 {
4400  double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
4401  double b[4];
4402 
4403  if (!e->v1 || !e->v2) {
4404  return false;
4405  }
4406 
4407  if (e->v1->fbcoord[0] != e->v1->fbcoord[0] || e->v2->fbcoord[0] != e->v2->fbcoord[0]) {
4408  return false;
4409  }
4410 
4411  b[0] = MIN2(e->v1->fbcoord[0], e->v2->fbcoord[0]);
4412  b[1] = MAX2(e->v1->fbcoord[0], e->v2->fbcoord[0]);
4413  b[2] = MIN2(e->v1->fbcoord[1], e->v2->fbcoord[1]);
4414  b[3] = MAX2(e->v1->fbcoord[1], e->v2->fbcoord[1]);
4415 
4416  if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) {
4417  return false;
4418  }
4419 
4420  (*colbegin) = (int)((b[0] + 1.0) / sp_w);
4421  (*colend) = (int)((b[1] + 1.0) / sp_w);
4422  (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
4423  (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
4424 
4425  /* It's possible that the line stretches too much out to the side, resulting negative value. */
4426  if ((*rowend) < (*rowbegin)) {
4427  (*rowend) = ld->qtree.count_y - 1;
4428  }
4429 
4430  if ((*colend) < (*colbegin)) {
4431  (*colend) = ld->qtree.count_x - 1;
4432  }
4433 
4434  CLAMP((*colbegin), 0, ld->qtree.count_x - 1);
4435  CLAMP((*rowbegin), 0, ld->qtree.count_y - 1);
4436  CLAMP((*colend), 0, ld->qtree.count_x - 1);
4437  CLAMP((*rowend), 0, ld->qtree.count_y - 1);
4438 
4439  return true;
4440 }
4441 
4443 {
4444  double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
4445  int col, row;
4446 
4447  if (x > 1 || x < -1 || y > 1 || y < -1) {
4448  return 0;
4449  }
4450 
4451  col = (int)((x + 1.0) / sp_w);
4452  row = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
4453 
4454  if (col >= ld->qtree.count_x) {
4455  col = ld->qtree.count_x - 1;
4456  }
4457  if (row >= ld->qtree.count_y) {
4458  row = ld->qtree.count_y - 1;
4459  }
4460  if (col < 0) {
4461  col = 0;
4462  }
4463  if (row < 0) {
4464  row = 0;
4465  }
4466 
4467  return &ld->qtree.initials[row * ld->qtree.count_x + col];
4468 }
4469 
4471 {
4472  LineartBoundingArea *iba;
4473  double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
4474  int c = (int)((x + 1.0) / sp_w);
4475  int r = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
4476  if (r < 0) {
4477  r = 0;
4478  }
4479  if (c < 0) {
4480  c = 0;
4481  }
4482  if (r >= ld->qtree.count_y) {
4483  r = ld->qtree.count_y - 1;
4484  }
4485  if (c >= ld->qtree.count_x) {
4486  c = ld->qtree.count_x - 1;
4487  }
4488 
4489  iba = &ld->qtree.initials[r * ld->qtree.count_x + c];
4490  while (iba->child) {
4491  if (x > iba->cx) {
4492  if (y > iba->cy) {
4493  iba = &iba->child[0];
4494  }
4495  else {
4496  iba = &iba->child[3];
4497  }
4498  }
4499  else {
4500  if (y > iba->cy) {
4501  iba = &iba->child[1];
4502  }
4503  else {
4504  iba = &iba->child[2];
4505  }
4506  }
4507  }
4508  return iba;
4509 }
4510 
4512 {
4513  LineartBoundingArea *ba;
4514  if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != NULL) {
4515  return lineart_get_bounding_area(ld, x, y);
4516  }
4517  return NULL;
4518 }
4519 
4521 {
4522  LineartData *ld = th->ld;
4523  int _dir_control = 0;
4525  for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next;
4526  eln = eln->next) {
4527  int index_start = eln == th->pending_from ? th->index_from : 0;
4528  int index_end = eln == th->pending_to ? th->index_to : eln->element_count;
4529  LineartTriangle *tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start);
4530  for (int ei = index_start; ei < index_end; ei++) {
4531  int x1, x2, y1, y2;
4532  int r, co;
4533  if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
4534  tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
4535  continue;
4536  }
4537  if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) {
4538  _dir_control++;
4539  for (co = x1; co <= x2; co++) {
4540  for (r = y1; r <= y2; r++) {
4542  ld, &ld->qtree.initials[r * ld->qtree.count_x + co], tri, 0, 1, 0, 1, th);
4543  }
4544  }
4545  } /* Else throw away. */
4546  tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
4547  }
4548  }
4549  }
4550 }
4551 
4553 {
4554  LineartData *ld = d->ld;
4555  double ZMax = ld->conf.far_clip;
4556  double ZMin = ld->conf.near_clip;
4557  int total_lines = 0;
4558 
4559  for (int i = 0; i < d->thread_count; i++) {
4560  LineartIsecThread *th = &d->threads[i];
4561  if (G.debug_value == 4000) {
4562  printf("Thread %d isec generated %d lines.\n", i, th->current);
4563  }
4564  if (!th->current) {
4565  continue;
4566  }
4567  total_lines += th->current;
4568  }
4569 
4570  if (!total_lines) {
4571  return;
4572  }
4573 
4574  /* We don't care about removing duplicated vert in this method, chaining can handle that,
4575  * and it saves us from using locks and look up tables. */
4576  LineartVert *v = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartVert) * total_lines * 2);
4577  LineartEdge *e = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * total_lines);
4579  sizeof(LineartEdgeSegment) * total_lines);
4580 
4582  sizeof(LineartElementLinkNode));
4583  eln->element_count = total_lines;
4584  eln->pointer = e;
4587 
4588  for (int i = 0; i < d->thread_count; i++) {
4589  LineartIsecThread *th = &d->threads[i];
4590  if (!th->current) {
4591  continue;
4592  }
4593 
4594  for (int j = 0; j < th->current; j++) {
4595  LineartIsecSingle *is = &th->array[j];
4596  LineartVert *v1 = v;
4597  LineartVert *v2 = v + 1;
4598  copy_v3_v3_db(v1->gloc, is->v1);
4599  copy_v3_v3_db(v2->gloc, is->v2);
4600  /* The intersection line has been generated only in geometry space, so we need to transform
4601  * them as well. */
4602  mul_v4_m4v3_db(v1->fbcoord, ld->conf.view_projection, v1->gloc);
4603  mul_v4_m4v3_db(v2->fbcoord, ld->conf.view_projection, v2->gloc);
4604  mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
4605  mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
4606 
4607  v1->fbcoord[0] -= ld->conf.shift_x * 2;
4608  v1->fbcoord[1] -= ld->conf.shift_y * 2;
4609  v2->fbcoord[0] -= ld->conf.shift_x * 2;
4610  v2->fbcoord[1] -= ld->conf.shift_y * 2;
4611 
4612  /* This z transformation is not the same as the rest of the part, because the data don't go
4613  * through normal perspective division calls in the pipeline, but this way the 3D result and
4614  * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
4615  * generation anyway. */
4616  v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
4617  v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
4618  e->v1 = v1;
4619  e->v2 = v2;
4620  e->t1 = is->tri1;
4621  e->t2 = is->tri2;
4622  /* This is so we can also match intersection edges from shadow to later viewing stage. */
4623  e->edge_identifier = (((uint64_t)e->t1->target_reference) << 32) | e->t2->target_reference;
4624  e->flags = LRT_EDGE_FLAG_INTERSECTION;
4625  e->intersection_mask = (is->tri1->intersection_mask | is->tri2->intersection_mask);
4626  BLI_addtail(&e->segments, es);
4627 
4628  int obi1 = (e->t1->target_reference & LRT_OBINDEX_HIGHER);
4629  int obi2 = (e->t2->target_reference & LRT_OBINDEX_HIGHER);
4631  obi1);
4632  LineartElementLinkNode *eln2 = obi1 == obi2 ? eln1 :
4634  &ld->geom.line_buffer_pointers, obi2);
4635  Object *ob1 = eln1 ? eln1->object_ref : NULL;
4636  Object *ob2 = eln2 ? eln2->object_ref : NULL;
4637  if (e->t1->intersection_priority > e->t2->intersection_priority) {
4638  e->object_ref = ob1;
4639  }
4640  else if (e->t1->intersection_priority < e->t2->intersection_priority) {
4641  e->object_ref = ob2;
4642  }
4643  else { /* equal priority */
4644  if (ob1 == ob2) {
4645  /* object_ref should be ambiguous if intersection lines comes from different objects. */
4646  e->object_ref = ob1;
4647  }
4648  }
4649 
4651 
4652  v += 2;
4653  e++;
4654  es++;
4655  }
4656  }
4657 }
4658 
4664 {
4665  double t_start;
4666  if (G.debug_value == 4000) {
4667  t_start = PIL_check_seconds_timer();
4668  }
4669 
4670  /* Initialize per-thread data for thread task scheduling information and storing intersection
4671  * results. */
4672  LineartIsecData d = {0};
4674 
4676  for (int i = 0; i < ld->thread_count; i++) {
4678  }
4680  BLI_task_pool_free(tp);
4681 
4682  if (ld->conf.use_intersections) {
4684  }
4685 
4687 
4688  if (G.debug_value == 4000) {
4689  double t_elapsed = PIL_check_seconds_timer() - t_start;
4690  printf("Line art intersection time: %f\n", t_elapsed);
4691  }
4692 }
4693 
4699  double *fbcoord1,
4700  double *fbcoord2)
4701 {
4702  double data[2] = {fbcoord1[0], fbcoord1[1]};
4703  double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1};
4704  double r = 1, sr = 1;
4705  bool p_unused;
4706 
4707  if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) {
4708  return lineart_get_bounding_area(ld, data[0], data[1]);
4709  }
4710 
4711  if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, LU, RU, &sr, &p_unused) && sr < r && sr > 0) {
4712  r = sr;
4713  }
4714  if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, LB, RB, &sr, &p_unused) && sr < r && sr > 0) {
4715  r = sr;
4716  }
4717  if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, LB, LU, &sr, &p_unused) && sr < r && sr > 0) {
4718  r = sr;
4719  }
4720  if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, RB, RU, &sr, &p_unused) && sr < r && sr > 0) {
4721  r = sr;
4722  }
4723  interp_v2_v2v2_db(data, fbcoord1, fbcoord2, r);
4724 
4725  return lineart_get_bounding_area(ld, data[0], data[1]);
4726 }
4727 
4733  double *fbcoord1,
4734  double *fbcoord2,
4735  double x,
4736  double y,
4737  double k,
4738  int positive_x,
4739  int positive_y,
4740  double *next_x,
4741  double *next_y)
4742 {
4743  double rx, ry, ux, uy, lx, ly, bx, by;
4744  double r1, r2;
4745  LineartBoundingArea *ba;
4746 
4747  /* If we are marching towards the right. */
4748  if (positive_x > 0) {
4749  rx = this->r;
4750  ry = y + k * (rx - x);
4751 
4752  /* If we are marching towards the top. */
4753  if (positive_y > 0) {
4754  uy = this->u;
4755  ux = x + (uy - y) / k;
4756  r1 = ratiod(fbcoord1[0], fbcoord2[0], rx);
4757  r2 = ratiod(fbcoord1[0], fbcoord2[0], ux);
4758  if (MIN2(r1, r2) > 1) {
4759  return 0;
4760  }
4761 
4762  /* We reached the right side before the top side. */
4763  if (r1 <= r2) {
4764  LISTBASE_FOREACH (LinkData *, lip, &this->rp) {
4765  ba = lip->data;
4766  if (ba->u >= ry && ba->b < ry) {
4767  *next_x = rx;
4768  *next_y = ry;
4769  return ba;
4770  }
4771  }
4772  }
4773  /* We reached the top side before the right side. */
4774  else {
4775  LISTBASE_FOREACH (LinkData *, lip, &this->up) {
4776  ba = lip->data;
4777  if (ba->r >= ux && ba->l < ux) {
4778  *next_x = ux;
4779  *next_y = uy;
4780  return ba;
4781  }
4782  }
4783  }
4784  }
4785  /* If we are marching towards the bottom. */
4786  else if (positive_y < 0) {
4787  by = this->b;
4788  bx = x + (by - y) / k;
4789  r1 = ratiod(fbcoord1[0], fbcoord2[0], rx);
4790  r2 = ratiod(fbcoord1[0], fbcoord2[0], bx);
4791  if (MIN2(r1, r2) > 1) {
4792  return 0;
4793  }
4794  if (r1 <= r2) {
4795  LISTBASE_FOREACH (LinkData *, lip, &this->rp) {
4796  ba = lip->data;
4797  if (ba->u >= ry && ba->b < ry) {
4798  *next_x = rx;
4799  *next_y = ry;
4800  return ba;
4801  }
4802  }
4803  }
4804  else {
4805  LISTBASE_FOREACH (LinkData *, lip, &this->bp) {
4806  ba = lip->data;
4807  if (ba->r >= bx && ba->l < bx) {
4808  *next_x = bx;
4809  *next_y = by;
4810  return ba;
4811  }
4812  }
4813  }
4814  }
4815  /* If the line is completely horizontal, in which Y difference == 0. */
4816  else {
4817  r1 = ratiod(fbcoord1[0], fbcoord2[0], this->r);
4818  if (r1 > 1) {
4819  return 0;
4820  }
4821  LISTBASE_FOREACH (LinkData *, lip, &this->rp) {
4822  ba = lip->data;
4823  if (ba->u >= y && ba->b < y) {
4824  *next_x = this->r;
4825  *next_y = y;
4826  return ba;
4827  }
4828  }
4829  }
4830  }
4831 
4832  /* If we are marching towards the left. */
4833  else if (positive_x < 0) {
4834  lx = this->l;
4835  ly = y + k * (lx - x);
4836 
4837  /* If we are marching towards the top. */
4838  if (positive_y > 0) {
4839  uy = this->u;
4840  ux = x + (uy - y) / k;
4841  r1 = ratiod(fbcoord1[0], fbcoord2[0], lx);
4842  r2 = ratiod(fbcoord1[0], fbcoord2[0], ux);
4843  if (MIN2(r1, r2) > 1) {
4844  return 0;
4845  }
4846  if (r1 <= r2) {
4847  LISTBASE_FOREACH (LinkData *, lip, &this->lp) {
4848  ba = lip->data;
4849  if (ba->u >= ly && ba->b < ly) {
4850  *next_x = lx;
4851  *next_y = ly;
4852  return ba;
4853  }
4854  }
4855  }
4856  else {
4857  LISTBASE_FOREACH (LinkData *, lip, &this->up) {
4858  ba = lip->data;
4859  if (ba->r >= ux && ba->l < ux) {
4860  *next_x = ux;
4861  *next_y = uy;
4862  return ba;
4863  }
4864  }
4865  }
4866  }
4867 
4868  /* If we are marching towards the bottom. */
4869  else if (positive_y < 0) {
4870  by = this->b;
4871  bx = x + (by - y) / k;
4872  r1 = ratiod(fbcoord1[0], fbcoord2[0], lx);
4873  r2 = ratiod(fbcoord1[0], fbcoord2[0], bx);
4874  if (MIN2(r1, r2) > 1) {
4875  return 0;
4876  }
4877  if (r1 <= r2) {
4878  LISTBASE_FOREACH (LinkData *, lip, &this->lp) {
4879  ba = lip->data;
4880  if (ba->u >= ly && ba->b < ly) {
4881  *next_x = lx;
4882  *next_y = ly;
4883  return ba;
4884  }
4885  }
4886  }
4887  else {
4888  LISTBASE_FOREACH (LinkData *, lip, &this->bp) {
4889  ba = lip->data;
4890  if (ba->r >= bx && ba->l < bx) {
4891  *next_x = bx;
4892  *next_y = by;
4893  return ba;
4894  }
4895  }
4896  }
4897  }
4898  /* Again, horizontal. */
4899  else {
4900  r1 = ratiod(fbcoord1[0], fbcoord2[0], this->l);
4901  if (r1 > 1) {
4902  return 0;
4903  }
4904  LISTBASE_FOREACH (LinkData *, lip, &this->lp) {
4905  ba = lip->data;
4906  if (ba->u >= y && ba->b < y) {
4907  *next_x = this->l;
4908  *next_y = y;
4909  return ba;
4910  }
4911  }
4912  }
4913  }
4914  /* If the line is completely vertical, hence X difference == 0. */
4915  else {
4916  if (positive_y > 0) {
4917  r1 = ratiod(fbcoord1[1], fbcoord2[1], this->u);
4918  if (r1 > 1) {
4919  return 0;
4920  }
4921  LISTBASE_FOREACH (LinkData *, lip, &this->up) {
4922  ba = lip->data;
4923  if (ba->r > x && ba->l <= x) {
4924  *next_x = x;
4925  *next_y = this->u;
4926  return ba;
4927  }
4928  }
4929  }
4930  else if (positive_y < 0) {
4931  r1 = ratiod(fbcoord1[1], fbcoord2[1], this->b);
4932  if (r1 > 1) {
4933  return 0;
4934  }
4935  LISTBASE_FOREACH (LinkData *, lip, &this->bp) {
4936  ba = lip->data;
4937  if (ba->r > x && ba->l <= x) {
4938  *next_x = x;
4939  *next_y = this->b;
4940  return ba;
4941  }
4942  }
4943  }
4944  else {
4945  /* Segment has no length. */
4946  return 0;
4947  }
4948  }
4949  return 0;
4950 }
4951 
4959  LineartCache **cached_result,
4960  bool enable_stroke_depth_offset)
4961 {
4962  LineartData *ld;
4964  int intersections_only = 0; /* Not used right now, but preserve for future. */
4965  Object *use_camera;
4966 
4967  double t_start;
4968  if (G.debug_value == 4000) {
4969  t_start = PIL_check_seconds_timer();
4970  }
4971 
4973  if (!lmd->source_camera ||
4974  (use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
4975  OB_CAMERA) {
4976  return false;
4977  }
4978  }
4979  else {
4980 
4982 
4983  if (!scene->camera) {
4984  return false;
4985  }
4986  use_camera = scene->camera;
4987  }
4988 
4990  *cached_result = lc;
4991 
4992  ld = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
4993 
4994  /* Triangle thread testing data size varies depending on the thread count.
4995  * See definition of LineartTriangleThread for details. */
4997 
4998  LineartData *shadow_rb = NULL;
4999  LineartElementLinkNode *shadow_veln, *shadow_eeln;
5000  ListBase *shadow_elns = ld->conf.shadow_selection ? &lc->shadow_elns : NULL;
5001  bool shadow_generated = lineart_main_try_generate_shadow(depsgraph,
5002  scene,
5003  ld,
5004  lmd,
5005  &lc->shadow_data_pool,
5006  &shadow_veln,
5007  &shadow_eeln,
5008  shadow_elns,
5009  &shadow_rb);
5010 
5011  /* Get view vector before loading geometries, because we detect feature lines there. */
5013 
5015  scene,
5016  use_camera,
5017  ld,
5019  false,
5020  shadow_elns);
5021 
5022  if (shadow_generated) {
5023  lineart_main_transform_and_add_shadow(ld, shadow_veln, shadow_eeln);
5024  }
5025 
5026  if (!ld->geom.vertex_buffer_pointers.first) {
5027  /* No geometry loaded, return early. */
5028  return true;
5029  }
5030 
5031  /* Initialize the bounding box acceleration structure, it's a lot like BVH in 3D. */
5033 
5034  /* We need to get cut into triangles that are crossing near/far plans, only this way can we get
5035  * correct coordinates of those clipped lines. Done in two steps,
5036  * setting clip_far==false for near plane. */
5037  lineart_main_cull_triangles(ld, false);
5038  /* `clip_far == true` for far plane. */
5039  lineart_main_cull_triangles(ld, true);
5040 
5041  /* At this point triangle adjacent info pointers is no longer needed, free them. */
5043 
5044  /* Do the perspective division after clipping is done. */
5046 
5048 
5049  /* Triangle intersections are done here during sequential adding of them. Only after this,
5050  * triangles and lines are all linked with acceleration structure, and the 2D occlusion stage
5051  * can do its job. */
5053 
5054  /* Add shadow cuts to intersection lines as well. */
5056 
5057  /* Re-link bounding areas because they have been subdivided by worker threads and we need
5058  * adjacent info. */
5060 
5061  /* Link lines to acceleration structure, this can only be done after perspective division, if
5062  * we do it after triangles being added, the acceleration structure has already been
5063  * subdivided, this way we do less list manipulations. */
5065 
5066  /* "intersection_only" is preserved for being called in a standalone fashion.
5067  * If so the data will already be available at the stage. Otherwise we do the occlusion and
5068  * chaining etc. */
5069 
5070  if (!intersections_only) {
5071 
5072  /* Occlusion is work-and-wait. This call will not return before work is completed. */
5074 
5075  lineart_main_make_enclosed_shapes(ld, shadow_rb);
5076 
5078 
5079  /* Chaining is all single threaded. See lineart_chain.c
5080  * In this particular call, only lines that are geometrically connected (share the _exact_
5081  * same end point) will be chained together. */
5083 
5084  /* We are unable to take care of occlusion if we only connect end points, so here we do a
5085  * spit, where the splitting point could be any cut in e->segments. */
5087 
5088  /* Then we connect chains based on the _proximity_ of their end points in image space, here's
5089  * the place threshold value gets involved. */
5091 
5092  if (ld->conf.chain_smooth_tolerance > FLT_EPSILON) {
5093  /* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best
5094  * effective range in image-space (Coordinate only goes from -1 to 1). This value is
5095  * somewhat arbitrary, but works best for the moment. */
5097  }
5098 
5101  }
5102 
5103  if (ld->conf.angle_splitting_threshold > FLT_EPSILON) {
5105  }
5106 
5107  if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
5110  }
5111 
5112  if (ld->conf.shadow_use_silhouette) {
5114  }
5115 
5116  /* Finally transfer the result list into cache. */
5117  memcpy(&lc->chains, &ld->chains, sizeof(ListBase));
5118 
5119  /* At last, we need to clear flags so we don't confuse GPencil generation calls. */
5121 
5123  }
5124 
5126 
5127  if (ld->conf.shadow_enclose_shapes && shadow_rb) {
5129  MEM_freeN(shadow_rb);
5130  }
5131 
5132  if (G.debug_value == 4000) {
5134 
5135  double t_elapsed = PIL_check_seconds_timer() - t_start;
5136  printf("Line art total time: %lf\n", t_elapsed);
5137  }
5138 
5139  return true;
5140 }
5141 
5144  Object *gpencil_object,
5145  float (*gp_obmat_inverse)[4],
5146  bGPDlayer *UNUSED(gpl),
5147  bGPDframe *gpf,
5148  int level_start,
5149  int level_end,
5150  int material_nr,
5151  Object *source_object,
5152  Collection *source_collection,
5153  int types,
5154  uchar mask_switches,
5155  uchar material_mask_bits,
5156  uchar intersection_mask,
5157  int16_t thickness,
5158  float opacity,
5159  uchar shaodow_selection,
5160  uchar silhouette_mode,
5161  const char *source_vgname,
5162  const char *vgname,
5163  int modifier_flags,
5164  int modifier_calculation_flags)
5165 {
5166  if (cache == NULL) {
5167  if (G.debug_value == 4000) {
5168  printf("NULL Lineart cache!\n");
5169  }
5170  return;
5171  }
5172 
5173  int stroke_count = 0;
5174  int color_idx = 0;
5175 
5176  Object *orig_ob = NULL;
5177  if (source_object) {
5178  orig_ob = source_object->id.orig_id ? (Object *)source_object->id.orig_id : source_object;
5179  }
5180 
5181  Collection *orig_col = NULL;
5182  if (source_collection) {
5183  orig_col = source_collection->id.orig_id ? (Collection *)source_collection->id.orig_id :
5184  source_collection;
5185  }
5186 
5187  /* (!orig_col && !orig_ob) means the whole scene is selected. */
5188 
5189  int enabled_types = cache->all_enabled_edge_types;
5190  bool invert_input = modifier_calculation_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
5191  bool match_output = modifier_calculation_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
5192  bool inverse_silhouette = modifier_flags & LRT_GPENCIL_INVERT_SILHOUETTE_FILTER;
5193 
5194  LISTBASE_FOREACH (LineartEdgeChain *, ec, &cache->chains) {
5195 
5196  if (ec->picked) {
5197  continue;
5198  }
5199  if (!(ec->type & (types & enabled_types))) {
5200  continue;
5201  }
5202  if (ec->level > level_end || ec->level < level_start) {
5203  continue;
5204  }
5205  if (orig_ob && orig_ob != ec->object_ref) {
5206  continue;
5207  }
5208  if (orig_col && ec->object_ref) {
5209  if (BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) {
5210  if (modifier_flags & LRT_GPENCIL_INVERT_COLLECTION) {
5211  continue;
5212  }
5213  }
5214  else {
5215  if (!(modifier_flags & LRT_GPENCIL_INVERT_COLLECTION)) {
5216  continue;
5217  }
5218  }
5219  }
5220  if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_ENABLE) {
5221  if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_MATCH) {
5222  if (ec->material_mask_bits != material_mask_bits) {
5223  continue;
5224  }
5225  }
5226  else {
5227  if (!(ec->material_mask_bits & material_mask_bits)) {
5228  continue;
5229  }
5230  }
5231  }
5232  if (ec->type & LRT_EDGE_FLAG_INTERSECTION) {
5233  if (mask_switches & LRT_GPENCIL_INTERSECTION_MATCH) {
5234  if (ec->intersection_mask != intersection_mask) {
5235  continue;
5236  }
5237  }
5238  else {
5239  if ((intersection_mask) && !(ec->intersection_mask & intersection_mask)) {
5240  continue;
5241  }
5242  }
5243  }
5244  if (shaodow_selection) {
5245  if (ec->shadow_mask_bits != LRT_SHADOW_MASK_UNDEFINED) {
5246  /* TODO(@Yiming): Give a behavior option for how to display undefined shadow info. */
5247  if ((shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED &&
5248  (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED)))) {
5249  continue;
5250  }
5251  else if ((shaodow_selection == LRT_SHADOW_FILTER_SHADED &&
5252  (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED)))) {
5253  continue;
5254  }
5255  else if (shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES) {
5256  uint32_t test_bits = ec->shadow_mask_bits & LRT_SHADOW_TEST_SHAPE_BITS;
5257  if ((test_bits != LRT_SHADOW_MASK_ILLUMINATED) &&
5259  continue;
5260  }
5261  }
5262  }
5263  }
5264  if (silhouette_mode && (ec->type & (LRT_EDGE_FLAG_CONTOUR))) {
5265  bool is_silhouette = false;
5266  if (orig_col) {
5267  if (!ec->silhouette_backdrop) {
5268  is_silhouette = true;
5269  }
5271  ec->silhouette_backdrop)) {
5272  is_silhouette = true;
5273  }
5274  }
5275  else {
5276  if ((!orig_ob) && (!ec->silhouette_backdrop)) {
5277  is_silhouette = true;
5278  }
5279  }
5280 
5281  if ((silhouette_mode == LRT_SILHOUETTE_FILTER_INDIVIDUAL || orig_ob) &&
5282  ec->silhouette_backdrop != ec->object_ref) {
5283  is_silhouette = true;
5284  }
5285 
5286  if (inverse_silhouette) {
5287  is_silhouette = !is_silhouette;
5288  }
5289  if (!is_silhouette) {
5290  continue;
5291  }
5292  }
5293 
5294  /* Preserved: If we ever do asynchronous generation, this picked flag should be set here. */
5295  // ec->picked = 1;
5296 
5297  const int count = MOD_lineart_chain_count(ec);
5298  if (count < 2) {
5299  continue;
5300  }
5301 
5302  bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, color_idx, count, thickness, false);
5303 
5304  int i;
5305  LISTBASE_FOREACH_INDEX (LineartEdgeChainItem *, eci, &ec->chain, i) {
5306  bGPDspoint *point = &gps->points[i];
5307  mul_v3_m4v3(&point->x, gp_obmat_inverse, eci->gpos);
5308  point->pressure = 1.0f;
5309  point->strength = opacity;
5310  }
5311 
5313  gps->mat_nr = max_ii(material_nr, 0);
5314 
5315  if (source_vgname && vgname) {
5316  Object *eval_ob = DEG_get_evaluated_object(depsgraph, ec->object_ref);
5317  int gpdg = -1;
5318  if ((match_output || (gpdg = BKE_object_defgroup_name_index(gpencil_object, vgname)) >= 0)) {
5319  if (eval_ob && eval_ob->type == OB_MESH) {
5320  int dindex = 0;
5321  Mesh *me = BKE_object_get_evaluated_mesh(eval_ob);
5322  if (me->dvert) {
5324  if ((!source_vgname) || strstr(db->name, source_vgname) == db->name) {
5325  if (match_output) {
5326  gpdg = BKE_object_defgroup_name_index(gpencil_object, db->name);
5327  if (gpdg < 0) {
5328  continue;
5329  }
5330  }
5331  int sindex = 0, vindex;
5332  LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
5333  vindex = eci->index;
5334  if (vindex >= me->totvert) {
5335  break;
5336  }
5337  MDeformWeight *mdw = BKE_defvert_ensure_index(&me->dvert[vindex], dindex);
5338  MDeformWeight *gdw = BKE_defvert_ensure_index(&gps->dvert[sindex], gpdg);
5339 
5340  float use_weight = mdw->weight;
5341  if (invert_input) {
5342  use_weight = 1 - use_weight;
5343  }
5344  gdw->weight = MAX2(use_weight, gdw->weight);
5345 
5346  sindex++;
5347  }
5348  }
5349  dindex++;
5350  }
5351  }
5352  }
5353  }
5354  }
5355 
5356  if (G.debug_value == 4000) {
5358  }
5359  BKE_gpencil_stroke_geometry_update(gpencil_object->data, gps);
5360  stroke_count++;
5361  }
5362 
5363  if (G.debug_value == 4000) {
5364  printf("LRT: Generated %d strokes.\n", stroke_count);
5365  }
5366 }
5367 
5370  Object *ob,
5371  bGPDlayer *gpl,
5372  bGPDframe *gpf,
5373  int8_t source_type,
5374  void *source_reference,
5375  int level_start,
5376  int level_end,
5377  int mat_nr,
5378  int16_t edge_types,
5379  uchar mask_switches,
5380  uchar material_mask_bits,
5381  uchar intersection_mask,
5382  int16_t thickness,
5383  float opacity,
5384  uchar shadow_selection,
5385  uchar silhouette_mode,
5386  const char *source_vgname,
5387  const char *vgname,
5388  int modifier_flags,
5389  int modifier_calculation_flags)
5390 {
5391 
5392  if (!gpl || !gpf || !ob) {
5393  return;
5394  }
5395 
5396  Object *source_object = NULL;
5397  Collection *source_collection = NULL;
5398  int16_t use_types = edge_types;
5399  if (source_type == LRT_SOURCE_OBJECT) {
5400  if (!source_reference) {
5401  return;
5402  }
5403  source_object = (Object *)source_reference;
5404  }
5405  else if (source_type == LRT_SOURCE_COLLECTION) {
5406  if (!source_reference) {
5407  return;
5408  }
5409  source_collection = (Collection *)source_reference;
5410  }
5411 
5412  float gp_obmat_inverse[4][4];
5413  invert_m4_m4(gp_obmat_inverse, ob->obmat);
5415  depsgraph,
5416  ob,
5417  gp_obmat_inverse,
5418  gpl,
5419  gpf,
5420  level_start,
5421  level_end,
5422  mat_nr,
5423  source_object,
5424  source_collection,
5425  use_types,
5426  mask_switches,
5427  material_mask_bits,
5428  intersection_mask,
5429  thickness,
5430  opacity,
5431  shadow_selection,
5432  silhouette_mode,
5433  source_vgname,
5434  vgname,
5435  modifier_flags,
5436  modifier_calculation_flags);
5437 }
Camera data-block and utility functions.
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y)
Definition: camera.c:236
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey)
Definition: camera.c:246
bool BKE_collection_has_object_recursive_instanced(struct Collection *collection, struct Object *ob)
Definition: collection.c:931
bool BKE_collection_has_object(struct Collection *collection, const struct Object *ob)
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_active_layer_index(const struct CustomData *data, int type)
int CustomData_get_layer_index(const struct CustomData *data, int type)
support for deformation groups and hooks.
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps)
Definition: gpencil.c:1891
struct bGPDstroke * BKE_gpencil_stroke_add(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, bool insert_at_head)
Definition: gpencil.c:792
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps)
void BKE_id_free(struct Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get_eval(struct Object *ob, short act)
Definition: material.c:707
void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh, const struct MLoopTri *looptri, int r_edges[3])
struct Mesh * BKE_mesh_new_from_object(struct Depsgraph *depsgraph, struct Object *object, bool preserve_all_data_layers, bool preserve_origindex)
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3])
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
General operations, lookup, etc. for blender objects.
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3])
Definition: object.cc:3645
struct Mesh * BKE_object_get_evaluated_mesh(const struct Object *object)
@ OB_VISIBLE_SELF
Definition: BKE_object.h:150
int BKE_object_visibility(const struct Object *ob, int dag_eval_mode)
int BKE_render_num_threads(const struct RenderData *r)
bool BKE_scene_camera_switch_update(struct Scene *scene)
Definition: scene.cc:2295
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
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
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
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 BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
MINLINE double ratiod(double min, double max, double pos)
MINLINE int max_ii(int a, int b)
#define M_PI
Definition: BLI_math_base.h:20
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3])
Definition: math_matrix.c:758
void mul_v3_m4v3_db(double r[3], const double mat[4][4], const double vec[3])
Definition: math_matrix.c:749
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void unit_m4_db(double m[4][4])
Definition: math_matrix.c:57
void copy_m4d_m4(double m1[4][4], const float m2[4][4])
Definition: math_matrix.c:180
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B[4][4])
Definition: math_matrix.c:344
void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3])
Definition: math_matrix.c:810
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void transpose_m4(float R[4][4])
Definition: math_matrix.c:1377
void copy_m4_m4_db(double m1[4][4], const double m2[4][4])
Definition: math_matrix.c:82
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:800
float focallength_to_fov(float focal_length, float sensor)
MINLINE double normalize_v3_db(double n[3])
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 normalize_v3(float r[3])
MINLINE void mul_v3db_db(double r[3], double f)
MINLINE void add_v3_v3_db(double r[3], const double a[3])
MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3db_v3fl(double r[3], const float a[3])
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3])
MINLINE void copy_v3_v3_db(double r[3], const double a[3])
void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], double t)
Definition: math_vector.c:1314
MINLINE void sub_v3_v3v3_db(double r[3], const double a[3], const double b[3])
MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2])
unsigned char uchar
Definition: BLI_sys_types.h:70
@ TASK_PRIORITY_HIGH
Definition: BLI_task.h:57
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition: task_pool.cc:480
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition: task_pool.cc:390
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:440
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:459
void BLI_spin_init(SpinLock *spin)
Definition: threads.cc:419
void BLI_spin_unlock(SpinLock *spin)
Definition: threads.cc:452
void BLI_spin_lock(SpinLock *spin)
Definition: threads.cc:433
void BLI_spin_end(SpinLock *spin)
Definition: threads.cc:467
#define INIT_MINMAX(min, max)
#define MAX3(a, b, c)
#define MIN3(a, b, c)
#define SWAP(type, a, b)
#define UNUSED(x)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define LIKELY(x)
typedef double(DMatrix)[4][4]
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
eEvaluationMode
Definition: DEG_depsgraph.h:44
@ DAG_EVAL_RENDER
Definition: DEG_depsgraph.h:46
#define DEG_OBJECT_ITER_END
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, flag_)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_VISIBLE
@ DEG_ITER_OBJECT_FLAG_DUPLI
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ CAMERA_SENSOR_FIT_HOR
@ CAMERA_SENSOR_FIT_VERT
@ CAM_PERSP
@ CAM_ORTHO
Object groups, one object can be in many groups at once.
@ COLLECTION_LRT_EXCLUDE
@ COLLECTION_LRT_INTERSECTION_ONLY
@ COLLECTION_LRT_FORCE_INTERSECTION
@ COLLECTION_LRT_OCCLUSION_ONLY
@ COLLECTION_LRT_NO_INTERSECTION
@ COLLECTION_HIDE_RENDER
@ COLLECTION_HIDE_VIEWPORT
@ COLLECTION_LRT_USE_INTERSECTION_MASK
@ COLLECTION_LRT_USE_INTERSECTION_PRIORITY
@ CD_FREESTYLE_EDGE
@ CD_FREESTYLE_FACE
@ LRT_GPENCIL_MATERIAL_MASK_ENABLE
@ LRT_GPENCIL_INTERSECTION_MATCH
@ LRT_GPENCIL_MATERIAL_MASK_MATCH
@ LRT_SILHOUETTE_FILTER_INDIVIDUAL
@ LRT_GPENCIL_INVERT_COLLECTION
@ LRT_GPENCIL_INVERT_SILHOUETTE_FILTER
@ LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA
@ LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES
@ LRT_SHADOW_FILTER_ILLUMINATED
@ LRT_SHADOW_FILTER_SHADED
#define LA_SUN
@ LRT_EDGE_FLAG_INHIBIT
@ LRT_EDGE_FLAG_SHADOW_FACING_LIGHT
@ LRT_EDGE_FLAG_MATERIAL
@ LRT_EDGE_FLAG_CREASE
@ LRT_EDGE_FLAG_PROJECTED_SHADOW
@ LRT_EDGE_FLAG_CONTOUR_SECONDARY
@ LRT_EDGE_FLAG_LOOSE
@ LRT_EDGE_FLAG_INTERSECTION
@ LRT_EDGE_FLAG_LIGHT_CONTOUR
@ LRT_EDGE_FLAG_CHAIN_PICKED
@ LRT_EDGE_FLAG_CONTOUR
@ LRT_EDGE_FLAG_NEXT_IS_DUPLICATION
@ LRT_EDGE_FLAG_EDGE_MARK
@ LRT_GPENCIL_INVERT_SOURCE_VGROUP
@ LRT_EVERYTHING_AS_CONTOUR
@ LRT_USE_CREASE_ON_SMOOTH_SURFACES
@ LRT_ALLOW_OVERLAP_EDGE_TYPES
@ LRT_FILTER_FACE_MARK
@ LRT_USE_IMAGE_BOUNDARY_TRIMMING
@ LRT_USE_CUSTOM_CAMERA
@ LRT_INTERSECTION_AS_CONTOUR
@ LRT_ALLOW_OVERLAPPING_EDGES
@ LRT_CHAIN_LOOSE_EDGES
@ LRT_GPENCIL_MATCH_OUTPUT_VGROUP
@ LRT_ALLOW_DUPLI_OBJECTS
@ LRT_FILTER_FACE_MARK_INVERT
@ LRT_USE_BACK_FACE_CULLING
@ LRT_LOOSE_AS_CONTOUR
@ LRT_CHAIN_GEOMETRY_SPACE
@ LRT_USE_CREASE_ON_SHARP_EDGES
@ LRT_FILTER_FACE_MARK_KEEP_CONTOUR
@ LRT_ALLOW_CLIPPING_BOUNDARIES
@ LRT_FILTER_FACE_MARK_BOUNDARIES
@ LRT_CHAIN_PRESERVE_DETAILS
@ LRT_MATERIAL_CUSTOM_INTERSECTION_PRIORITY
@ LRT_MATERIAL_MASK_ENABLED
@ MA_BL_CULL_BACKFACE
@ ME_AUTOSMOOTH
@ FREESTYLE_EDGE_MARK
@ ME_SMOOTH
@ FREESTYLE_FACE_MARK
@ ME_LOOSEEDGE
@ ME_SHARP
@ OB_MBALL
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_LAMP
@ OB_MESH
@ OB_CURVES_LEGACY
@ OBJECT_LRT_OWN_INTERSECTION_PRIORITY
@ OBJECT_LRT_OWN_CREASE
@ OBJECT_LRT_INCLUDE
@ OBJECT_LRT_NO_INTERSECTION
@ OBJECT_LRT_EXCLUDE
@ OBJECT_LRT_INHERIT
@ OBJECT_LRT_OCCLUSION_ONLY
@ OBJECT_LRT_INTERSECTION_ONLY
@ OBJECT_LRT_FORCE_INTERSECTION
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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_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 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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define LRT_TILE_EDGE_COUNT_INITIAL
Definition: MOD_lineart.h:258
#define LRT_DOUBLE_CLOSE_ENOUGH(a, b)
Definition: MOD_lineart.h:588
#define LRT_SHADOW_MASK_INHIBITED
Definition: MOD_lineart.h:451
#define LRT_SHADOW_MASK_UNDEFINED
Definition: MOD_lineart.h:447
#define LRT_OBINDEX_LOWER
Definition: MOD_lineart.h:481
BLI_INLINE int lineart_intersect_seg_seg(const double a1[2], const double a2[2], const double b1[2], const double b2[2], double *r_ratio, bool *r_aligned)
Definition: MOD_lineart.h:608
#define LRT_OBINDEX_SHIFT
Definition: MOD_lineart.h:480
#define LRT_SHADOW_MASK_ILLUMINATED_SHAPE
Definition: MOD_lineart.h:454
#define LRT_LIGHT_CONTOUR_TARGET
Definition: MOD_lineart.h:486
#define DBL_TRIANGLE_LIM
Definition: MOD_lineart.h:431
#define LRT_SHADOW_MASK_ENCLOSED_SHAPE
Definition: MOD_lineart.h:450
#define LRT_SHADOW_TEST_SHAPE_BITS
Definition: MOD_lineart.h:456
#define LRT_OBINDEX_HIGHER
Definition: MOD_lineart.h:482
@ LRT_TILE_RECURSIVE_PERSPECTIVE
Definition: MOD_lineart.h:252
@ LRT_TILE_RECURSIVE_ORTHO
Definition: MOD_lineart.h:254
#define LRT_SHADOW_MASK_ILLUMINATED
Definition: MOD_lineart.h:448
#define LRT_TILE_SPLITTING_TRIANGLE_LIMIT
Definition: MOD_lineart.h:257
@ LRT_TRIANGLE_NO_INTERSECTION
Definition: MOD_lineart.h:442
@ LRT_CULL_GENERATED
Definition: MOD_lineart.h:440
@ LRT_CULL_DISCARD
Definition: MOD_lineart.h:439
@ LRT_TRIANGLE_MAT_BACK_FACE_CULLING
Definition: MOD_lineart.h:443
@ LRT_TRIANGLE_INTERSECTION_ONLY
Definition: MOD_lineart.h:441
@ LRT_TRIANGLE_FORCE_INTERSECTION
Definition: MOD_lineart.h:444
@ LRT_CULL_USED
Definition: MOD_lineart.h:438
#define LRT_THREAD_EDGE_COUNT
Definition: MOD_lineart.h:465
#define LRT_SHADOW_MASK_SHADED
Definition: MOD_lineart.h:449
@ LRT_ELEMENT_NO_INTERSECTION
Definition: MOD_lineart.h:74
@ LRT_ELEMENT_BORDER_ONLY
Definition: MOD_lineart.h:73
@ LRT_ELEMENT_INTERSECTION_DATA
Definition: MOD_lineart.h:75
@ LRT_ELEMENT_IS_ADDITIONAL
Definition: MOD_lineart.h:72
struct LineartTriangle LineartTriangle
#define LRT_EDGE_IDENTIFIER(obi, e)
Definition: MOD_lineart.h:483
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
Platform independent time functions.
volatile int lock
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define cosf(x)
Definition: cuda/compat.h:101
StackEntry * from
Scene scene
const Depsgraph * depsgraph
uint col
BLI_INLINE float fb(float length, float L)
int count
void MOD_lineart_chain_connect(LineartData *ld)
void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
void MOD_lineart_chain_clip_at_border(LineartData *ld)
int MOD_lineart_chain_count(const LineartEdgeChain *ec)
void MOD_lineart_finalize_chains(LineartData *ld)
void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld)
void MOD_lineart_chain_feature_lines(LineartData *ld)
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
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)
void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
struct EdgeNeighborData EdgeNeighborData
static void lineart_bounding_area_line_add(LineartBoundingArea *ba, LineartEdge *e)
Definition: lineart_cpu.c:359
void MOD_lineart_clear_cache(struct LineartCache **lc)
Definition: lineart_cpu.c:3539
static void lineart_object_load_single_instance(LineartData *ld, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *ref_ob, float use_mat[4][4], bool is_render, LineartObjectLoadTaskInfo *olti, int thread_count, int obindex)
Definition: lineart_cpu.c:2454
static void lineart_bounding_areas_connect_recursive(LineartData *ld, LineartBoundingArea *root)
Definition: lineart_cpu.c:3901
static LineartTriangle * lineart_triangle_from_index(LineartData *ld, LineartTriangle *rt_array, int index)
Definition: lineart_cpu.c:1461
static int lineart_triangle_size_get(LineartData *ld)
Definition: lineart_cpu.c:3691
void lineart_main_occlusion_begin(LineartData *ld)
Definition: lineart_cpu.c:464
static LineartBoundingArea * lineart_get_bounding_area(LineartData *ld, double x, double y)
Definition: lineart_cpu.c:4470
#define INTERSECT_JUST_SMALLER(is, order, num, index)
Definition: lineart_cpu.c:2768
static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count)
Definition: lineart_cpu.c:3351
#define LRT_MESH_EDGE_TYPES_COUNT
Definition: lineart_cpu.c:1443
#define RELINK_EDGE(e_num, new_tri)
struct VertData VertData
static void lineart_destroy_isec_thread(LineartIsecData *d)
Definition: lineart_cpu.c:3370
static bool lineart_triangle_intersect_math(LineartTriangle *tri, LineartTriangle *t2, double *v1, double *v2)
Definition: lineart_cpu.c:3207
static bool lineart_bounding_area_triangle_intersect(LineartData *fb, LineartTriangle *tri, LineartBoundingArea *ba, bool *r_triangle_vert_inside)
Definition: lineart_cpu.c:4064
void lineart_main_discard_out_of_frame_edges(LineartData *ld)
Definition: lineart_cpu.c:1389
void lineart_main_get_view_vector(LineartData *ld)
Definition: lineart_cpu.c:3437
void lineart_main_link_lines(LineartData *ld)
Definition: lineart_cpu.c:4284
void lineart_main_load_geometries(Depsgraph *depsgraph, Scene *scene, Object *camera, LineartData *ld, bool allow_duplicates, bool do_shadow_casting, ListBase *shadow_elns)
Definition: lineart_cpu.c:2524
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
Definition: lineart_cpu.c:3517
bool lineart_edge_from_triangle(const LineartTriangle *tri, const LineartEdge *e, bool allow_overlapping_edges)
Definition: lineart_cpu.c:2708
static LineartEdgeNeighbor * lineart_build_edge_neighbor(Mesh *me, int total_edges)
Definition: lineart_cpu.c:1941
static bool lineart_edge_match(LineartTriangle *tri, LineartEdge *e, int v1, int v2)
Definition: lineart_cpu.c:729
static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData *to_be_joined)
Definition: lineart_cpu.c:1726
static void lineart_create_edges_from_isec_data(LineartIsecData *d)
Definition: lineart_cpu.c:4552
static void lineart_edge_neighbor_init_task(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
Definition: lineart_cpu.c:1918
static void lineart_add_isec_thread(LineartIsecThread *th, const double *v1, const double *v2, LineartTriangle *tri1, LineartTriangle *tri2)
Definition: lineart_cpu.c:3280
struct LineartIsecThread LineartIsecThread
static bool lineart_triangle_2v_intersection_math(LineartVert *v1, LineartVert *v2, LineartTriangle *tri, const double *last, double *rv)
Definition: lineart_cpu.c:3167
static void lineart_load_tri_task(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
Definition: lineart_cpu.c:1850
void lineart_main_bounding_areas_connect_post(LineartData *ld)
Definition: lineart_cpu.c:3911
static const int LRT_MESH_EDGE_TYPES[]
Definition: lineart_cpu.c:1434
static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartData *la_data, ListBase *shadow_elns)
Definition: lineart_cpu.c:1978
static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
Definition: lineart_cpu.c:1743
#define LRT_VERT_OUT_OF_BOUND(v)
static void lineart_destroy_render_data(LineartData *ld)
Definition: lineart_cpu.c:3502
void lineart_main_add_triangles(LineartData *ld)
Definition: lineart_cpu.c:4663
static bool lineart_triangle_share_edge(const LineartTriangle *l, const LineartTriangle *r)
Definition: lineart_cpu.c:3091
LineartBoundingArea * MOD_lineart_get_bounding_area(LineartData *ld, double x, double y)
Definition: lineart_cpu.c:4511
static uchar lineart_intersection_mask_check(Collection *c, Object *ob)
Definition: lineart_cpu.c:2302
void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
Definition: lineart_cpu.c:1774
static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1[3], double v2[3])
Definition: lineart_cpu.c:616
static int lineart_occlusion_make_task_info(LineartData *ld, LineartRenderTaskInfo *rti)
Definition: lineart_cpu.c:421
static void lineart_loose_data_reallocate(LooseEdgeData *loose_data, int count)
Definition: lineart_cpu.c:1715
#define LRT_CULL_DECIDE_INSIDE
void lineart_main_clear_linked_edges(LineartData *ld)
Definition: lineart_cpu.c:4271
static void lineart_triangle_adjacent_assign(LineartTriangle *tri, LineartTriangleAdjacent *tri_adj, LineartEdge *e)
Definition: lineart_cpu.c:1826
static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba)
Definition: lineart_cpu.c:352
static void lineart_free_bounding_area_memories(LineartData *ld)
Definition: lineart_cpu.c:4220
static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti)
Definition: lineart_cpu.c:446
LineartBoundingArea * lineart_bounding_area_next(LineartBoundingArea *this, double *fbcoord1, double *fbcoord2, double x, double y, double k, int positive_x, int positive_y, double *next_x, double *next_y)
Definition: lineart_cpu.c:4732
static bool lineart_triangle_edge_image_space_occlusion(const LineartTriangle *tri, const LineartEdge *e, const double *override_camera_loc, const bool override_cam_is_persp, const bool allow_overlapping_edges, const double m_view_projection[4][4], const double camera_dir[3], const float cam_shift_x, const float cam_shift_y, double *from, double *to)
Definition: lineart_cpu.c:2800
static int lineart_edge_type_duplication_count(int eflag)
Definition: lineart_cpu.c:1445
struct LooseEdgeData LooseEdgeData
struct LineartIsecData LineartIsecData
void lineart_main_cull_triangles(LineartData *ld, bool clip_far)
Definition: lineart_cpu.c:1211
static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), LineartIsecThread *th)
Definition: lineart_cpu.c:4520
static void lineart_bounding_area_split(LineartData *ld, LineartBoundingArea *root, int recursive_level)
Definition: lineart_cpu.c:3947
static void feat_data_sum_reduce(const void *__restrict UNUSED(userdata), void *__restrict chunk_join, void *__restrict chunk)
Definition: lineart_cpu.c:1490
void lineart_main_bounding_area_make_initial(LineartData *ld)
Definition: lineart_cpu.c:3696
static void lineart_add_edge_to_array_thread(LineartObjectInfo *obi, LineartEdge *e)
Definition: lineart_cpu.c:1793
static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata), void *__restrict chunk_join, void *__restrict chunk)
Definition: lineart_cpu.c:1765
struct LineartIsecSingle LineartIsecSingle
static void lineart_bounding_area_link_triangle(LineartData *ld, LineartBoundingArea *root_ba, LineartTriangle *tri, double l_r_u_b[4], int recursive, int recursive_level, bool do_intersection, struct LineartIsecThread *th)
Definition: lineart_cpu.c:4115
struct TriData TriData
#define INCREASE_EDGE
static void lineart_mvert_transform_task(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
Definition: lineart_cpu.c:1420
#define LRT_ISECT_TRIANGLE_PER_THREAD
Definition: lineart_cpu.c:3306
LineartBoundingArea * lineart_edge_first_bounding_area(LineartData *ld, double *fbcoord1, double *fbcoord2)
Definition: lineart_cpu.c:4698
static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig)
Definition: lineart_cpu.c:710
static bool lineart_get_triangle_bounding_areas(LineartData *ld, LineartTriangle *tri, int *rowbegin, int *rowend, int *colbegin, int *colend)
Definition: lineart_cpu.c:4357
static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri, LineartBoundingArea *ba, LineartIsecThread *th, int up_to)
Definition: lineart_cpu.c:3379
static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool), LineartObjectLoadTaskInfo *olti)
Definition: lineart_cpu.c:2294
static void lineart_triangle_set_cull_flag(LineartTriangle *tri, uchar flag)
Definition: lineart_cpu.c:722
static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartObjectInfo *obi)
Definition: lineart_cpu.c:1812
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModifierData *lmd, LineartCache **cached_result, bool enable_stroke_depth_offset)
Definition: lineart_cpu.c:4957
void lineart_main_free_adjacent_data(LineartData *ld)
Definition: lineart_cpu.c:1346
static LineartEdgeSegment * lineart_give_segment(LineartData *ld)
Definition: lineart_cpu.c:129
static void lineart_occlusion_single_line(LineartData *ld, LineartEdge *e, int thread_id)
Definition: lineart_cpu.c:379
static void lineart_triangle_cull_single(LineartData *ld, LineartTriangle *tri, int in0, int in1, int in2, double cam_pos[3], double view_dir[3], bool allow_boundaries, double m_view_projection[4][4], Object *ob, int *r_v_count, int *r_e_count, int *r_t_count, LineartElementLinkNode *v_eln, LineartElementLinkNode *e_eln, LineartElementLinkNode *t_eln)
Definition: lineart_cpu.c:748
struct EdgeFeatData EdgeFeatData
static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive)
Definition: lineart_cpu.c:4205
#define REMOVE_TRIANGLE_EDGE
static bool lineart_point_inside_triangle(const double v[2], const double v0[2], const double v1[2], const double v2[2])
Definition: lineart_cpu.c:491
static void lineart_end_bounding_area_recursive(LineartBoundingArea *ba)
Definition: lineart_cpu.c:3467
static void lineart_bounding_area_link_edge(LineartData *ld, LineartBoundingArea *root_ba, LineartEdge *e)
Definition: lineart_cpu.c:4229
#define LRT_PARALLEL(index)
Definition: lineart_cpu.c:2776
static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
Definition: lineart_cpu.c:1499
static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_list, LineartObjectInfo *obi, int thread_count, int this_face_count)
Definition: lineart_cpu.c:2392
static LineartCache * lineart_init_cache(void)
Definition: lineart_cpu.c:3533
LineartBoundingArea * MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y)
Definition: lineart_cpu.c:4442
void lineart_destroy_render_data_keep_init(LineartData *ld)
Definition: lineart_cpu.c:3477
static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2])
Definition: lineart_cpu.c:522
static uchar lineart_intersection_priority_check(Collection *c, Object *ob)
Definition: lineart_cpu.c:2320
#define INTERSECT_JUST_GREATER(is, order, num, index)
Definition: lineart_cpu.c:2760
struct LineartEdgeNeighbor LineartEdgeNeighbor
static bool lineart_schedule_new_triangle_task(LineartIsecThread *th)
Definition: lineart_cpu.c:3308
static void lineart_discard_duplicated_edges(LineartEdge *old_e)
Definition: lineart_cpu.c:735
#define LRT_TRI_SAME_POINT(tri, i, pt)
static void lineart_clear_linked_edges_recursive(LineartData *ld, LineartBoundingArea *root_ba)
Definition: lineart_cpu.c:4256
void lineart_edge_cut(LineartData *ld, LineartEdge *e, double start, double end, uchar material_mask_bits, uchar mat_occlusion, uint32_t shadow_bits)
Definition: lineart_cpu.c:150
static LineartVert * lineart_triangle_share_point(const LineartTriangle *l, const LineartTriangle *r)
Definition: lineart_cpu.c:3134
static LineartElementLinkNode * lineart_memory_get_vert_space(LineartData *ld)
Definition: lineart_cpu.c:676
static int lineart_usage_check(Collection *c, Object *ob, bool is_render)
Definition: lineart_cpu.c:2344
static bool lineart_get_edge_bounding_areas(LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend)
Definition: lineart_cpu.c:4397
static LineartElementLinkNode * lineart_memory_get_triangle_space(LineartData *ld)
Definition: lineart_cpu.c:657
static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es)
Definition: lineart_cpu.c:116
LineartPointTri
Definition: lineart_cpu.c:564
@ LRT_INSIDE_TRIANGLE
Definition: lineart_cpu.c:567
@ LRT_ON_TRIANGLE
Definition: lineart_cpu.c:566
@ LRT_OUTSIDE_TRIANGLE
Definition: lineart_cpu.c:565
void lineart_main_perspective_division(LineartData *ld)
Definition: lineart_cpu.c:1364
static void lineart_main_remove_unused_lines_from_tiles(LineartData *ld)
Definition: lineart_cpu.c:4347
static void lineart_bounding_areas_connect_new(LineartData *ld, LineartBoundingArea *root)
Definition: lineart_cpu.c:3761
static void lineart_identify_loose_edges(void *__restrict UNUSED(userdata), const int i, const TaskParallelTLS *__restrict tls)
Definition: lineart_cpu.c:1753
#define INTERSECT_SORT_MIN_TO_MAX_3(ia, ib, ic, lst)
Definition: lineart_cpu.c:2750
void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count)
Definition: lineart_cpu.c:1800
#define SELECT_EDGE(e_num, v1_link, v2_link, new_tri)
static void lineart_main_remove_unused_lines_recursive(LineartBoundingArea *ba, uint8_t max_occlusion)
Definition: lineart_cpu.c:4301
BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, LineartTriangle *tri)
Definition: lineart_cpu.c:346
static void lineart_gpencil_generate(LineartCache *cache, Depsgraph *depsgraph, Object *gpencil_object, float(*gp_obmat_inverse)[4], bGPDlayer *UNUSED(gpl), bGPDframe *gpf, int level_start, int level_end, int material_nr, Object *source_object, Collection *source_collection, int types, uchar mask_switches, uchar material_mask_bits, uchar intersection_mask, int16_t thickness, float opacity, uchar shaodow_selection, uchar silhouette_mode, const char *source_vgname, const char *vgname, int modifier_flags, int modifier_calculation_flags)
Definition: lineart_cpu.c:5142
static bool lineart_triangle_get_other_verts(const LineartTriangle *tri, const LineartVert *vt, LineartVert **l, LineartVert **r)
Definition: lineart_cpu.c:2685
struct EdgeFeatReduceData EdgeFeatReduceData
void MOD_lineart_gpencil_generate(LineartCache *cache, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, int8_t source_type, void *source_reference, int level_start, int level_end, int mat_nr, int16_t edge_types, uchar mask_switches, uchar material_mask_bits, uchar intersection_mask, int16_t thickness, float opacity, uchar shadow_selection, uchar silhouette_mode, const char *source_vgname, const char *vgname, int modifier_flags, int modifier_calculation_flags)
Definition: lineart_cpu.c:5368
static LineartElementLinkNode * lineart_memory_get_edge_space(LineartData *ld)
Definition: lineart_cpu.c:693
static LineartData * lineart_create_render_buffer(Scene *scene, LineartGpencilModifierData *lmd, Object *camera, Object *active_camera, LineartCache *lc)
Definition: lineart_cpu.c:3549
#define LRT_CULL_ENSURE_MEMORY
static bool lineart_bounding_area_edge_intersect(LineartData *UNUSED(fb), const double l[2], const double r[2], LineartBoundingArea *ba)
Definition: lineart_cpu.c:4023
static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[2], double v2[2])
Definition: lineart_cpu.c:574
#define LRT_ISEC(index)
Definition: lineart_cpu.c:2775
static bool lineart_geometry_check_visible(double model_view_proj[4][4], double shift_x, double shift_y, Mesh *use_mesh)
Definition: lineart_cpu.c:2411
#define LRT_GUARD_NOT_FOUND
void lineart_register_intersection_shadow_cuts(struct LineartData *ld, struct ListBase *shadow_elns)
bool lineart_main_try_generate_shadow(struct Depsgraph *depsgraph, struct Scene *scene, struct LineartData *original_ld, struct LineartGpencilModifierData *lmd, struct LineartStaticMemPool *shadow_data_pool, struct LineartElementLinkNode **r_veln, struct LineartElementLinkNode **r_eeln, struct ListBase *r_calculated_edges_eln_list, struct LineartData **r_shadow_ld_if_reproject)
void * lineart_list_append_pointer_pool_sized(ListBase *h, struct LineartStaticMemPool *smp, void *data, int size)
Definition: lineart_util.c:35
#define LRT_BOUND_AREA_CROSSES(b1, b2)
#define LRT_EDGE_BA_MARCHING_BEGIN(fb1, fb2)
void * lineart_mem_acquire_thread(struct LineartStaticMemPool *smp, size_t size)
Definition: lineart_util.c:119
#define LRT_EDGE_BA_MARCHING_NEXT(fb1, fb2)
LineartEdge * lineart_find_matching_edge(struct LineartElementLinkNode *shadow_eln, uint64_t edge_identifier)
void lineart_register_shadow_cuts(struct LineartData *ld, struct LineartEdge *e, struct LineartEdge *shadow_edge)
#define LRT_EDGE_BA_MARCHING_END
void lineart_main_make_enclosed_shapes(struct LineartData *ld, struct LineartData *shadow_ld)
#define LRT_ITER_ALL_LINES_END
void lineart_count_and_print_render_buffer_memory(struct LineartData *ld)
Definition: lineart_util.c:208
void * lineart_list_append_pointer_pool_thread(ListBase *h, struct LineartStaticMemPool *smp, void *data)
Definition: lineart_util.c:49
void lineart_matrix_perspective_44d(double(*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax)
Definition: lineart_util.c:157
#define LRT_BA_ROWS
void lineart_list_remove_pointer_item_no_free(ListBase *h, LinkData *lip)
Definition: lineart_util.c:86
#define LRT_ITER_ALL_LINES_BEGIN
void lineart_main_transform_and_add_shadow(struct LineartData *ld, struct LineartElementLinkNode *veln, struct LineartElementLinkNode *eeln)
void * lineart_list_append_pointer_pool_sized_thread(ListBase *h, LineartStaticMemPool *smp, void *data, int size)
Definition: lineart_util.c:60
LineartElementLinkNode * lineart_find_matching_eln(struct ListBase *shadow_elns, int obindex)
void lineart_mem_destroy(struct LineartStaticMemPool *smp)
Definition: lineart_util.c:139
void * lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size)
Definition: lineart_util.c:104
void * lineart_list_append_pointer_pool(ListBase *h, struct LineartStaticMemPool *smp, void *data)
Definition: lineart_util.c:24
void lineart_matrix_ortho_44d(double(*mProjection)[4], double xMin, double xMax, double yMin, double yMax, double zMin, double zMax)
Definition: lineart_util.c:189
static char ** types
Definition: makesdna.c:67
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
static ulong * next
#define RB
#define LB
#define G(x, y, z)
static unsigned c
Definition: RandGen.cpp:83
static double B1(double u)
Definition: FitCurve.cpp:304
static unsigned a[3]
Definition: RandGen.cpp:78
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
static const pxr::TfToken opacity("opacity", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
signed short int16_t
Definition: stdint.h:76
unsigned short uint16_t
Definition: stdint.h:79
unsigned int uint32_t
Definition: stdint.h:80
unsigned char uint8_t
Definition: stdint.h:78
unsigned __int64 uint64_t
Definition: stdint.h:90
signed char int8_t
Definition: stdint.h:75
struct BMVert * v
Definition: bmesh_class.h:153
float vec[8][3]
float clip_end
char sensor_fit
float sensor_y
float lens
float sensor_x
float clip_start
float ortho_scale
int freestyle_edge_index
Definition: lineart_cpu.c:1482
bool use_freestyle_face
Definition: lineart_cpu.c:1479
LineartEdgeNeighbor * edge_nabr
Definition: lineart_cpu.c:1483
Object * ob_eval
Definition: lineart_cpu.c:1473
bool use_freestyle_edge
Definition: lineart_cpu.c:1481
LineartVert * v_array
Definition: lineart_cpu.c:1476
const MLoopTri * mlooptri
Definition: lineart_cpu.c:1474
LineartTriangle * tri_array
Definition: lineart_cpu.c:1475
bool use_auto_smooth
Definition: lineart_cpu.c:1478
int freestyle_face_index
Definition: lineart_cpu.c:1480
LineartData * ld
Definition: lineart_cpu.c:1471
float crease_threshold
Definition: lineart_cpu.c:1477
LineartAdjacentEdge * adj_e
Definition: lineart_cpu.c:1913
MLoopTri * mlooptri
Definition: lineart_cpu.c:1914
LineartEdgeNeighbor * edge_nabr
Definition: lineart_cpu.c:1912
struct ID * orig_id
Definition: DNA_ID.h:419
struct LineartBoundingArea * child
Definition: MOD_lineart.h:551
struct LineartEdge ** linked_lines
Definition: MOD_lineart.h:568
uint32_t triangle_count
Definition: MOD_lineart.h:560
uint32_t insider_triangle_count
Definition: MOD_lineart.h:564
uint32_t max_line_count
Definition: MOD_lineart.h:563
struct LineartTriangle ** linked_triangles
Definition: MOD_lineart.h:567
uint32_t max_triangle_count
Definition: MOD_lineart.h:561
ListBase shadow_elns
Definition: MOD_lineart.h:425
ListBase chains
Definition: MOD_lineart.h:421
LineartStaticMemPool chain_data_pool
Definition: MOD_lineart.h:417
uint16_t all_enabled_edge_types
Definition: MOD_lineart.h:428
LineartStaticMemPool shadow_data_pool
Definition: MOD_lineart.h:418
float cam_obmat_secondary[4][4]
Definition: MOD_lineart.h:377
bool filter_face_mark_invert
Definition: MOD_lineart.h:360
double view_projection[4][4]
Definition: MOD_lineart.h:321
double view_vector[3]
Definition: MOD_lineart.h:390
double view_vector_secondary[3]
Definition: MOD_lineart.h:391
double camera_pos_secondary[3]
Definition: MOD_lineart.h:379
float chaining_image_threshold
Definition: MOD_lineart.h:385
bool filter_face_mark_keep_contour
Definition: MOD_lineart.h:362
double active_camera_pos[3]
Definition: MOD_lineart.h:380
double camera_pos[3]
Definition: MOD_lineart.h:378
float chain_smooth_tolerance
Definition: MOD_lineart.h:388
bool use_image_boundary_trimming
Definition: MOD_lineart.h:356
double view[4][4]
Definition: MOD_lineart.h:322
bool filter_face_mark_boundaries
Definition: MOD_lineart.h:361
bool allow_overlapping_edges
Definition: MOD_lineart.h:350
float angle_splitting_threshold
Definition: MOD_lineart.h:386
bool use_geometry_space_chain
Definition: MOD_lineart.h:355
float cam_obmat[4][4]
Definition: MOD_lineart.h:376
bool light_reference_available
Definition: MOD_lineart.h:370
ListBase vertex_buffer_pointers
Definition: MOD_lineart.h:308
ListBase line_buffer_pointers
Definition: MOD_lineart.h:309
ListBase triangle_adjacent_pointers
Definition: MOD_lineart.h:313
ListBase triangle_buffer_pointers
Definition: MOD_lineart.h:310
uint32_t initial_tile_count
Definition: MOD_lineart.h:302
struct LineartBoundingArea * initials
Definition: MOD_lineart.h:300
int thread_count
Definition: MOD_lineart.h:274
LineartStaticMemPool render_data_pool
Definition: MOD_lineart.h:277
struct LineartData::_conf conf
struct LineartData::_geom geom
struct LineartData::_qtree qtree
int isect_scheduled_up_to_index
Definition: MOD_lineart.h:395
ListBase chains
Definition: MOD_lineart.h:405
int sizeof_triangle
Definition: MOD_lineart.h:275
LineartElementLinkNode * isect_scheduled_up_to
Definition: MOD_lineart.h:394
ListBase wasted_cuts
Definition: MOD_lineart.h:407
SpinLock lock_task
Definition: MOD_lineart.h:410
LineartStaticMemPool * edge_data_pool
Definition: MOD_lineart.h:287
int scheduled_count
Definition: MOD_lineart.h:399
SpinLock lock_cuts
Definition: MOD_lineart.h:409
struct LineartPendingEdges pending_edges
Definition: MOD_lineart.h:398
LineartStaticMemPool * chain_data_pool
Definition: MOD_lineart.h:279
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
uint64_t edge_identifier
Definition: MOD_lineart.h:174
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
eLineArtElementNodeFlag flags
Definition: MOD_lineart.h:83
struct LineartElementLinkNode * next
Definition: MOD_lineart.h:79
LineartData * ld
Definition: lineart_cpu.c:77
LineartIsecThread * threads
Definition: lineart_cpu.c:78
LineartTriangle * tri1
Definition: lineart_cpu.c:54
LineartTriangle * tri2
Definition: lineart_cpu.c:54
LineartElementLinkNode * pending_from
Definition: lineart_cpu.c:61
LineartIsecSingle * array
Definition: lineart_cpu.c:67
LineartData * ld
Definition: lineart_cpu.c:73
LineartElementLinkNode * pending_to
Definition: lineart_cpu.c:62
LineartElementLinkNode * v_eln
Definition: MOD_lineart.h:496
struct Mesh * original_me
Definition: MOD_lineart.h:492
double model_view[4][4]
Definition: MOD_lineart.h:494
double normal[4][4]
Definition: MOD_lineart.h:495
struct LineartPendingEdges pending_edges
Definition: MOD_lineart.h:508
double model_view_proj[4][4]
Definition: MOD_lineart.h:493
struct Object * original_ob_eval
Definition: MOD_lineart.h:491
uint8_t override_intersection_mask
Definition: MOD_lineart.h:498
struct LineartObjectInfo * next
Definition: MOD_lineart.h:489
uint8_t intersection_priority
Definition: MOD_lineart.h:499
struct Object * original_ob
Definition: MOD_lineart.h:490
struct LineartData * ld
Definition: MOD_lineart.h:513
LineartObjectInfo * pending
Definition: MOD_lineart.h:516
LineartEdge ** array
Definition: MOD_lineart.h:266
struct LineartData * ld
Definition: MOD_lineart.h:468
struct LineartPendingEdges pending_edges
Definition: MOD_lineart.h:476
struct LineartEdge * e[3]
Definition: MOD_lineart.h:30
struct LineartEdge * testing_e[1]
Definition: MOD_lineart.h:68
struct LineartTriangle base
Definition: MOD_lineart.h:59
uint8_t material_mask_bits
Definition: MOD_lineart.h:39
uint8_t intersection_priority
Definition: MOD_lineart.h:48
uint8_t intersection_mask
Definition: MOD_lineart.h:40
uint32_t target_reference
Definition: MOD_lineart.h:46
struct LinkNode * intersecting_verts
Definition: MOD_lineart.h:55
double gn[3]
Definition: MOD_lineart.h:37
uint8_t mat_occlusion
Definition: MOD_lineart.h:41
struct LineartVert * v[3]
Definition: MOD_lineart.h:34
double fbcoord[4]
Definition: MOD_lineart.h:147
double gloc[3]
Definition: MOD_lineart.h:146
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
MEdge ** loose_array
Definition: lineart_cpu.c:1711
unsigned int v1
unsigned int v2
struct MLoopTri * array
unsigned int poly
unsigned int tri[3]
unsigned int v
short mat_nr
float co[3]
unsigned char mat_occlusion
unsigned char intersection_priority
unsigned char material_mask_bits
struct MaterialLineArt lineart
struct MLoopTri_Store looptris
struct BMEditMesh * edit_mesh
float smoothresh
struct MVert * mvert
uint16_t flag
struct MDeformVert * dvert
int totedge
ListBase vertex_group_names
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
CustomData pdata
int totpoly
CustomData edata
struct MPoly * mpoly
ustring name
Definition: graph/node.h:174
unsigned char intersection_priority
ObjectLineArt lineart
float obmat[4][4]
void * data
struct Collection * master_collection
struct RenderData r
struct Object * camera
TaskParallelReduceFunc func_reduce
Definition: BLI_task.h:181
size_t userdata_chunk_size
Definition: BLI_task.h:169
int lineart_triangle_size
Definition: lineart_cpu.c:1846
LineartTriangleAdjacent * tri_adj
Definition: lineart_cpu.c:1847
LineartVert * vert_arr
Definition: lineart_cpu.c:1844
LineartObjectInfo * ob_info
Definition: lineart_cpu.c:1842
const MLoopTri * mlooptri
Definition: lineart_cpu.c:1843
LineartTriangle * tri_arr
Definition: lineart_cpu.c:1845
double(* model_view_proj)[4]
Definition: lineart_cpu.c:1417
LineartVert * v_arr
Definition: lineart_cpu.c:1415
MVert * mvert
Definition: lineart_cpu.c:1414
double(* model_view)[4]
Definition: lineart_cpu.c:1416
bGPDspoint * points
struct MDeformVert * dvert
function< void(void)> TaskRunFunction
Definition: task.h:16
double PIL_check_seconds_timer(void)
Definition: time.c:64