diff options
Diffstat (limited to 'source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c')
-rw-r--r-- | source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c | 387 |
1 files changed, 228 insertions, 159 deletions
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 226b8f532b5..7c8e0c5a6f5 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -17,13 +17,16 @@ #define LRT_OTHER_VERT(e, vt) ((vt) == (e)->v1 ? (e)->v2 : ((vt) == (e)->v2 ? (e)->v1 : NULL)) +struct Object; + /* Get a connected line, only for lines who has the exact given vert, or (in the case of * intersection lines) who has a vert that has the exact same position. */ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba, LineartVert *vt, LineartVert **new_vt, int match_flag, - unsigned char match_isec_mask) + uint8_t match_isec_mask, + struct Object *match_isec_object) { for (int i = 0; i < ba->line_count; i++) { LineartEdge *n_e = ba->linked_lines[i]; @@ -46,6 +49,9 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba, } if (n_e->flags & LRT_EDGE_FLAG_INTERSECTION) { + if (n_e->object_ref != match_isec_object) { + continue; + } if (vt->fbcoord[0] == n_e->v1->fbcoord[0] && vt->fbcoord[1] == n_e->v1->fbcoord[1]) { *new_vt = LRT_OTHER_VERT(n_e, n_e->v1); return n_e; @@ -60,12 +66,12 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba, return NULL; } -static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb) +static LineartEdgeChain *lineart_chain_create(LineartData *ld) { LineartEdgeChain *ec; - ec = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChain)); + ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain)); - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); return ec; } @@ -85,14 +91,15 @@ static bool lineart_point_overlapping(LineartEdgeChainItem *eci, return false; } -static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, +static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld, LineartEdgeChain *ec, - float *fbcoord, - float *gpos, - float *normal, - char type, + float fbcoord[4], + float gpos[3], + float normal[3], + uint8_t type, int level, - unsigned char material_mask_bits, + uint8_t material_mask_bits, + uint32_t shadow_mask_bits, size_t index) { LineartEdgeChainItem *eci; @@ -105,10 +112,11 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, old_eci->line_type = type; old_eci->occlusion = level; old_eci->material_mask_bits = material_mask_bits; + old_eci->shadow_mask_bits = shadow_mask_bits; return old_eci; } - eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem)); + eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem)); copy_v4_v4(eci->pos, fbcoord); copy_v3_v3(eci->gpos, gpos); @@ -117,19 +125,21 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb, eci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE; eci->occlusion = level; eci->material_mask_bits = material_mask_bits; + eci->shadow_mask_bits = shadow_mask_bits; BLI_addtail(&ec->chain, eci); return eci; } -static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb, +static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld, LineartEdgeChain *ec, - float *fbcoord, - float *gpos, - float *normal, - char type, + float fbcoord[4], + float gpos[3], + float normal[3], + uint8_t type, int level, - unsigned char material_mask_bits, + uint8_t material_mask_bits, + uint32_t shadow_mask_bits, size_t index) { LineartEdgeChainItem *eci; @@ -138,7 +148,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb return ec->chain.first; } - eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem)); + eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem)); copy_v4_v4(eci->pos, fbcoord); copy_v3_v3(eci->gpos, gpos); @@ -147,19 +157,21 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb eci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE; eci->occlusion = level; eci->material_mask_bits = material_mask_bits; + eci->shadow_mask_bits = shadow_mask_bits; BLI_addhead(&ec->chain, eci); return eci; } -void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) +void MOD_lineart_chain_feature_lines(LineartData *ld) { LineartEdgeChain *ec; LineartEdgeChainItem *eci; LineartBoundingArea *ba; LineartEdgeSegment *es; int last_occlusion; - unsigned char last_transparency; + uint8_t last_transparency; + uint32_t last_shadow; /* Used when converting from double. */ float use_fbcoord[4]; float use_gpos[3]; @@ -181,7 +193,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED; - ec = lineart_chain_create(rb); + ec = lineart_chain_create(ld); /* One chain can only have one object_ref and intersection_mask, * so we assign them based on the first segment we found. */ @@ -207,11 +219,11 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) } /* Step 1: grow left. */ - ba = MOD_lineart_get_bounding_area(rb, e->v1->fbcoord[0], e->v1->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, e->v1->fbcoord[0], e->v1->fbcoord[1]); new_vt = e->v1; es = e->segments.first; VERT_COORD_TO_FLOAT(new_vt); - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -219,9 +231,10 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) e->flags, es->occlusion, es->material_mask_bits, + es->shadow_mask_bits, e->v1->index); while (ba && (new_e = lineart_line_get_connected( - ba, new_vt, &new_vt, e->flags, e->intersection_mask))) { + ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) { new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED; if (new_e->t1 || new_e->t2) { @@ -243,12 +256,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) for (es = new_e->segments.last; es; es = es->prev) { double gpos[3], lpos[3]; double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord; - double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); - interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); + double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]); + interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -256,25 +269,28 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) new_e->flags, es->occlusion, es->material_mask_bits, + es->shadow_mask_bits, new_e->v1->index); last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; } } else if (new_vt == new_e->v2) { es = new_e->segments.first; last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; es = es->next; for (; es; es = es->next) { double gpos[3], lpos[3]; double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord; - double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); - interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); + double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]); + interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -282,12 +298,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) new_e->flags, last_occlusion, last_transparency, + last_shadow, new_e->v2->index); last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; } VERT_COORD_TO_FLOAT(new_e->v2); - lineart_chain_prepend_point(rb, + lineart_chain_prepend_point(ld, ec, use_fbcoord, use_gpos, @@ -295,9 +313,10 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) new_e->flags, last_occlusion, last_transparency, + last_shadow, new_e->v2->index); } - ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]); } /* Restore normal value. */ @@ -318,17 +337,18 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) /* Step 2: Adding all cuts from the given line, so we can continue connecting the right side * of the line. */ es = e->segments.first; - last_occlusion = ((LineartEdgeSegment *)es)->occlusion; - last_transparency = ((LineartEdgeSegment *)es)->material_mask_bits; + last_occlusion = es->occlusion; + last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; for (es = es->next; es; es = es->next) { double gpos[3], lpos[3]; double *lfb = e->v1->fbcoord, *rfb = e->v2->fbcoord; - double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); - interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->at); + double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]); + interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->ratio); interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at); use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -336,12 +356,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) e->flags, es->occlusion, es->material_mask_bits, + es->shadow_mask_bits, e->v1->index); last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; } VERT_COORD_TO_FLOAT(e->v2) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -349,13 +371,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) e->flags, last_occlusion, last_transparency, + last_shadow, e->v2->index); /* Step 3: grow right. */ - ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]); new_vt = e->v2; while (ba && (new_e = lineart_line_get_connected( - ba, new_vt, &new_vt, e->flags, e->intersection_mask))) { + ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) { new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED; if (new_e->t1 || new_e->t2) { @@ -381,20 +404,23 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) es = new_e->segments.last; last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; /* Fix leading vertex occlusion. */ eci->occlusion = last_occlusion; eci->material_mask_bits = last_transparency; + eci->shadow_mask_bits = last_shadow; for (es = new_e->segments.last; es; es = es->prev) { double gpos[3], lpos[3]; double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord; - double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); - interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); + double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]); + interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); last_occlusion = es->prev ? es->prev->occlusion : last_occlusion; last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency; + last_shadow = es->prev ? es->prev->shadow_mask_bits : last_shadow; POS_TO_FLOAT(lpos, gpos) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -402,6 +428,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) new_e->flags, last_occlusion, last_transparency, + last_shadow, new_e->v1->index); } } @@ -409,18 +436,20 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) es = new_e->segments.first; last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; eci->occlusion = last_occlusion; eci->material_mask_bits = last_transparency; + eci->shadow_mask_bits = last_shadow; es = es->next; for (; es; es = es->next) { double gpos[3], lpos[3]; double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord; - double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]); - interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at); + double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]); + interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio); interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at); use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at); POS_TO_FLOAT(lpos, gpos) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -428,12 +457,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) new_e->flags, es->occlusion, es->material_mask_bits, + es->shadow_mask_bits, new_e->v2->index); last_occlusion = es->occlusion; last_transparency = es->material_mask_bits; + last_shadow = es->shadow_mask_bits; } VERT_COORD_TO_FLOAT(new_e->v2) - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, use_fbcoord, use_gpos, @@ -441,11 +472,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) new_e->flags, last_occlusion, last_transparency, + last_shadow, new_e->v2->index); } - ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]); + ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]); } - if (rb->fuzzy_everything) { + if (ld->conf.fuzzy_everything) { ec->type = LRT_EDGE_FLAG_CONTOUR; } else { @@ -455,7 +487,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb) LRT_ITER_ALL_LINES_END } -static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRenderBuffer *rb, +static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartData *ld, LineartBoundingArea *root, LineartEdgeChainItem *eci) { @@ -468,32 +500,32 @@ static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRende ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1] if (IN_BOUND(ch[0], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[0], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[0], eci); } if (IN_BOUND(ch[1], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[1], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[1], eci); } if (IN_BOUND(ch[2], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[2], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[2], eci); } if (IN_BOUND(ch[3], eci)) { - return lineart_bounding_area_get_eci_recursive(rb, &ch[3], eci); + return lineart_bounding_area_get_eci_recursive(ld, &ch[3], eci); } #undef IN_BOUND return NULL; } -static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuffer *rb, +static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartData *ld, LineartEdgeChainItem *eci) { if (!eci) { return NULL; } - LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, eci->pos[0], eci->pos[1]); + LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(ld, eci->pos[0], eci->pos[1]); if (root == NULL) { return NULL; } - return lineart_bounding_area_get_eci_recursive(rb, root, eci); + return lineart_bounding_area_get_eci_recursive(ld, root, eci); } /** @@ -502,14 +534,14 @@ static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuf * areas, this happens either when 1) the geometry is way too dense, or 2) the chaining threshold * is too big that it covers multiple small bounding areas. */ -static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb, +static void lineart_bounding_area_link_point_recursive(LineartData *ld, LineartBoundingArea *root, LineartEdgeChain *ec, LineartEdgeChainItem *eci) { if (root->child == NULL) { LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized( - &root->linked_chains, &rb->render_data_pool, ec, sizeof(LineartChainRegisterEntry)); + &root->linked_chains, ld->chain_data_pool, ec, sizeof(LineartChainRegisterEntry)); cre->eci = eci; @@ -524,34 +556,34 @@ static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb, ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1] if (IN_BOUND(ch[0], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[0], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[0], ec, eci); } else if (IN_BOUND(ch[1], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[1], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[1], ec, eci); } else if (IN_BOUND(ch[2], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[2], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[2], ec, eci); } else if (IN_BOUND(ch[3], eci)) { - lineart_bounding_area_link_point_recursive(rb, &ch[3], ec, eci); + lineart_bounding_area_link_point_recursive(ld, &ch[3], ec, eci); } #undef IN_BOUND } } -static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdgeChain *ec) +static void lineart_bounding_area_link_chain(LineartData *ld, LineartEdgeChain *ec) { LineartEdgeChainItem *pl = ec->chain.first; LineartEdgeChainItem *pr = ec->chain.last; - LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(rb, pl->pos[0], pl->pos[1]); - LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(rb, pr->pos[0], pr->pos[1]); + LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(ld, pl->pos[0], pl->pos[1]); + LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(ld, pr->pos[0], pr->pos[1]); if (ba1) { - lineart_bounding_area_link_point_recursive(rb, ba1, ec, pl); + lineart_bounding_area_link_point_recursive(ld, ba1, ec, pl); } if (ba2) { - lineart_bounding_area_link_point_recursive(rb, ba2, ec, pr); + lineart_bounding_area_link_point_recursive(ld, ba2, ec, pr); } } @@ -564,7 +596,8 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, float dist_accum = 0; int fixed_occ = last_matching_eci->occlusion; - unsigned char fixed_mask = last_matching_eci->material_mask_bits; + uint8_t fixed_mask = last_matching_eci->material_mask_bits; + uint32_t fixed_shadow = last_matching_eci->shadow_mask_bits; LineartEdgeChainItem *can_skip_to = NULL; LineartEdgeChainItem *last_eci = last_matching_eci; @@ -579,7 +612,8 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, if (eci->occlusion < fixed_occ) { break; } - if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) { + if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ && + eci->shadow_mask_bits == fixed_shadow) { can_skip_to = eci; } } @@ -589,12 +623,14 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, LineartEdgeChainItem *next_eci; for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) { next_eci = eci->next; - if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) { + if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ && + eci->shadow_mask_bits == fixed_shadow) { continue; } if (preserve_details) { eci->material_mask_bits = fixed_mask; eci->occlusion = fixed_occ; + eci->shadow_mask_bits = fixed_shadow; } else { BLI_remlink(&ec->chain, eci); @@ -606,41 +642,44 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec, return false; } -void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) +void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld) { LineartEdgeChain *ec, *new_ec; LineartEdgeChainItem *eci, *next_eci; ListBase swap = {0}; - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; int loop_id = 0; while ((ec = BLI_pophead(&swap)) != NULL) { ec->next = ec->prev = NULL; - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); ec->loop_id = loop_id; loop_id++; LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; int fixed_occ = first_eci->occlusion; - unsigned char fixed_mask = first_eci->material_mask_bits; + uint8_t fixed_mask = first_eci->material_mask_bits; + uint32_t fixed_shadow = first_eci->shadow_mask_bits; ec->level = fixed_occ; ec->material_mask_bits = fixed_mask; + ec->shadow_mask_bits = fixed_shadow; for (eci = first_eci->next; eci; eci = next_eci) { next_eci = eci->next; - if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask) { + if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask || + eci->shadow_mask_bits != fixed_shadow) { if (next_eci) { if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) { continue; } if (lineart_chain_fix_ambiguous_segments(ec, eci->prev, - rb->chaining_image_threshold, - rb->chain_preserve_details, + ld->conf.chaining_image_threshold, + ld->conf.chain_preserve_details, &next_eci)) { continue; } @@ -649,11 +688,12 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) /* Set the same occlusion level for the end vertex, so when further connection is needed * the backwards occlusion info is also correct. */ eci->occlusion = fixed_occ; + eci->shadow_mask_bits = fixed_shadow; eci->material_mask_bits = fixed_mask; /* No need to split at the last point anyway. */ break; } - new_ec = lineart_chain_create(rb); + new_ec = lineart_chain_create(ld); new_ec->chain.first = eci; new_ec->chain.last = ec->chain.last; new_ec->loop_id = loop_id; @@ -662,7 +702,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) eci->prev = 0; /* End the previous one. */ - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, eci->pos, eci->gpos, @@ -670,6 +710,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) eci->line_type, fixed_occ, fixed_mask, + fixed_shadow, eci->index); new_ec->object_ref = ec->object_ref; new_ec->type = ec->type; @@ -677,22 +718,25 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) ec = new_ec; fixed_occ = eci->occlusion; fixed_mask = eci->material_mask_bits; + fixed_shadow = eci->shadow_mask_bits; ec->level = fixed_occ; ec->material_mask_bits = fixed_mask; + ec->shadow_mask_bits = fixed_shadow; } } } - /* Get rid of those very short "zig-zag" lines that jumps around visibility. */ - MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM); - LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) { - lineart_bounding_area_link_chain(rb, iec); + + MOD_lineart_chain_discard_unused(ld, DBL_EDGE_LIM, ld->conf.max_occlusion_level); + + LISTBASE_FOREACH (LineartEdgeChain *, iec, &ld->chains) { + lineart_bounding_area_link_chain(ld, iec); } } /** * NOTE: segment type (crease/material/contour...) is ambiguous after this. */ -static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb), +static void lineart_chain_connect(LineartData *UNUSED(ld), LineartEdgeChain *onto, LineartEdgeChain *sub, int reverse_1, @@ -742,13 +786,14 @@ static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb), } } -static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuffer *rb, +static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld, LineartBoundingArea *ba, LineartEdgeChain *ec, LineartEdgeChainItem *eci, int occlusion, - unsigned char material_mask_bits, - unsigned char isec_mask, + uint8_t material_mask_bits, + uint8_t isec_mask, + uint32_t shadow_mask, int loop_id, float dist, float *result_new_len, @@ -761,8 +806,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf * next one. */ LISTBASE_FOREACH_MUTABLE (LineartChainRegisterEntry *, cre, &ba->linked_chains) { if (cre->ec->object_ref != ec->object_ref) { - if (!rb->fuzzy_everything) { - if (rb->fuzzy_intersections) { + if (!ld->conf.fuzzy_everything) { + if (ld->conf.fuzzy_intersections) { /* If none of those are intersection lines... */ if ((!(cre->ec->type & LRT_EDGE_FLAG_INTERSECTION)) && (!(ec->type & LRT_EDGE_FLAG_INTERSECTION))) { @@ -779,12 +824,12 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf } if (cre->ec == ec || (!cre->ec->chain.first) || (cre->ec->level != occlusion) || (cre->ec->material_mask_bits != material_mask_bits) || - (cre->ec->intersection_mask != isec_mask)) { + (cre->ec->intersection_mask != isec_mask) || (cre->ec->shadow_mask_bits != shadow_mask)) { continue; } - if (!rb->fuzzy_everything) { + if (!ld->conf.fuzzy_everything) { if (cre->ec->type != ec->type) { - if (rb->fuzzy_intersections) { + if (ld->conf.fuzzy_intersections) { if (!(cre->ec->type == LRT_EDGE_FLAG_INTERSECTION || ec->type == LRT_EDGE_FLAG_INTERSECTION)) { continue; /* Fuzzy intersections but no intersection line found. */ @@ -796,8 +841,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf } } - float new_len = rb->use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) : - len_v2v2(cre->eci->pos, eci->pos); + float new_len = ld->conf.use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) : + len_v2v2(cre->eci->pos, eci->pos); /* Even if the vertex is not from the same contour loop, we try to chain it still if the * distance is small enough. This way we can better chain smaller loops and smooth them out * later. */ @@ -817,15 +862,16 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf #define LRT_TEST_ADJACENT_AREAS(dist_to, list) \ if (dist_to < dist && dist_to > 0) { \ - LISTBASE_FOREACH (LinkData *, ld, list) { \ - LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \ - adjacent_closest = lineart_chain_get_closest_cre(rb, \ + LISTBASE_FOREACH (LinkData *, link, list) { \ + LineartBoundingArea *sba = (LineartBoundingArea *)link->data; \ + adjacent_closest = lineart_chain_get_closest_cre(ld, \ sba, \ ec, \ eci, \ occlusion, \ material_mask_bits, \ isec_mask, \ + shadow_mask, \ loop_id, \ dist, \ &adjacent_new_len, \ @@ -848,65 +894,69 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf return closest_cre; } -void MOD_lineart_chain_connect(LineartRenderBuffer *rb) +void MOD_lineart_chain_connect(LineartData *ld) { LineartEdgeChain *ec; LineartEdgeChainItem *eci_l, *eci_r; LineartBoundingArea *ba_l, *ba_r; LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre; - float dist = rb->chaining_image_threshold; + float dist = ld->conf.chaining_image_threshold; float dist_l, dist_r; - int occlusion, reverse_main, loop_id; - unsigned char material_mask_bits, isec_mask; + int reverse_main, loop_id; + uint8_t occlusion, material_mask_bits, isec_mask; + uint32_t shadow_mask; ListBase swap = {0}; - if (rb->chaining_image_threshold < 0.0001) { + if (ld->conf.chaining_image_threshold < 0.0001) { return; } - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; while ((ec = BLI_pophead(&swap)) != NULL) { ec->next = ec->prev = NULL; - if (ec->picked) { + if (ec->picked || ec->chain.first == ec->chain.last) { continue; } - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); loop_id = ec->loop_id; - if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) { + if (ec->type == LRT_EDGE_FLAG_LOOSE && (!ld->conf.use_loose_edge_chain)) { continue; } occlusion = ec->level; material_mask_bits = ec->material_mask_bits; isec_mask = ec->intersection_mask; + shadow_mask = ec->shadow_mask_bits; eci_l = ec->chain.first; eci_r = ec->chain.last; - while ((ba_l = lineart_bounding_area_get_end_point(rb, eci_l)) && - (ba_r = lineart_bounding_area_get_end_point(rb, eci_r))) { - closest_cre_l = lineart_chain_get_closest_cre(rb, + while ((ba_l = lineart_bounding_area_get_end_point(ld, eci_l)) && + (ba_r = lineart_bounding_area_get_end_point(ld, eci_r))) { + closest_cre_l = lineart_chain_get_closest_cre(ld, ba_l, ec, eci_l, occlusion, material_mask_bits, isec_mask, + shadow_mask, loop_id, dist, &dist_l, NULL); - closest_cre_r = lineart_chain_get_closest_cre(rb, + closest_cre_r = lineart_chain_get_closest_cre(ld, ba_r, ec, eci_r, occlusion, material_mask_bits, isec_mask, + shadow_mask, loop_id, dist, &dist_r, @@ -936,10 +986,10 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb) closest_cre->picked = 1; closest_cre->ec->picked = 1; if (closest_cre->is_left) { - lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 0); + lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 0); } else { - lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 1); + lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 1); } BLI_remlink(&swap, closest_cre->ec); eci_l = ec->chain.first; @@ -969,13 +1019,15 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec) return offset_accum; } -void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold) +void MOD_lineart_chain_discard_unused(LineartData *ld, + const float threshold, + uint8_t max_occlusion) { LineartEdgeChain *ec, *next_ec; - for (ec = rb->chains.first; ec; ec = next_ec) { + for (ec = ld->chains.first; ec; ec = next_ec) { next_ec = ec->next; - if (MOD_lineart_chain_compute_length(ec) < threshold) { - BLI_remlink(&rb->chains, ec); + if (ec->level > max_occlusion || MOD_lineart_chain_compute_length(ec) < threshold) { + BLI_remlink(&ld->chains, ec); } } } @@ -999,9 +1051,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) } } -void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) +void MOD_lineart_smooth_chains(LineartData *ld, float tolerance) { - LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { /* Go through the chain two times, once from each direction. */ for (int times = 0; times < 2; times++) { for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci; @@ -1067,25 +1119,27 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance) } } -static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb, +static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartData *ld, LineartEdgeChainItem *eci_inside, LineartEdgeChainItem *eci_outside) { float isec[2]; - float LU[2] = {-1.0f, 1.0f}, LB[2] = {-1.0f, -1.0f}, RU[2] = {1.0f, 1.0f}, RB[2] = {1.0f, -1.0f}; + /* l: left, r: right, b: bottom, u: top. */ + float ref_lu[2] = {-1.0f, 1.0f}, ref_lb[2] = {-1.0f, -1.0f}, ref_ru[2] = {1.0f, 1.0f}, + ref_rb[2] = {1.0f, -1.0f}; bool found = false; LineartEdgeChainItem *eci2 = eci_outside, *eci1 = eci_inside; if (eci2->pos[0] < -1.0f) { - found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, LB, isec) > 0); + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_lb, isec) > 0); } if (!found && eci2->pos[0] > 1.0f) { - found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, RU, RB, isec) > 0); + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_ru, ref_rb, isec) > 0); } if (!found && eci2->pos[1] < -1.0f) { - found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LB, RB, isec) > 0); + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lb, ref_rb, isec) > 0); } if (!found && eci2->pos[1] > 1.0f) { - found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, RU, isec) > 0); + found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_ru, isec) > 0); } if (UNLIKELY(!found)) { @@ -1097,7 +1151,7 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu ratiof(eci1->pos[1], eci2->pos[1], isec[1]); float gratio = eci1->pos[3] * ratio / (ratio * eci1->pos[3] + (1 - ratio) * eci2->pos[3]); - LineartEdgeChainItem *eci = lineart_mem_acquire(rb->chain_data_pool, + LineartEdgeChainItem *eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem)); memcpy(eci, eci1, sizeof(LineartEdgeChainItem)); interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio); @@ -1111,22 +1165,22 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu ((eci)->pos[0] >= -1.0f && (eci)->pos[0] <= 1.0f && (eci)->pos[1] >= -1.0f && \ (eci)->pos[1] <= 1.0f) -void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) +void MOD_lineart_chain_clip_at_border(LineartData *ld) { LineartEdgeChain *ec; LineartEdgeChainItem *eci, *next_eci, *prev_eci, *new_eci; bool is_inside, new_inside; ListBase swap = {0}; - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; while ((ec = BLI_pophead(&swap)) != NULL) { bool ec_added = false; LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; is_inside = LRT_ECI_INSIDE(first_eci) ? true : false; if (!is_inside) { - ec->picked = true; + ec->picked = 1; } for (eci = first_eci->next; eci; eci = next_eci) { next_eci = eci->next; @@ -1137,9 +1191,9 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) if ((new_inside = LRT_ECI_INSIDE(eci)) != is_inside) { if (new_inside == false) { /* Stroke goes out. */ - new_eci = lineart_chain_create_crossing_point(rb, prev_eci, eci); + new_eci = lineart_chain_create_crossing_point(ld, prev_eci, eci); - LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool, + LineartEdgeChain *new_ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain)); memcpy(new_ec, ec, sizeof(LineartEdgeChain)); new_ec->chain.first = next_eci; @@ -1147,7 +1201,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) prev_eci->next = NULL; ec->chain.last = prev_eci; BLI_addtail(&ec->chain, new_eci); - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); ec_added = true; ec = new_ec; @@ -1156,7 +1210,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) continue; } /* Stroke comes in. */ - new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci); + new_eci = lineart_chain_create_crossing_point(ld, eci, prev_eci); ec->chain.first = eci; eci->prev = NULL; @@ -1172,25 +1226,25 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb) } if ((!ec_added) && is_inside) { - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); } } } -void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad) +void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad) { LineartEdgeChain *ec, *new_ec; LineartEdgeChainItem *eci, *next_eci, *prev_eci; ListBase swap = {0}; - swap.first = rb->chains.first; - swap.last = rb->chains.last; + swap.first = ld->chains.first; + swap.last = ld->chains.last; - rb->chains.last = rb->chains.first = NULL; + ld->chains.last = ld->chains.first = NULL; while ((ec = BLI_pophead(&swap)) != NULL) { ec->next = ec->prev = NULL; - BLI_addtail(&rb->chains, ec); + BLI_addtail(&ld->chains, ec); LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first; for (eci = first_eci->next; eci; eci = next_eci) { next_eci = eci->next; @@ -1203,7 +1257,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol break; /* No need to split at the last point anyway. */ } if (angle < angle_threshold_rad) { - new_ec = lineart_chain_create(rb); + new_ec = lineart_chain_create(ld); new_ec->chain.first = eci; new_ec->chain.last = ec->chain.last; ec->chain.last = eci->prev; @@ -1211,7 +1265,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol eci->prev = 0; /* End the previous one. */ - lineart_chain_append_point(rb, + lineart_chain_append_point(ld, ec, eci->pos, eci->gpos, @@ -1219,6 +1273,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol eci->line_type, ec->level, eci->material_mask_bits, + eci->shadow_mask_bits, eci->index); new_ec->object_ref = ec->object_ref; new_ec->type = ec->type; @@ -1226,46 +1281,44 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol new_ec->loop_id = ec->loop_id; new_ec->intersection_mask = ec->intersection_mask; new_ec->material_mask_bits = ec->material_mask_bits; + new_ec->shadow_mask_bits = ec->shadow_mask_bits; ec = new_ec; } } } } -void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, - float dist, - bool use_custom_camera) +void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera) { float dir[3]; float cam[3]; float view[3]; float view_clamp[3]; - copy_v3fl_v3db(cam, rb->camera_pos); - copy_v3fl_v3db(view, rb->view_vector); if (use_custom_camera) { - copy_v3fl_v3db(cam, rb->camera_pos); + copy_v3fl_v3db(cam, ld->conf.camera_pos); } else { - copy_v3fl_v3db(cam, rb->active_camera_pos); + copy_v3fl_v3db(cam, ld->conf.active_camera_pos); } - if (rb->cam_is_persp) { - LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + if (ld->conf.cam_is_persp) { + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { sub_v3_v3v3(dir, cam, eci->gpos); float orig_len = len_v3(dir); normalize_v3(dir); - mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip)); + mul_v3_fl(dir, MIN2(dist, orig_len - ld->conf.near_clip)); add_v3_v3(eci->gpos, dir); } } } else { - LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) { + copy_v3fl_v3db(view, ld->conf.view_vector); + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { sub_v3_v3v3(dir, cam, eci->gpos); - float len_lim = dot_v3v3(view, dir) - rb->near_clip; + float len_lim = dot_v3v3(view, dir) - ld->conf.near_clip; normalize_v3_v3(view_clamp, view); mul_v3_fl(view_clamp, MIN2(dist, len_lim)); add_v3_v3(eci->gpos, view_clamp); @@ -1273,3 +1326,19 @@ void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, } } } + +void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld) +{ + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { + if (ec->type == LRT_EDGE_FLAG_CONTOUR && + ec->shadow_mask_bits & LRT_SHADOW_SILHOUETTE_ERASED_GROUP) { + uint32_t target = ec->shadow_mask_bits & LRT_OBINDEX_HIGHER; + LineartElementLinkNode *eln = lineart_find_matching_eln(&ld->geom.line_buffer_pointers, + target); + if (!eln) { + continue; + } + ec->silhouette_backdrop = eln->object_ref; + } + } +} |