Blender  V3.3
lineart_shadow.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MOD_gpencil_lineart.h"
8 #include "MOD_lineart.h"
9 
10 #include "lineart_intern.h"
11 
12 #include "BKE_global.h"
13 #include "BKE_gpencil_modifier.h"
14 #include "BKE_lib_id.h"
15 #include "BKE_material.h"
16 #include "BKE_object.h"
17 #include "BKE_scene.h"
18 #include "DEG_depsgraph_query.h"
19 #include "DNA_collection_types.h"
20 #include "DNA_gpencil_types.h"
21 #include "DNA_light_types.h"
22 #include "DNA_material_types.h"
23 #include "DNA_mesh_types.h"
24 #include "DNA_meshdata_types.h"
25 #include "DNA_modifier_types.h"
26 #include "DNA_scene_types.h"
27 #include "MEM_guardedalloc.h"
28 
29 #include "BLI_task.h"
30 #include "PIL_time.h"
31 
32 /* Shadow loading etc. ================== */
33 
35 {
36  LISTBASE_FOREACH (LineartElementLinkNode *, eln, shadow_elns) {
37  if (eln->obindex == obindex) {
38  return eln;
39  }
40  }
41  return NULL;
42 }
43 
45  uint64_t edge_identifier)
46 {
47  LineartEdge *elist = (LineartEdge *)shadow_eln->pointer;
48  for (int i = 0; i < shadow_eln->element_count; i++) {
49  if (elist[i].edge_identifier == edge_identifier) {
50  return &elist[i];
51  }
52  }
53  return NULL;
54 }
55 
57 {
58 
60  return false;
61  }
62  double view_vector[3];
63  double light_vector[3];
64  bool side_1_facing_light = false;
65  bool side_2_facing_light = false;
66  bool side_1_facing_camera = false;
67  if (ld->conf.cam_is_persp_secondary) {
68  sub_v3_v3v3_db(light_vector, ld->conf.camera_pos_secondary, e->v1->gloc);
69  }
70  else {
71  copy_v3_v3_db(light_vector, ld->conf.view_vector_secondary);
72  }
73  double dot_light_1 = dot_v3v3_db(light_vector, e->t1->gn);
74  side_1_facing_light = (dot_light_1 > 0);
75  if (e->t2) {
76  double dot_light_2 = dot_v3v3_db(light_vector, e->t2->gn);
77  side_2_facing_light = (dot_light_2 > 0);
78  }
79  else {
80  side_2_facing_light = !side_1_facing_light;
81  }
82 
83  if (ld->conf.cam_is_persp) {
84  sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, e->v1->gloc);
85  }
86  else {
87  copy_v3_v3_db(view_vector, ld->conf.view_vector);
88  }
89  double dot_view_1 = dot_v3v3_db(view_vector, e->t1->gn);
90  side_1_facing_camera = (dot_view_1 > 0);
91 
92  if ((side_1_facing_camera && (!side_1_facing_light) && side_2_facing_light) ||
93  ((!side_1_facing_camera) && side_1_facing_light && (!side_2_facing_light))) {
94  return true;
95  }
96  return false;
97 }
98 
99 /* Cuts the original edge based on the occlusion results under light-camera, if segment
100  * is occluded in light-camera, then that segment on the original edge must be shaded. */
102 {
103  LISTBASE_FOREACH (LineartEdgeSegment *, es, &shadow_edge->segments) {
104  /* Convert to view space cutting points. */
105  double la1 = es->ratio;
106  double la2 = es->next ? es->next->ratio : 1.0f;
107  la1 = la1 * e->v2->fbcoord[3] /
108  (e->v1->fbcoord[3] - la1 * (e->v1->fbcoord[3] - e->v2->fbcoord[3]));
109  la2 = la2 * e->v2->fbcoord[3] /
110  (e->v1->fbcoord[3] - la2 * (e->v1->fbcoord[3] - e->v2->fbcoord[3]));
111  unsigned char shadow_bits = (es->occlusion != 0) ? LRT_SHADOW_MASK_SHADED :
113 
115  shadow_bits == LRT_SHADOW_MASK_ILLUMINATED) {
116  shadow_bits = LRT_SHADOW_MASK_SHADED;
117  }
118 
119  lineart_edge_cut(ld, e, la1, la2, 0, 0, shadow_bits);
120  }
121 }
122 
124 {
125  if (!shadow_elns) {
126  return;
127  }
128 
129  LineartElementLinkNode *eln_isect_shadow = NULL;
130  LineartElementLinkNode *eln_isect_original = NULL;
131 
132  LISTBASE_FOREACH (LineartElementLinkNode *, eln, shadow_elns) {
133  if (eln->flags & LRT_ELEMENT_INTERSECTION_DATA) {
134  eln_isect_shadow = eln;
135  break;
136  }
137  }
139  if (eln->flags & LRT_ELEMENT_INTERSECTION_DATA) {
140  eln_isect_original = eln;
141  break;
142  }
143  }
144  if (!eln_isect_shadow || !eln_isect_original) {
145  return;
146  }
147 
148  /* Keeping it single threaded for now because a simple parallel_for could end up getting the same
149  * #shadow_e in different threads. */
150  for (int i = 0; i < eln_isect_original->element_count; i++) {
151  LineartEdge *e = &((LineartEdge *)eln_isect_original->pointer)[i];
152  LineartEdge *shadow_e = lineart_find_matching_edge(eln_isect_shadow,
153  (uint64_t)e->edge_identifier);
154  if (shadow_e) {
155  lineart_register_shadow_cuts(ld, e, shadow_e);
156  }
157  }
158 }
159 
160 /* Shadow computation part ================== */
161 
163 {
164  BLI_spin_lock(&ld->lock_cuts);
165 
166  /* See if there is any already allocated memory we can reuse. */
167  if (ld->wasted_shadow_cuts.first) {
170  memset(es, 0, sizeof(LineartShadowSegment));
171  return (LineartShadowSegment *)es;
172  }
174 
175  /* Otherwise allocate some new memory. */
177  sizeof(LineartShadowSegment));
178 }
179 
180 static void lineart_shadow_segment_slice_get(double *fb_co_1,
181  double *fb_co_2,
182  double *gloc_1,
183  double *gloc_2,
184  double ratio,
185  double at_1,
186  double at_2,
187  double *r_fb_co,
188  double *r_gloc)
189 {
190  double real_at = ((at_2 - at_1) == 0) ? 0 : ((ratio - at_1) / (at_2 - at_1));
191  double ga = fb_co_1[3] * real_at / (fb_co_2[3] * (1.0f - real_at) + fb_co_1[3] * real_at);
192  interp_v3_v3v3_db(r_fb_co, fb_co_1, fb_co_2, real_at);
193  r_fb_co[3] = interpd(fb_co_2[3], fb_co_1[3], ga);
194  interp_v3_v3v3_db(r_gloc, gloc_1, gloc_2, ga);
195 }
196 
220 static bool lineart_do_closest_segment(bool is_persp,
221  double *s1_fb_co_1,
222  double *s1_fb_co_2,
223  double *s2_fb_co_1,
224  double *s2_fb_co_2,
225  double *s1_gloc_1,
226  double *s1_gloc_2,
227  double *s2_gloc_1,
228  double *s2_gloc_2,
229  double *r_fb_co_1,
230  double *r_fb_co_2,
231  double *r_gloc_1,
232  double *r_gloc_2,
233  double *r_new_in_the_middle,
234  double *r_new_in_the_middle_global,
235  double *r_new_at,
236  bool *is_side_2r,
237  bool *use_new_ref)
238 {
239  int side = 0;
240  int z_index = is_persp ? 3 : 2;
241  /* Always use the closest point to the light camera. */
242  if (s1_fb_co_1[z_index] >= s2_fb_co_1[z_index]) {
243  copy_v4_v4_db(r_fb_co_1, s2_fb_co_1);
244  copy_v3_v3_db(r_gloc_1, s2_gloc_1);
245  side++;
246  }
247  if (s1_fb_co_2[z_index] >= s2_fb_co_2[z_index]) {
248  copy_v4_v4_db(r_fb_co_2, s2_fb_co_2);
249  copy_v3_v3_db(r_gloc_2, s2_gloc_2);
250  *is_side_2r = true;
251  side++;
252  }
253  if (s1_fb_co_1[z_index] <= s2_fb_co_1[z_index]) {
254  copy_v4_v4_db(r_fb_co_1, s1_fb_co_1);
255  copy_v3_v3_db(r_gloc_1, s1_gloc_1);
256  side--;
257  }
258  if (s1_fb_co_2[z_index] <= s2_fb_co_2[z_index]) {
259  copy_v4_v4_db(r_fb_co_2, s1_fb_co_2);
260  copy_v3_v3_db(r_gloc_2, s1_gloc_2);
261  *is_side_2r = false;
262  side--;
263  }
264 
265  /* No need to cut in the middle, because one segment completely overlaps the other. */
266  if (side) {
267  if (side > 0) {
268  *is_side_2r = true;
269  *use_new_ref = true;
270  }
271  else if (side < 0) {
272  *is_side_2r = false;
273  *use_new_ref = false;
274  }
275  return false;
276  }
277 
278  /* Else there must be an intersection point in the middle. Use "w" value to linearly plot the
279  * position and get image space "ratio" position. */
280  double dl = s1_fb_co_1[z_index] - s2_fb_co_1[z_index];
281  double dr = s1_fb_co_2[z_index] - s2_fb_co_2[z_index];
282  double ga = ratiod(dl, dr, 0);
283  *r_new_at = is_persp ? s2_fb_co_2[3] * ga / (s2_fb_co_1[3] * (1.0f - ga) + s2_fb_co_2[3] * ga) :
284  ga;
285  interp_v3_v3v3_db(r_new_in_the_middle, s2_fb_co_1, s2_fb_co_2, *r_new_at);
286  r_new_in_the_middle[3] = interpd(s2_fb_co_2[3], s2_fb_co_1[3], ga);
287  interp_v3_v3v3_db(r_new_in_the_middle_global, s1_gloc_1, s1_gloc_2, ga);
288  *use_new_ref = true;
289 
290  return true;
291 }
292 
293 /* For each visible [segment] of the edge, create 1 shadow edge. Note if the original edge has
294  * multiple visible cuts, multiple shadow edges should be generated. */
296  bool transform_edge_cuts,
297  bool do_light_contour)
298 {
299  /* If the segment is short enough, we ignore them because it's not prominently visible anyway. */
300 #define DISCARD_NONSENSE_SEGMENTS \
301  if (es->occlusion != 0 || \
302  (es->next && \
303  LRT_DOUBLE_CLOSE_ENOUGH(es->ratio, ((LineartEdgeSegment *)es->next)->ratio))) { \
304  LRT_ITER_ALL_LINES_NEXT; \
305  continue; \
306  }
307 
308  /* Count and allocate at once to save time. */
309  int segment_count = 0;
311  if (do_light_contour) {
312  accept_types |= LRT_EDGE_FLAG_LIGHT_CONTOUR;
313  }
315  {
316  /* Only contour and loose edges can actually cast shadows. We allow light contour here because
317  * we want to see if it also doubles as a view contour, in that case we also need to project
318  * them. */
319  if (!(e->flags & accept_types)) {
320  continue;
321  }
322  if (e->flags == LRT_EDGE_FLAG_LIGHT_CONTOUR) {
323  /* Check if the light contour also doubles as a view contour. */
324  LineartEdge *orig_e = (LineartEdge *)e->t1;
325  if (!orig_e->t2) {
326  e->flags |= LRT_EDGE_FLAG_CONTOUR;
327  }
328  else {
329  double vv[3];
330  double *view_vector = vv;
331  double dot_1 = 0, dot_2 = 0;
332  double result;
333  if (ld->conf.cam_is_persp) {
334  sub_v3_v3v3_db(view_vector, orig_e->v1->gloc, ld->conf.camera_pos);
335  }
336  else {
337  view_vector = ld->conf.view_vector;
338  }
339 
340  dot_1 = dot_v3v3_db(view_vector, orig_e->t1->gn);
341  dot_2 = dot_v3v3_db(view_vector, orig_e->t2->gn);
342 
343  if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
344  /* If this edge is both a light contour and a view contour, mark it for the convenience
345  * of generating it in the next iteration. */
346  e->flags |= LRT_EDGE_FLAG_CONTOUR;
347  }
348  }
349  if (!(e->flags & LRT_EDGE_FLAG_CONTOUR)) {
350  continue;
351  }
352  }
353  LISTBASE_FOREACH (LineartEdgeSegment *, es, &e->segments) {
355  segment_count++;
356  }
357  }
359 
361  sizeof(LineartShadowEdge) * segment_count);
363  &ld->render_data_pool, sizeof(LineartShadowSegment) * segment_count * 2);
364 
365  ld->shadow_edges = sedge;
366  ld->shadow_edges_count = segment_count;
367 
368  int i = 0;
370  {
371  if (!(e->flags & (LRT_EDGE_FLAG_CONTOUR | LRT_EDGE_FLAG_LOOSE))) {
372  continue;
373  }
374  LISTBASE_FOREACH (LineartEdgeSegment *, es, &e->segments) {
376 
377  double next_at = es->next ? ((LineartEdgeSegment *)es->next)->ratio : 1.0f;
378  /* Get correct XYZ and W coordinates. */
379  interp_v3_v3v3_db(sedge[i].fbc1, e->v1->fbcoord, e->v2->fbcoord, es->ratio);
380  interp_v3_v3v3_db(sedge[i].fbc2, e->v1->fbcoord, e->v2->fbcoord, next_at);
381 
382  /* Global coord for light-shadow separation line (occlusion-corrected light contour). */
383  double ga1 = e->v1->fbcoord[3] * es->ratio /
384  (es->ratio * e->v1->fbcoord[3] + (1 - es->ratio) * e->v2->fbcoord[3]);
385  double ga2 = e->v1->fbcoord[3] * next_at /
386  (next_at * e->v1->fbcoord[3] + (1 - next_at) * e->v2->fbcoord[3]);
387  interp_v3_v3v3_db(sedge[i].g1, e->v1->gloc, e->v2->gloc, ga1);
388  interp_v3_v3v3_db(sedge[i].g2, e->v1->gloc, e->v2->gloc, ga2);
389 
390  /* Assign an absurdly big W for initial distance so when triangles show up to catch the
391  * shadow, their w must certainly be smaller than this value so the shadow catches
392  * successfully. */
393  sedge[i].fbc1[3] = 1e30;
394  sedge[i].fbc2[3] = 1e30;
395  sedge[i].fbc1[2] = 1e30;
396  sedge[i].fbc2[2] = 1e30;
397 
398  /* Assign to the first segment's right and the last segment's left position */
399  copy_v4_v4_db(sseg[i * 2].fbc2, sedge[i].fbc1);
400  copy_v4_v4_db(sseg[i * 2 + 1].fbc1, sedge[i].fbc2);
401  sseg[i * 2].ratio = 0.0f;
402  sseg[i * 2 + 1].ratio = 1.0f;
403  BLI_addtail(&sedge[i].shadow_segments, &sseg[i * 2]);
404  BLI_addtail(&sedge[i].shadow_segments, &sseg[i * 2 + 1]);
405 
406  if (e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
407  sedge[i].e_ref = (LineartEdge *)e->t1;
408  sedge[i].e_ref_light_contour = e;
409  /* Restore original edge flag for edges "who is both view and light contour" so we still
410  * have correct edge flags. */
411  e->flags &= (~LRT_EDGE_FLAG_CONTOUR);
412  }
413  else {
414  sedge[i].e_ref = e;
415  }
416 
417  sedge[i].es_ref = es;
418 
419  i++;
420  }
421  }
423 
424  /* Transform the cutting position to global space for regular feature lines. This is for
425  * convenience of reusing the shadow cast function for both shadow line generation and silhouette
426  * registration, which the latter one needs view-space coordinates, while cast shadow needs
427  * global-space coordinates. */
428  if (transform_edge_cuts) {
430  {
431  LISTBASE_FOREACH (LineartEdgeSegment *, es, &e->segments) {
432  es->ratio = e->v1->fbcoord[3] * es->ratio /
433  (es->ratio * e->v1->fbcoord[3] + (1 - es->ratio) * e->v2->fbcoord[3]);
434  }
435  }
437  }
438 
439  if (G.debug_value == 4000) {
440  printf("Shadow: Added %d raw shadow_edges\n", segment_count);
441  }
442 }
443 
444 /* This function does the actual cutting on a given "shadow edge".
445  * #start / #end determines the view(from light camera) space cutting ratio.
446  * #start/end_gloc/fbc are the respective start/end coordinates.
447  * #facing_light is set from the caller which determines if this edge landed on a triangle's light
448  * facing side or not.
449  *
450  * Visually this function does this: (Top is the far side of the camera)
451  * _-end
452  * _-`
453  * l[-------------_-`--------------]r [e] 1) Calls for cut on top of #e.
454  * _-`
455  * _-`
456  * start-`
457  *
458  * _-end
459  * _-`
460  * l[-----][------_-`----][--------]r [e] 2) Add cutting points on #e at #start/#end.
461  * _-`
462  * _-`
463  * start-`
464  *
465  * _-end
466  * _-`
467  * [------_-`----] 3) Call lineart_shadow_segment_slice_get() to
468  * _-` get coordinates of a visually aligned segment on
469  * _-` #e with the incoming segment.
470  * start-`
471  *
472  * _c-----] 4) Call lineart_do_closest_segment() to find out the
473  * _-` actual geometry after cut, add a new cut if needed.
474  * _-`
475  * [`
476  *
477  * l[-----] _][----][--------]r [e] 5) Write coordinates on cuts.
478  * _-`
479  * _-`
480  * [`
481  *
482  * This process is repeated on each existing segments of the shadow edge (#e), which ensures they
483  * all have been tested for closest segments after cutting. And in the diagram it's clear that the
484  * left/right side of cuts are likely to be discontinuous, each cut's left side designates the
485  * right side of the last segment, and vise versa. */
488  double start,
489  double end,
490  double *start_gloc,
491  double *end_gloc,
492  double *start_fb_co,
493  double *end_fb_co,
494  bool facing_light,
495  uint32_t target_reference)
496 {
497  LineartShadowSegment *seg, *i_seg;
498  LineartShadowSegment *cut_start_after = e->shadow_segments.first,
499  *cut_end_before = e->shadow_segments.last;
500  LineartShadowSegment *new_seg_1 = NULL, *new_seg_2 = NULL, *seg_1 = NULL, *seg_2 = NULL;
501  int untouched = 0;
502 
503  /* If for some reason the occlusion function may give a result that has zero length, or
504  * reversed in direction, or NAN, we take care of them here. */
505  if (LRT_DOUBLE_CLOSE_ENOUGH(start, end)) {
506  return;
507  }
508  if (LRT_DOUBLE_CLOSE_ENOUGH(start, 1) || LRT_DOUBLE_CLOSE_ENOUGH(end, 0)) {
509  return;
510  }
511  if (UNLIKELY(start != start)) {
512  start = 0;
513  }
514  if (UNLIKELY(end != end)) {
515  end = 0;
516  }
517 
518  if (start > end) {
519  double t = start;
520  start = end;
521  end = t;
522  }
523 
524  /* Begin looking for starting position of the segment. */
525  /* Not using a list iteration macro because of it more clear when using for loops to iterate
526  * through the segments. */
527  for (seg = e->shadow_segments.first; seg; seg = seg->next) {
528  if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, start)) {
529  cut_start_after = seg;
530  new_seg_1 = cut_start_after;
531  break;
532  }
533  if (seg->next == NULL) {
534  break;
535  }
536  i_seg = seg->next;
537  if (i_seg->ratio > start + 1e-09 && start > seg->ratio) {
538  cut_start_after = seg;
539  new_seg_1 = lineart_give_shadow_segment(ld);
540  break;
541  }
542  }
543  if (!cut_start_after && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
544  untouched = 1;
545  }
546  for (seg = cut_start_after->next; seg; seg = seg->next) {
547  /* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle
548  * strip). */
549  if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, end)) {
550  cut_end_before = seg;
551  new_seg_2 = cut_end_before;
552  break;
553  }
554  /* This check is to prevent `es->ratio == 1.0` (where we don't need to cut because we are ratio
555  * the end point). */
556  if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
557  cut_end_before = seg;
558  new_seg_2 = cut_end_before;
559  untouched = 1;
560  break;
561  }
562  /* When an actual cut is needed in the line. */
563  if (seg->ratio > end) {
564  cut_end_before = seg;
565  new_seg_2 = lineart_give_shadow_segment(ld);
566  break;
567  }
568  }
569 
570  /* When we still can't find any existing cut in the line, we allocate new ones. */
571  if (new_seg_1 == NULL) {
572  new_seg_1 = lineart_give_shadow_segment(ld);
573  }
574  if (new_seg_2 == NULL) {
575  if (untouched) {
576  new_seg_2 = new_seg_1;
577  cut_end_before = new_seg_2;
578  }
579  else {
580  new_seg_2 = lineart_give_shadow_segment(ld);
581  }
582  }
583 
584  /* If we touched the cut list, we assign the new cut position based on new cut position,
585  * this way we accommodate precision lost due to multiple cut inserts. */
586  new_seg_1->ratio = start;
587  if (!untouched) {
588  new_seg_2->ratio = end;
589  }
590 
591  double r_fb_co_1[4], r_fb_co_2[4], r_gloc_1[3], r_gloc_2[3];
592  double r_new_in_the_middle[4], r_new_in_the_middle_global[3], r_new_at;
593  double *s1_fb_co_1, *s1_fb_co_2, *s1_gloc_1, *s1_gloc_2;
594 
595  /* Temporary coordinate records and "middle" records. */
596  double t_g1[3], t_g2[3], t_fbc1[4], t_fbc2[4], m_g1[3], m_fbc1[4], m_g2[3], m_fbc2[4];
597  bool is_side_2r, has_middle = false, use_new_ref;
598  copy_v4_v4_db(t_fbc1, start_fb_co);
599  copy_v3_v3_db(t_g1, start_gloc);
600 
601  /* Do max stuff before insert. */
603  for (seg = cut_start_after; seg != cut_end_before; seg = nes) {
604  nes = seg->next;
605 
606  s1_fb_co_1 = seg->fbc2, s1_fb_co_2 = nes->fbc1;
607  s1_gloc_1 = seg->g2, s1_gloc_2 = nes->g1;
608  seg_1 = seg, seg_2 = nes;
609  if (seg == cut_start_after) {
611  nes->fbc1,
612  seg->g2,
613  nes->g1,
614  new_seg_1->ratio,
615  seg->ratio,
616  nes->ratio,
617  m_fbc1,
618  m_g1);
619  s1_fb_co_1 = m_fbc1, s1_gloc_1 = m_g1;
620  seg_1 = new_seg_1;
621  if (cut_start_after != new_seg_1) {
622  BLI_insertlinkafter(&e->shadow_segments, cut_start_after, new_seg_1);
623  copy_v4_v4_db(new_seg_1->fbc1, m_fbc1);
624  copy_v3_v3_db(new_seg_1->g1, m_g1);
625  }
626  }
627  if (nes == cut_end_before) {
629  nes->fbc1,
630  seg->g2,
631  nes->g1,
632  new_seg_2->ratio,
633  seg->ratio,
634  nes->ratio,
635  m_fbc2,
636  m_g2);
637  s1_fb_co_2 = m_fbc2, s1_gloc_2 = m_g2;
638  seg_2 = new_seg_2;
639  if (cut_end_before != new_seg_2) {
640  BLI_insertlinkbefore(&e->shadow_segments, cut_end_before, new_seg_2);
641  copy_v4_v4_db(new_seg_2->fbc2, m_fbc2);
642  copy_v3_v3_db(new_seg_2->g2, m_g2);
643  /* Need to restore the flag for next segment's reference. */
644  seg_2->flag = seg->flag;
645  seg_2->target_reference = seg->target_reference;
646  }
647  }
648 
650  start_fb_co, end_fb_co, start_gloc, end_gloc, seg_2->ratio, start, end, t_fbc2, t_g2);
651 
652  if ((has_middle = lineart_do_closest_segment(ld->conf.cam_is_persp,
653  s1_fb_co_1,
654  s1_fb_co_2,
655  t_fbc1,
656  t_fbc2,
657  s1_gloc_1,
658  s1_gloc_2,
659  t_g1,
660  t_g2,
661  r_fb_co_1,
662  r_fb_co_2,
663  r_gloc_1,
664  r_gloc_2,
665  r_new_in_the_middle,
666  r_new_in_the_middle_global,
667  &r_new_at,
668  &is_side_2r,
669  &use_new_ref))) {
671  ss_middle->ratio = interpf(seg_2->ratio, seg_1->ratio, r_new_at);
672  ss_middle->flag = LRT_SHADOW_CASTED |
673  (use_new_ref ? (facing_light ? LRT_SHADOW_FACING_LIGHT : 0) : seg_1->flag);
674  ss_middle->target_reference = (use_new_ref ? (target_reference) : seg_1->target_reference);
675  copy_v3_v3_db(ss_middle->g1, r_new_in_the_middle_global);
676  copy_v3_v3_db(ss_middle->g2, r_new_in_the_middle_global);
677  copy_v4_v4_db(ss_middle->fbc1, r_new_in_the_middle);
678  copy_v4_v4_db(ss_middle->fbc2, r_new_in_the_middle);
679  BLI_insertlinkafter(&e->shadow_segments, seg_1, ss_middle);
680  }
681  /* Always assign the "closest" value to the segment. */
682  copy_v4_v4_db(seg_1->fbc2, r_fb_co_1);
683  copy_v3_v3_db(seg_1->g2, r_gloc_1);
684  copy_v4_v4_db(seg_2->fbc1, r_fb_co_2);
685  copy_v3_v3_db(seg_2->g1, r_gloc_2);
686 
687  if (has_middle) {
688  seg_1->flag = LRT_SHADOW_CASTED |
689  (is_side_2r ? seg->flag : (facing_light ? LRT_SHADOW_FACING_LIGHT : 0));
690  seg_1->target_reference = is_side_2r ? seg->target_reference : target_reference;
691  }
692  else {
693  seg_1->flag = LRT_SHADOW_CASTED |
694  (use_new_ref ? (facing_light ? LRT_SHADOW_FACING_LIGHT : 0) : seg->flag);
695  seg_1->target_reference = use_new_ref ? target_reference : seg->target_reference;
696  }
697 
698  copy_v4_v4_db(t_fbc1, t_fbc2);
699  copy_v3_v3_db(t_g1, t_g2);
700  }
701 }
702 
704  LineartTriangle *tri,
705  LineartShadowEdge *sedge,
706  double *r_at_1,
707  double *r_at_2,
708  double *r_fb_co_1,
709  double *r_fb_co_2,
710  double *r_gloc_1,
711  double *r_gloc_2,
712  bool *r_facing_light)
713 {
714 
715  double *LFBC = sedge->fbc1, *RFBC = sedge->fbc2, *FBC0 = tri->v[0]->fbcoord,
716  *FBC1 = tri->v[1]->fbcoord, *FBC2 = tri->v[2]->fbcoord;
717 
718  /* Bound box check. Because we have already done occlusion in the shadow camera, so any visual
719  * intersection found in this function must mean that the triangle is behind the given line so it
720  * will always project a shadow, hence no need to do depth bound-box check. */
721  if ((MAX3(FBC0[0], FBC1[0], FBC2[0]) < MIN2(LFBC[0], RFBC[0])) ||
722  (MIN3(FBC0[0], FBC1[0], FBC2[0]) > MAX2(LFBC[0], RFBC[0])) ||
723  (MAX3(FBC0[1], FBC1[1], FBC2[1]) < MIN2(LFBC[1], RFBC[1])) ||
724  (MIN3(FBC0[1], FBC1[1], FBC2[1]) > MAX2(LFBC[1], RFBC[1]))) {
725  return false;
726  }
727 
728  bool is_persp = ld->conf.cam_is_persp;
729  double ratio[2];
730  int trie[2];
731  int pi = 0;
732  if (lineart_line_isec_2d_ignore_line2pos(FBC0, FBC1, LFBC, RFBC, &ratio[pi])) {
733  trie[pi] = 0;
734  pi++;
735  }
736  if (lineart_line_isec_2d_ignore_line2pos(FBC1, FBC2, LFBC, RFBC, &ratio[pi])) {
737  /* ratio[0] == 1 && ratio[1] == 0 means we found a intersection at the same point of the
738  * edge (FBC1), ignore this one and try get the intersection point from the other side of
739  * the edge
740  */
741  if (!(pi && LRT_DOUBLE_CLOSE_ENOUGH(ratio[0], 1.0f) &&
742  LRT_DOUBLE_CLOSE_ENOUGH(ratio[1], 0.0f))) {
743  trie[pi] = 1;
744  pi++;
745  }
746  }
747  if (!pi) {
748  return false;
749  }
750  if (pi == 1 && lineart_line_isec_2d_ignore_line2pos(FBC2, FBC0, LFBC, RFBC, &ratio[pi])) {
751 
752  if ((trie[0] == 0 && LRT_DOUBLE_CLOSE_ENOUGH(ratio[0], 0.0f) &&
753  LRT_DOUBLE_CLOSE_ENOUGH(ratio[1], 1.0f)) ||
754  (trie[0] == 1 && LRT_DOUBLE_CLOSE_ENOUGH(ratio[0], 1.0f) &&
755  LRT_DOUBLE_CLOSE_ENOUGH(ratio[1], 0.0f))) {
756  return false;
757  }
758  trie[pi] = 2;
759  pi++;
760  }
761 
762  if (pi != 2) {
763  return false;
764  }
765 
766  /* Get projected global position. */
767 
768  double gpos1[3], gpos2[3];
769  double *v1 = (trie[0] == 0 ? FBC0 : (trie[0] == 1 ? FBC1 : FBC2));
770  double *v2 = (trie[0] == 0 ? FBC1 : (trie[0] == 1 ? FBC2 : FBC0));
771  double *v3 = (trie[1] == 0 ? FBC0 : (trie[1] == 1 ? FBC1 : FBC2));
772  double *v4 = (trie[1] == 0 ? FBC1 : (trie[1] == 1 ? FBC2 : FBC0));
773  double *gv1 = (trie[0] == 0 ? tri->v[0]->gloc :
774  (trie[0] == 1 ? tri->v[1]->gloc : tri->v[2]->gloc));
775  double *gv2 = (trie[0] == 0 ? tri->v[1]->gloc :
776  (trie[0] == 1 ? tri->v[2]->gloc : tri->v[0]->gloc));
777  double *gv3 = (trie[1] == 0 ? tri->v[0]->gloc :
778  (trie[1] == 1 ? tri->v[1]->gloc : tri->v[2]->gloc));
779  double *gv4 = (trie[1] == 0 ? tri->v[1]->gloc :
780  (trie[1] == 1 ? tri->v[2]->gloc : tri->v[0]->gloc));
781  double gr1 = is_persp ? v1[3] * ratio[0] / (ratio[0] * v1[3] + (1 - ratio[0]) * v2[3]) :
782  ratio[0];
783  double gr2 = is_persp ? v3[3] * ratio[1] / (ratio[1] * v3[3] + (1 - ratio[1]) * v4[3]) :
784  ratio[1];
785  interp_v3_v3v3_db(gpos1, gv1, gv2, gr1);
786  interp_v3_v3v3_db(gpos2, gv3, gv4, gr2);
787 
788  double fbc1[4], fbc2[4];
789 
790  mul_v4_m4v3_db(fbc1, ld->conf.view_projection, gpos1);
791  mul_v4_m4v3_db(fbc2, ld->conf.view_projection, gpos2);
792  if (is_persp) {
793  mul_v3db_db(fbc1, 1.0f / fbc1[3]);
794  mul_v3db_db(fbc2, 1.0f / fbc2[3]);
795  }
796 
797  int use = (fabs(LFBC[0] - RFBC[0]) > fabs(LFBC[1] - RFBC[1])) ? 0 : 1;
798  double at1 = ratiod(LFBC[use], RFBC[use], fbc1[use]);
799  double at2 = ratiod(LFBC[use], RFBC[use], fbc2[use]);
800  if (at1 > at2) {
801  swap_v3_v3_db(gpos1, gpos2);
802  swap_v4_v4_db(fbc1, fbc2);
803  SWAP(double, at1, at2);
804  }
805 
806  /* If not effectively projecting anything. */
807  if (at1 > (1.0f - FLT_EPSILON) || at2 < FLT_EPSILON) {
808  return false;
809  }
810 
811  /* Trim to edge's end points. */
812 
813  double t_fbc1[4], t_fbc2[4], t_gpos1[3], t_gpos2[3];
814  bool trimmed1 = false, trimmed2 = false;
815  if (at1 < 0 || at2 > 1) {
816  double rat1 = (-at1) / (at2 - at1);
817  double rat2 = (1.0f - at1) / (at2 - at1);
818  double gat1 = is_persp ? fbc1[3] * rat1 / (rat1 * fbc1[3] + (1 - rat1) * fbc2[3]) : rat1;
819  double gat2 = is_persp ? fbc1[3] * rat2 / (rat2 * fbc1[3] + (1 - rat2) * fbc2[3]) : rat2;
820  if (at1 < 0) {
821  interp_v3_v3v3_db(t_gpos1, gpos1, gpos2, gat1);
822  interp_v3_v3v3_db(t_fbc1, fbc1, fbc2, rat1);
823  t_fbc1[3] = interpd(fbc2[3], fbc1[3], gat1);
824  at1 = 0, trimmed1 = true;
825  }
826  if (at2 > 1) {
827  interp_v3_v3v3_db(t_gpos2, gpos1, gpos2, gat2);
828  interp_v3_v3v3_db(t_fbc2, fbc1, fbc2, rat2);
829  t_fbc2[3] = interpd(fbc2[3], fbc1[3], gat2);
830  at2 = 1, trimmed2 = true;
831  }
832  }
833  if (trimmed1) {
834  copy_v4_v4_db(fbc1, t_fbc1);
835  copy_v3_v3_db(gpos1, t_gpos1);
836  }
837  if (trimmed2) {
838  copy_v4_v4_db(fbc2, t_fbc2);
839  copy_v3_v3_db(gpos2, t_gpos2);
840  }
841 
842  *r_at_1 = at1;
843  *r_at_2 = at2;
844  copy_v4_v4_db(r_fb_co_1, fbc1);
845  copy_v4_v4_db(r_fb_co_2, fbc2);
846  copy_v3_v3_db(r_gloc_1, gpos1);
847  copy_v3_v3_db(r_gloc_2, gpos2);
848 
849  double camera_vector[3];
850 
851  if (is_persp) {
852  sub_v3_v3v3_db(camera_vector, ld->conf.camera_pos, tri->v[0]->gloc);
853  }
854  else {
855  copy_v3_v3_db(camera_vector, ld->conf.view_vector);
856  }
857 
858  double dot_f = dot_v3v3_db(camera_vector, tri->gn);
859  *r_facing_light = (dot_f < 0);
860 
861  return true;
862 }
863 
864 /* The one step all to cast all visible edges in light camera back to other geometries behind them,
865  * the result of this step can then be generated as actual LineartEdge's for occlusion test in view
866  * camera. */
867 static void lineart_shadow_cast(LineartData *ld, bool transform_edge_cuts, bool do_light_contour)
868 {
869 
870  lineart_shadow_create_shadow_edge_array(ld, transform_edge_cuts, do_light_contour);
871 
872  /* Keep it single threaded for now because the loop will write "done" pointers to triangles. */
873  for (int edge_i = 0; edge_i < ld->shadow_edges_count; edge_i++) {
874  LineartShadowEdge *sedge = &ld->shadow_edges[edge_i];
875 
877  double at_1, at_2;
878  double fb_co_1[4], fb_co_2[4];
879  double global_1[3], global_2[3];
880  bool facing_light;
881 
882  LRT_EDGE_BA_MARCHING_BEGIN(sedge->fbc1, sedge->fbc2)
883  {
884  for (int i = 0; i < nba->triangle_count; i++) {
885  tri = (LineartTriangleThread *)nba->linked_triangles[i];
886  if (tri->testing_e[0] == (LineartEdge *)sedge || tri->base.mat_occlusion == 0 ||
888  (LineartTriangle *)tri, sedge->e_ref, ld->conf.allow_overlapping_edges)) {
889  continue;
890  }
891  tri->testing_e[0] = (LineartEdge *)sedge;
892 
894  (LineartTriangle *)tri,
895  sedge,
896  &at_1,
897  &at_2,
898  fb_co_1,
899  fb_co_2,
900  global_1,
901  global_2,
902  &facing_light)) {
904  sedge,
905  at_1,
906  at_2,
907  global_1,
908  global_2,
909  fb_co_1,
910  fb_co_2,
911  facing_light,
912  tri->base.target_reference);
913  }
914  }
915  LRT_EDGE_BA_MARCHING_NEXT(sedge->fbc1, sedge->fbc2);
916  }
918  }
919 }
920 
921 /* For each [segment] on a shadow shadow_edge, 1 LineartEdge will be generated with a cast shadow
922  * edge flag (if that segment failed to cast onto anything then it's not generated). The original
923  * shadow shadow_edge is optionally generated as a light contour. */
925  bool do_original_edges,
926  LineartElementLinkNode **r_veln,
927  LineartElementLinkNode **r_eeln)
928 {
929  int tot_edges = 0;
930  int tot_orig_edges = 0;
931  for (int i = 0; i < ld->shadow_edges_count; i++) {
932  LineartShadowEdge *sedge = &ld->shadow_edges[i];
934  if (!(sseg->flag & LRT_SHADOW_CASTED)) {
935  continue;
936  }
937  if (!sseg->next) {
938  break;
939  }
940  tot_edges++;
941  }
942  tot_orig_edges++;
943  }
944 
945  int edge_alloc = tot_edges + (do_original_edges ? tot_orig_edges : 0);
946 
947  if (G.debug_value == 4000) {
948  printf("Line art shadow segments total: %d\n", tot_edges);
949  }
950 
951  if (!edge_alloc) {
952  return false;
953  }
955  sizeof(LineartElementLinkNode));
957  sizeof(LineartElementLinkNode));
958  veln->pointer = lineart_mem_acquire(ld->shadow_data_pool, sizeof(LineartVert) * edge_alloc * 2);
959  eeln->pointer = lineart_mem_acquire(ld->shadow_data_pool, sizeof(LineartEdge) * edge_alloc);
961  sizeof(LineartEdgeSegment) * edge_alloc);
962  *r_veln = veln;
963  *r_eeln = eeln;
964 
965  veln->element_count = edge_alloc * 2;
966  eeln->element_count = edge_alloc;
967 
968  LineartVert *vlist = veln->pointer;
969  LineartEdge *elist = eeln->pointer;
970 
971  int ei = 0;
972  for (int i = 0; i < ld->shadow_edges_count; i++) {
973  LineartShadowEdge *sedge = &ld->shadow_edges[i];
975  if (!(sseg->flag & LRT_SHADOW_CASTED)) {
976  continue;
977  }
978  if (!sseg->next) {
979  break;
980  }
981  LineartEdge *e = &elist[ei];
982  BLI_addtail(&e->segments, &es[ei]);
983  LineartVert *v1 = &vlist[ei * 2], *v2 = &vlist[ei * 2 + 1];
984  copy_v3_v3_db(v1->gloc, sseg->g2);
985  copy_v3_v3_db(v2->gloc, ((LineartShadowSegment *)sseg->next)->g1);
986  e->v1 = v1;
987  e->v2 = v2;
988  e->t1 = (LineartTriangle *)sedge->e_ref; /* See LineartEdge::t1 for usage. */
989  e->t2 = (LineartTriangle *)(sedge->e_ref_light_contour ? sedge->e_ref_light_contour :
990  sedge->e_ref);
991  e->target_reference = sseg->target_reference;
992  e->edge_identifier = sedge->e_ref->edge_identifier;
995  0));
996  ei++;
997  }
998  if (do_original_edges) {
999  /* Occlusion-corrected light contour. */
1000  LineartEdge *e = &elist[ei];
1001  BLI_addtail(&e->segments, &es[ei]);
1002  LineartVert *v1 = &vlist[ei * 2], *v2 = &vlist[ei * 2 + 1];
1003  v1->index = sedge->e_ref->v1->index;
1004  v2->index = sedge->e_ref->v2->index;
1005  copy_v3_v3_db(v1->gloc, sedge->g1);
1006  copy_v3_v3_db(v2->gloc, sedge->g2);
1007  uint64_t ref_1 = sedge->e_ref->t1 ? sedge->e_ref->t1->target_reference : 0;
1008  uint64_t ref_2 = sedge->e_ref->t2 ? sedge->e_ref->t2->target_reference : 0;
1009  e->edge_identifier = sedge->e_ref->edge_identifier;
1010  e->target_reference = ((ref_1 << 32) | ref_2);
1011  e->v1 = v1;
1012  e->v2 = v2;
1013  e->t1 = e->t2 = (LineartTriangle *)sedge->e_ref;
1014  e->flags = LRT_EDGE_FLAG_LIGHT_CONTOUR;
1016  lineart_edge_cut(ld, e, 0.0f, 1.0f, 0, 0, LRT_SHADOW_MASK_SHADED);
1017  }
1018  ei++;
1019  }
1020  }
1021  return true;
1022 }
1023 
1025 {
1026  /* Keeping it single threaded for now because a simple parallel_for could end up getting the same
1027  * #sedge->e_ref in different threads. */
1028  for (int i = 0; i < ld->shadow_edges_count; i++) {
1029  LineartShadowEdge *sedge = &ld->shadow_edges[i];
1030 
1031  LineartEdge *e = sedge->e_ref;
1032  LineartEdgeSegment *es = sedge->es_ref;
1033  double es_start = es->ratio, es_end = es->next ? es->next->ratio : 1.0f;
1035  if (!(sseg->flag & LRT_SHADOW_CASTED)) {
1036  continue;
1037  }
1038  if (!sseg->next) {
1039  break;
1040  }
1041 
1042  uint32_t silhouette_flags = (sseg->target_reference & LRT_OBINDEX_HIGHER) |
1044 
1045  double at_start = interpd(es_end, es_start, sseg->ratio);
1046  double at_end = interpd(es_end, es_start, sseg->next->ratio);
1047  lineart_edge_cut(ld, e, at_start, at_end, 0, 0, silhouette_flags);
1048  }
1049  }
1050 }
1051 
1052 /* To achieve enclosed shape effect, we need to:
1053  * 1) Show shaded segments against lit background.
1054  * 2) Erase lit segments against lit background. */
1056 {
1057  LineartEdge *e;
1058  LineartEdgeSegment *es;
1059  for (int i = 0; i < shadow_ld->pending_edges.next; i++) {
1060  e = shadow_ld->pending_edges.array[i];
1061 
1062  /* Only care about shade-on-light and light-on-light situations, hence we only need
1063  * non-occluded segments in shadow buffer. */
1064  if (e->min_occ > 0) {
1065  continue;
1066  }
1067  for (es = e->segments.first; es; es = es->next) {
1068  if (es->occlusion > 0) {
1069  continue;
1070  }
1071  double next_at = es->next ? ((LineartEdgeSegment *)es->next)->ratio : 1.0f;
1072  LineartEdge *orig_e = (LineartEdge *)e->t2;
1073 
1074  /* Shadow view space to global. */
1075  double ga1 = e->v1->fbcoord[3] * es->ratio /
1076  (es->ratio * e->v1->fbcoord[3] + (1 - es->ratio) * e->v2->fbcoord[3]);
1077  double ga2 = e->v1->fbcoord[3] * next_at /
1078  (next_at * e->v1->fbcoord[3] + (1 - next_at) * e->v2->fbcoord[3]);
1079  double g1[3], g2[3], g1v[4], g2v[4];
1080  interp_v3_v3v3_db(g1, e->v1->gloc, e->v2->gloc, ga1);
1081  interp_v3_v3v3_db(g2, e->v1->gloc, e->v2->gloc, ga2);
1082  mul_v4_m4v3_db(g1v, ld->conf.view_projection, g1);
1083  mul_v4_m4v3_db(g2v, ld->conf.view_projection, g2);
1084 
1085  if (ld->conf.cam_is_persp) {
1086  mul_v3db_db(g1v, (1 / g1v[3]));
1087  mul_v3db_db(g2v, (1 / g2v[3]));
1088  }
1089 
1090  g1v[0] -= ld->conf.shift_x * 2;
1091  g1v[1] -= ld->conf.shift_y * 2;
1092  g2v[0] -= ld->conf.shift_x * 2;
1093  g2v[1] -= ld->conf.shift_y * 2;
1094 
1095 #define GET_RATIO(n) \
1096  (fabs(orig_e->v2->fbcoord[0] - orig_e->v1->fbcoord[0]) > \
1097  fabs(orig_e->v2->fbcoord[1] - orig_e->v1->fbcoord[1])) ? \
1098  ((g##n##v[0] - orig_e->v1->fbcoord[0]) / \
1099  (orig_e->v2->fbcoord[0] - orig_e->v1->fbcoord[0])) : \
1100  ((g##n##v[1] - orig_e->v1->fbcoord[1]) / (orig_e->v2->fbcoord[1] - orig_e->v1->fbcoord[1]))
1101  double la1, la2;
1102  la1 = GET_RATIO(1);
1103  la2 = GET_RATIO(2);
1104 #undef GET_RATIO
1105 
1106  lineart_edge_cut(ld, orig_e, la1, la2, 0, 0, LRT_SHADOW_MASK_ENCLOSED_SHAPE);
1107  }
1108  }
1109 }
1110 
1111 /* This call would internally duplicate #original_ld, override necessary configurations for shadow
1112  * computations. It will return:
1113  *
1114  * 1) Generated shadow edges in format of `LineartElementLinkNode` which can be directly loaded
1115  * into later main view camera occlusion stage.
1116  * 2) Shadow render buffer if 3rd stage reprojection is need for silhouette/lit/shaded region
1117  * selection. Otherwise the shadow render buffer is deleted before this function returns.
1118  */
1120  Scene *scene,
1121  LineartData *original_ld,
1123  LineartStaticMemPool *shadow_data_pool,
1124  LineartElementLinkNode **r_veln,
1125  LineartElementLinkNode **r_eeln,
1126  ListBase *r_calculated_edges_eln_list,
1127  LineartData **r_shadow_ld_if_reproject)
1128 {
1129  if ((!original_ld->conf.use_shadow && !original_ld->conf.use_light_contour &&
1130  !original_ld->conf.shadow_selection) ||
1131  (!lmd->light_contour_object)) {
1132  return false;
1133  }
1134 
1135  double t_start;
1136  if (G.debug_value == 4000) {
1137  t_start = PIL_check_seconds_timer();
1138  }
1139 
1140  bool is_persp = true;
1141 
1142  if (lmd->light_contour_object->type == OB_LAMP) {
1143  Light *la = (Light *)lmd->light_contour_object->data;
1144  if (la->type == LA_SUN) {
1145  is_persp = false;
1146  }
1147  }
1148 
1149  LineartData *ld = MEM_callocN(sizeof(LineartData), "LineArt render buffer copied");
1150  memcpy(ld, original_ld, sizeof(LineartData));
1151 
1152  BLI_spin_init(&ld->lock_task);
1153  BLI_spin_init(&ld->lock_cuts);
1155 
1156  ld->conf.do_shadow_cast = true;
1157  ld->shadow_data_pool = shadow_data_pool;
1158 
1159  /* See LineartData::edge_data_pool for explanation. */
1160  if (ld->conf.shadow_selection) {
1161  ld->edge_data_pool = shadow_data_pool;
1162  }
1163  else {
1164  ld->edge_data_pool = &ld->render_data_pool;
1165  }
1166 
1169 
1173  ld->conf.cam_is_persp = is_persp;
1174  ld->conf.near_clip = is_persp ? lmd->shadow_camera_near : -lmd->shadow_camera_far;
1175  ld->conf.far_clip = lmd->shadow_camera_far;
1176  ld->w = lmd->shadow_camera_size;
1177  ld->h = lmd->shadow_camera_size;
1178  /* Need to prevent wrong camera configuration so that shadow computation won't stall. */
1179  if (!ld->w || !ld->h) {
1180  ld->w = ld->h = 200;
1181  }
1182  if (!ld->conf.near_clip || !ld->conf.far_clip) {
1183  ld->conf.near_clip = 0.1f;
1184  ld->conf.far_clip = 200.0f;
1185  }
1187 
1188  /* Contour and loose edge from light viewing direction will be cast as shadow, so only
1189  * force them on. If we need lit/shaded information for other line types, they are then
1190  * enabled as-is so that cutting positions can also be calculated through shadow projection.
1191  */
1192  if (!ld->conf.shadow_selection) {
1194  ld->conf.use_intersections = ld->conf.use_light_contour = false;
1195  }
1196  else {
1197  ld->conf.use_contour_secondary = true;
1198  ld->conf.allow_duplicated_types = true;
1199  }
1200  ld->conf.use_loose = true;
1201  ld->conf.use_contour = true;
1202 
1203  ld->conf.max_occlusion_level = 0; /* No point getting see-through projections there. */
1204  ld->conf.use_back_face_culling = false;
1205 
1206  /* Override matrices to light "camera". */
1207  double proj[4][4], view[4][4], result[4][4];
1208  float inv[4][4];
1209  if (is_persp) {
1211  }
1212  else {
1214  proj, -ld->w, ld->w, -ld->h, ld->h, ld->conf.near_clip, ld->conf.far_clip);
1215  }
1216  invert_m4_m4(inv, ld->conf.cam_obmat);
1217  mul_m4db_m4db_m4fl_uniq(result, proj, inv);
1218  copy_m4_m4_db(proj, result);
1219  copy_m4_m4_db(ld->conf.view_projection, proj);
1220  unit_m4_db(view);
1221  copy_m4_m4_db(ld->conf.view, view);
1222 
1224 
1226  depsgraph, scene, NULL, ld, lmd->flags & LRT_ALLOW_DUPLI_OBJECTS, true, NULL);
1227 
1228  if (!ld->geom.vertex_buffer_pointers.first) {
1229  /* No geometry loaded, return early. */
1231  MEM_freeN(ld);
1232  return false;
1233  }
1234 
1235  /* The exact same process as in MOD_lineart_compute_feature_lines() until occlusion finishes.
1236  */
1237 
1239  lineart_main_cull_triangles(ld, false);
1240  lineart_main_cull_triangles(ld, true);
1248 
1249  /* Do shadow cast stuff then get generated vert/edge data. */
1250  lineart_shadow_cast(ld, true, false);
1251  bool any_generated = lineart_shadow_cast_generate_edges(ld, true, r_veln, r_eeln);
1252 
1253  if (ld->conf.shadow_selection) {
1254  memcpy(r_calculated_edges_eln_list, &ld->geom.line_buffer_pointers, sizeof(ListBase));
1255  }
1256 
1257  if (ld->conf.shadow_enclose_shapes) {
1258  /* Need loaded data for re-projecting the 3rd time to get shape boundary against lit/shaded
1259  * region. */
1260  (*r_shadow_ld_if_reproject) = ld;
1261  }
1262  else {
1264  MEM_freeN(ld);
1265  }
1266 
1267  if (G.debug_value == 4000) {
1268  double t_elapsed = PIL_check_seconds_timer() - t_start;
1269  printf("Line art shadow stage 1 time: %f\n", t_elapsed);
1270  }
1271 
1272  return any_generated;
1273 }
1274 
1280 
1281 static void lineart_shadow_transform_task(void *__restrict userdata,
1282  const int element_index,
1283  const TaskParallelTLS *__restrict UNUSED(tls))
1284 {
1286  LineartData *ld = data->ld;
1287  LineartVert *v = &data->v[element_index];
1288  mul_v4_m4v3_db(v->fbcoord, ld->conf.view_projection, v->gloc);
1289 }
1290 
1292  void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
1293 {
1295  LineartData *ld = data->ld;
1296  LineartEdge *e = data->e;
1297 
1298  if (e[i].flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
1300  &ld->geom.vertex_buffer_pointers, e[i].edge_identifier & LRT_OBINDEX_HIGHER);
1301  if (eln) {
1302  int v1i = (((e[i].edge_identifier) >> 32) & LRT_OBINDEX_LOWER);
1303  int v2i = (e[i].edge_identifier & LRT_OBINDEX_LOWER);
1304  LineartVert *v = (LineartVert *)eln->pointer;
1305  /* If the global position is close enough, use the original vertex to prevent flickering
1306  * caused by very slim boundary condition in point_triangle_relation().*/
1307  if (LRT_CLOSE_LOOSER_v3(e[i].v1->gloc, v[v1i].gloc)) {
1308  e[i].v1 = &v[v1i];
1309  }
1310  if (LRT_CLOSE_LOOSER_v3(e[i].v2->gloc, v[v2i].gloc)) {
1311  e[i].v2 = &v[v2i];
1312  }
1313  }
1314  }
1315 }
1316 
1317 /* Shadow segments needs to be transformed to view-camera space, just like any other objects.
1318  */
1320  LineartElementLinkNode *veln,
1321  LineartElementLinkNode *eeln)
1322 {
1323 
1324  TaskParallelSettings transform_settings;
1325  BLI_parallel_range_settings_defaults(&transform_settings);
1326  /* Set the minimum amount of edges a thread has to process. */
1327  transform_settings.min_iter_per_thread = 8192;
1328 
1330  data.ld = ld;
1331  data.v = (LineartVert *)veln->pointer;
1332  data.e = (LineartEdge *)eeln->pointer;
1333 
1335  0, veln->element_count, &data, lineart_shadow_transform_task, &transform_settings);
1337  eeln->element_count,
1338  &data,
1340  &transform_settings);
1341  for (int i = 0; i < eeln->element_count; i++) {
1343  }
1344 
1347 }
1348 
1349 /* Does the 3rd stage reprojection, will not re-load objects because #shadow_ld is not deleted.
1350  * Only re-projects view camera edges and check visibility in light camera, then we can determine
1351  * whether an edge landed on a lit or shaded area. */
1353 {
1354  double t_start;
1355  if (G.debug_value == 4000) {
1356  t_start = PIL_check_seconds_timer();
1357  }
1358 
1359  if (shadow_ld || ld->conf.shadow_use_silhouette) {
1360  lineart_shadow_cast(ld, false, shadow_ld ? true : false);
1361  if (ld->conf.shadow_use_silhouette) {
1363  }
1364  }
1365 
1366  if (G.debug_value == 4000) {
1367  double t_elapsed = PIL_check_seconds_timer() - t_start;
1368  printf("Line art shadow stage 2 cast and silhouette time: %f\n", t_elapsed);
1369  }
1370 
1371  if (!shadow_ld) {
1372  return;
1373  }
1374 
1376 
1377  if (shadow_ld->pending_edges.array) {
1378  MEM_freeN(shadow_ld->pending_edges.array);
1379  shadow_ld->pending_edges.array = NULL;
1380  shadow_ld->pending_edges.next = shadow_ld->pending_edges.max = 0;
1381  }
1382 
1383  LineartElementLinkNode *shadow_veln, *shadow_eeln;
1384 
1385  bool any_generated = lineart_shadow_cast_generate_edges(ld, false, &shadow_veln, &shadow_eeln);
1386 
1387  if (!any_generated) {
1388  return;
1389  }
1390 
1391  LineartVert *v = shadow_veln->pointer;
1392  for (int i = 0; i < shadow_veln->element_count; i++) {
1393  mul_v4_m4v3_db(v[i].fbcoord, shadow_ld->conf.view_projection, v[i].gloc);
1394  if (shadow_ld->conf.cam_is_persp) {
1395  mul_v3db_db(v[i].fbcoord, (1 / v[i].fbcoord[3]));
1396  }
1397  }
1398 
1400  shadow_eeln->element_count);
1401 
1402  LineartEdge *se = shadow_eeln->pointer;
1403  for (int i = 0; i < shadow_eeln->element_count; i++) {
1404  lineart_add_edge_to_array(&shadow_ld->pending_edges, &se[i]);
1405  }
1406 
1407  shadow_ld->scheduled_count = 0;
1408 
1410  lineart_main_link_lines(shadow_ld);
1411  lineart_main_occlusion_begin(shadow_ld);
1412 
1414 
1415  if (G.debug_value == 4000) {
1416  double t_elapsed = PIL_check_seconds_timer() - t_start;
1417  printf("Line art shadow stage 2 total time: %f\n", t_elapsed);
1418  }
1419 }
General operations, lookup, etc. for materials.
General operations, lookup, etc. for blender objects.
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:221
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
MINLINE double interpd(double a, double b, double t)
MINLINE double ratiod(double min, double max, double pos)
MINLINE float interpf(float a, float b, float t)
void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3])
Definition: math_matrix.c:758
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_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 copy_m4_m4_db(double m1[4][4], const double m2[4][4])
Definition: math_matrix.c:82
#define DEG2RAD(_deg)
void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], double t)
Definition: math_vector.c:1305
MINLINE void swap_v3_v3_db(double a[3], double b[3])
MINLINE void mul_v3db_db(double r[3], double f)
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 swap_v4_v4_db(double a[4], double b[4])
MINLINE void copy_v3_v3_db(double r[3], const double a[3])
MINLINE void copy_v4_v4_db(double r[4], const double a[4])
MINLINE void sub_v3_v3v3_db(double r[3], const double a[3], const double b[3])
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
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
#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 MIN2(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
Object groups, one object can be in many groups at once.
#define LA_SUN
@ LRT_EDGE_FLAG_SHADOW_FACING_LIGHT
@ LRT_EDGE_FLAG_PROJECTED_SHADOW
@ LRT_EDGE_FLAG_CONTOUR_SECONDARY
@ LRT_EDGE_FLAG_LOOSE
@ LRT_EDGE_FLAG_LIGHT_CONTOUR
@ LRT_EDGE_FLAG_CONTOUR
@ LRT_ALLOW_DUPLI_OBJECTS
@ OB_LAMP
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 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 LRT_DOUBLE_CLOSE_ENOUGH(a, b)
Definition: MOD_lineart.h:588
#define LRT_OBINDEX_LOWER
Definition: MOD_lineart.h:481
#define LRT_SHADOW_MASK_ENCLOSED_SHAPE
Definition: MOD_lineart.h:450
#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_SILHOUETTE_ERASED_GROUP
Definition: MOD_lineart.h:452
#define LRT_SHADOW_MASK_ILLUMINATED
Definition: MOD_lineart.h:448
#define LRT_CLOSE_LOOSER_v3(a, b)
Definition: MOD_lineart.h:592
#define LRT_SHADOW_MASK_SHADED
Definition: MOD_lineart.h:449
@ LRT_ELEMENT_INTERSECTION_DATA
Definition: MOD_lineart.h:75
BLI_INLINE int lineart_line_isec_2d_ignore_line2pos(const double a1[2], const double a2[2], const double b1[2], const double b2[2], double *r_a_ratio)
Definition: MOD_lineart.h:754
@ LRT_SHADOW_CASTED
Definition: MOD_lineart.h:123
@ LRT_SHADOW_FACING_LIGHT
Definition: MOD_lineart.h:124
Platform independent time functions.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
Scene scene
const Depsgraph * depsgraph
void lineart_main_occlusion_begin(LineartData *ld)
Definition: lineart_cpu.c:464
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
bool lineart_edge_from_triangle(const LineartTriangle *tri, const LineartEdge *e, bool allow_overlapping_edges)
Definition: lineart_cpu.c:2708
void lineart_main_bounding_areas_connect_post(LineartData *ld)
Definition: lineart_cpu.c:3911
void lineart_main_add_triangles(LineartData *ld)
Definition: lineart_cpu.c:4663
void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
Definition: lineart_cpu.c:1774
void lineart_main_clear_linked_edges(LineartData *ld)
Definition: lineart_cpu.c:4271
void lineart_main_cull_triangles(LineartData *ld, bool clip_far)
Definition: lineart_cpu.c:1211
void lineart_main_bounding_area_make_initial(LineartData *ld)
Definition: lineart_cpu.c:3696
void lineart_main_free_adjacent_data(LineartData *ld)
Definition: lineart_cpu.c:1346
void lineart_destroy_render_data_keep_init(LineartData *ld)
Definition: lineart_cpu.c:3477
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
void lineart_main_perspective_division(LineartData *ld)
Definition: lineart_cpu.c:1364
void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count)
Definition: lineart_cpu.c:1800
#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)
#define LRT_EDGE_BA_MARCHING_END
#define LRT_ITER_ALL_LINES_END
void lineart_matrix_perspective_44d(double(*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax)
Definition: lineart_util.c:157
#define LRT_ITER_ALL_LINES_BEGIN
void * lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size)
Definition: lineart_util.c:104
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
LineartEdge * lineart_find_matching_edge(LineartElementLinkNode *shadow_eln, uint64_t edge_identifier)
static bool lineart_contour_viewed_from_dark_side(LineartData *ld, LineartEdge *e)
static void lineart_shadow_register_enclosed_shapes(LineartData *ld, LineartData *shadow_ld)
static bool lineart_shadow_cast_generate_edges(LineartData *ld, bool do_original_edges, LineartElementLinkNode **r_veln, LineartElementLinkNode **r_eeln)
static void lineart_shadow_segment_slice_get(double *fb_co_1, double *fb_co_2, double *gloc_1, double *gloc_2, double ratio, double at_1, double at_2, double *r_fb_co, double *r_gloc)
static void lineart_shadow_cast(LineartData *ld, bool transform_edge_cuts, bool do_light_contour)
static void lineart_shadow_register_silhouette(LineartData *ld)
static void lineart_shadow_create_shadow_edge_array(LineartData *ld, bool transform_edge_cuts, bool do_light_contour)
void lineart_register_intersection_shadow_cuts(LineartData *ld, ListBase *shadow_elns)
static bool lineart_shadow_cast_onto_triangle(LineartData *ld, LineartTriangle *tri, LineartShadowEdge *sedge, double *r_at_1, double *r_at_2, double *r_fb_co_1, double *r_fb_co_2, double *r_gloc_1, double *r_gloc_2, bool *r_facing_light)
#define GET_RATIO(n)
bool lineart_main_try_generate_shadow(Depsgraph *depsgraph, Scene *scene, LineartData *original_ld, LineartGpencilModifierData *lmd, LineartStaticMemPool *shadow_data_pool, LineartElementLinkNode **r_veln, LineartElementLinkNode **r_eeln, ListBase *r_calculated_edges_eln_list, LineartData **r_shadow_ld_if_reproject)
static void lineart_shadow_edge_cut(LineartData *ld, LineartShadowEdge *e, double start, double end, double *start_gloc, double *end_gloc, double *start_fb_co, double *end_fb_co, bool facing_light, uint32_t target_reference)
void lineart_main_make_enclosed_shapes(LineartData *ld, LineartData *shadow_ld)
static void lineart_shadow_transform_task(void *__restrict userdata, const int element_index, const TaskParallelTLS *__restrict UNUSED(tls))
static bool lineart_do_closest_segment(bool is_persp, double *s1_fb_co_1, double *s1_fb_co_2, double *s2_fb_co_1, double *s2_fb_co_2, double *s1_gloc_1, double *s1_gloc_2, double *s2_gloc_1, double *s2_gloc_2, double *r_fb_co_1, double *r_fb_co_2, double *r_gloc_1, double *r_gloc_2, double *r_new_in_the_middle, double *r_new_in_the_middle_global, double *r_new_at, bool *is_side_2r, bool *use_new_ref)
static LineartShadowSegment * lineart_give_shadow_segment(LineartData *ld)
LineartElementLinkNode * lineart_find_matching_eln(ListBase *shadow_elns, int obindex)
#define DISCARD_NONSENSE_SEGMENTS
void lineart_register_shadow_cuts(LineartData *ld, LineartEdge *e, LineartEdge *shadow_edge)
static void lineart_shadow_finalize_shadow_edges_task(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
struct LineartShadowFinalizeData LineartShadowFinalizeData
void lineart_main_transform_and_add_shadow(LineartData *ld, LineartElementLinkNode *veln, LineartElementLinkNode *eeln)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
#define G(x, y, z)
unsigned short uint16_t
Definition: stdint.h:79
unsigned int uint32_t
Definition: stdint.h:80
unsigned __int64 uint64_t
Definition: stdint.h:90
short type
float cam_obmat_secondary[4][4]
Definition: MOD_lineart.h:377
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
double camera_pos[3]
Definition: MOD_lineart.h:378
double view[4][4]
Definition: MOD_lineart.h:322
bool allow_overlapping_edges
Definition: MOD_lineart.h:350
float cam_obmat[4][4]
Definition: MOD_lineart.h:376
ListBase vertex_buffer_pointers
Definition: MOD_lineart.h:308
ListBase line_buffer_pointers
Definition: MOD_lineart.h:309
LineartShadowEdge * shadow_edges
Definition: MOD_lineart.h:402
ListBase wasted_shadow_cuts
Definition: MOD_lineart.h:408
LineartStaticMemPool render_data_pool
Definition: MOD_lineart.h:277
struct LineartData::_conf conf
struct LineartData::_geom geom
struct LineartData::_qtree qtree
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
int shadow_edges_count
Definition: MOD_lineart.h:403
LineartStaticMemPool * shadow_data_pool
Definition: MOD_lineart.h:282
struct LineartEdgeSegment * next
Definition: MOD_lineart.h:94
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 LineartVert * v1
Definition: MOD_lineart.h:154
LineartEdge ** array
Definition: MOD_lineart.h:266
ListBase shadow_segments
Definition: MOD_lineart.h:119
struct LineartEdgeSegment * es_ref
Definition: MOD_lineart.h:118
struct LineartEdge * e_ref_light_contour
Definition: MOD_lineart.h:117
struct LineartEdge * e_ref
Definition: MOD_lineart.h:116
struct LineartShadowSegment * next
Definition: MOD_lineart.h:129
uint32_t target_reference
Definition: MOD_lineart.h:141
struct LineartEdge * testing_e[1]
Definition: MOD_lineart.h:68
struct LineartTriangle base
Definition: MOD_lineart.h:59
uint32_t target_reference
Definition: MOD_lineart.h:46
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 * first
Definition: DNA_listBase.h:31
float obmat[4][4]
void * data
double PIL_check_seconds_timer(void)
Definition: time.c:64