Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc
- This file was moved from source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c.
| Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_modifier_types.h" | #include "DNA_modifier_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "lineart_intern.h" | #include "lineart_intern.h" | ||||
| typedef struct LineartIsecSingle { | struct LineartIsecSingle { | ||||
| double v1[3], v2[3]; | double v1[3], v2[3]; | ||||
| LineartTriangle *tri1, *tri2; | LineartTriangle *tri1, *tri2; | ||||
| } LineartIsecSingle; | }; | ||||
| typedef struct LineartIsecThread { | struct LineartIsecThread { | ||||
| int thread_id; | int thread_id; | ||||
| /* Scheduled work range. */ | /* Scheduled work range. */ | ||||
| LineartElementLinkNode *pending_from; | LineartElementLinkNode *pending_from; | ||||
| LineartElementLinkNode *pending_to; | LineartElementLinkNode *pending_to; | ||||
| int index_from; | int index_from; | ||||
| int index_to; | int index_to; | ||||
| /* Thread intersection result data. */ | /* Thread intersection result data. */ | ||||
| LineartIsecSingle *array; | LineartIsecSingle *array; | ||||
| int current; | int current; | ||||
| int max; | int max; | ||||
| int count_test; | int count_test; | ||||
| /* For individual thread reference. */ | /* For individual thread reference. */ | ||||
| LineartData *ld; | LineartData *ld; | ||||
| } LineartIsecThread; | }; | ||||
| typedef struct LineartIsecData { | struct LineartIsecData { | ||||
| LineartData *ld; | LineartData *ld; | ||||
| LineartIsecThread *threads; | LineartIsecThread *threads; | ||||
| int thread_count; | int thread_count; | ||||
| } LineartIsecData; | }; | ||||
| static void lineart_bounding_area_link_edge(LineartData *ld, | static void lineart_bounding_area_link_edge(LineartData *ld, | ||||
| LineartBoundingArea *root_ba, | LineartBoundingArea *root_ba, | ||||
| LineartEdge *e); | LineartEdge *e); | ||||
| static bool lineart_get_edge_bounding_areas( | static bool lineart_get_edge_bounding_areas( | ||||
| LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend); | LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend); | ||||
| Show All 11 Lines | |||||
| static void lineart_bounding_area_link_triangle(LineartData *ld, | static void lineart_bounding_area_link_triangle(LineartData *ld, | ||||
| LineartBoundingArea *root_ba, | LineartBoundingArea *root_ba, | ||||
| LineartTriangle *tri, | LineartTriangle *tri, | ||||
| double l_r_u_b[4], | double l_r_u_b[4], | ||||
| int recursive, | int recursive, | ||||
| int recursive_level, | int recursive_level, | ||||
| bool do_intersection, | bool do_intersection, | ||||
| struct LineartIsecThread *th); | LineartIsecThread *th); | ||||
| static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive); | static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive); | ||||
| static void lineart_free_bounding_area_memories(LineartData *ld); | static void lineart_free_bounding_area_memories(LineartData *ld); | ||||
| static LineartCache *lineart_init_cache(void); | static LineartCache *lineart_init_cache(void); | ||||
| static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es) | static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es) | ||||
| Show All 33 Lines | |||||
| void lineart_edge_cut(LineartData *ld, | void lineart_edge_cut(LineartData *ld, | ||||
| LineartEdge *e, | LineartEdge *e, | ||||
| double start, | double start, | ||||
| double end, | double end, | ||||
| uchar material_mask_bits, | uchar material_mask_bits, | ||||
| uchar mat_occlusion, | uchar mat_occlusion, | ||||
| uint32_t shadow_bits) | uint32_t shadow_bits) | ||||
| { | { | ||||
| LineartEdgeSegment *seg, *i_seg, *next_seg, *prev_seg; | LineartEdgeSegment *i_seg, *prev_seg; | ||||
| LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0; | LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0; | ||||
| LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0; | LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0; | ||||
| int untouched = 0; | int untouched = 0; | ||||
| /* If for some reason the occlusion function may give a result that has zero length, or reversed | /* If for some reason the occlusion function may give a result that has zero length, or reversed | ||||
| * in direction, or NAN, we take care of them here. */ | * in direction, or NAN, we take care of them here. */ | ||||
| if (LRT_DOUBLE_CLOSE_ENOUGH(start, end)) { | if (LRT_DOUBLE_CLOSE_ENOUGH(start, end)) { | ||||
| return; | return; | ||||
| Show All 12 Lines | if (start > end) { | ||||
| double t = start; | double t = start; | ||||
| start = end; | start = end; | ||||
| end = t; | end = t; | ||||
| } | } | ||||
| /* Begin looking for starting position of the segment. */ | /* Begin looking for starting position of the segment. */ | ||||
| /* Not using a list iteration macro because of it more clear when using for loops to iterate | /* Not using a list iteration macro because of it more clear when using for loops to iterate | ||||
| * through the segments. */ | * through the segments. */ | ||||
| for (seg = e->segments.first; seg; seg = seg->next) { | LISTBASE_FOREACH (LineartEdgeSegment *, seg, &e->segments) { | ||||
| if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, start)) { | if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, start)) { | ||||
| cut_start_before = seg; | cut_start_before = seg; | ||||
| new_seg1 = cut_start_before; | new_seg1 = cut_start_before; | ||||
| break; | break; | ||||
| } | } | ||||
| if (seg->next == NULL) { | if (seg->next == nullptr) { | ||||
| break; | break; | ||||
| } | } | ||||
| i_seg = seg->next; | i_seg = seg->next; | ||||
| if (i_seg->ratio > start + 1e-09 && start > seg->ratio) { | if (i_seg->ratio > start + 1e-09 && start > seg->ratio) { | ||||
| cut_start_before = i_seg; | cut_start_before = i_seg; | ||||
| new_seg1 = lineart_give_segment(ld); | new_seg1 = lineart_give_segment(ld); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { | if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { | ||||
| untouched = 1; | untouched = 1; | ||||
| } | } | ||||
| for (seg = cut_start_before; seg; seg = seg->next) { | for (LineartEdgeSegment *seg = cut_start_before; seg; seg = seg->next) { | ||||
| /* We tried to cut ratio existing cutting point (e.g. where the line's occluded by a triangle | /* We tried to cut ratio existing cutting point (e.g. where the line's occluded by a triangle | ||||
| * strip). */ | * strip). */ | ||||
| if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, end)) { | if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, end)) { | ||||
| cut_end_before = seg; | cut_end_before = seg; | ||||
| new_seg2 = cut_end_before; | new_seg2 = cut_end_before; | ||||
| break; | break; | ||||
| } | } | ||||
| /* This check is to prevent `es->ratio == 1.0` (where we don't need to cut because we are ratio | /* This check is to prevent `es->ratio == 1.0` (where we don't need to cut because we are ratio | ||||
| * the end point). */ | * the end point). */ | ||||
| if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { | if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) { | ||||
| cut_end_before = seg; | cut_end_before = seg; | ||||
| new_seg2 = cut_end_before; | new_seg2 = cut_end_before; | ||||
| untouched = 1; | untouched = 1; | ||||
| break; | break; | ||||
| } | } | ||||
| /* When an actual cut is needed in the line. */ | /* When an actual cut is needed in the line. */ | ||||
| if (seg->ratio > end) { | if (seg->ratio > end) { | ||||
| cut_end_before = seg; | cut_end_before = seg; | ||||
| new_seg2 = lineart_give_segment(ld); | new_seg2 = lineart_give_segment(ld); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* When we still can't find any existing cut in the line, we allocate new ones. */ | /* When we still can't find any existing cut in the line, we allocate new ones. */ | ||||
| if (new_seg1 == NULL) { | if (new_seg1 == nullptr) { | ||||
| new_seg1 = lineart_give_segment(ld); | new_seg1 = lineart_give_segment(ld); | ||||
| } | } | ||||
| if (new_seg2 == NULL) { | if (new_seg2 == nullptr) { | ||||
| if (untouched) { | if (untouched) { | ||||
| new_seg2 = new_seg1; | new_seg2 = new_seg1; | ||||
| cut_end_before = new_seg2; | cut_end_before = new_seg2; | ||||
| } | } | ||||
| else { | else { | ||||
| new_seg2 = lineart_give_segment(ld); | new_seg2 = lineart_give_segment(ld); | ||||
| } | } | ||||
| } | } | ||||
| if (cut_start_before) { | if (cut_start_before) { | ||||
| if (cut_start_before != new_seg1) { | if (cut_start_before != new_seg1) { | ||||
| /* Insert cutting points for when a new cut is needed. */ | /* Insert cutting points for when a new cut is needed. */ | ||||
| i_seg = cut_start_before->prev ? cut_start_before->prev : NULL; | i_seg = cut_start_before->prev ? cut_start_before->prev : nullptr; | ||||
| if (i_seg) { | if (i_seg) { | ||||
| new_seg1->occlusion = i_seg->occlusion; | new_seg1->occlusion = i_seg->occlusion; | ||||
| new_seg1->material_mask_bits = i_seg->material_mask_bits; | new_seg1->material_mask_bits = i_seg->material_mask_bits; | ||||
| new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits; | new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits; | ||||
| } | } | ||||
| BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1); | BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1); | ||||
| } | } | ||||
| /* Otherwise we already found a existing cutting point, no need to insert a new one. */ | /* Otherwise we already found a existing cutting point, no need to insert a new one. */ | ||||
| } | } | ||||
| else { | else { | ||||
| /* We have yet to reach a existing cutting point even after we searched the whole line, so we | /* We have yet to reach a existing cutting point even after we searched the whole line, so we | ||||
| * append the new cut to the end. */ | * append the new cut to the end. */ | ||||
| i_seg = e->segments.last; | i_seg = static_cast<LineartEdgeSegment *>(e->segments.last); | ||||
| new_seg1->occlusion = i_seg->occlusion; | new_seg1->occlusion = i_seg->occlusion; | ||||
| new_seg1->material_mask_bits = i_seg->material_mask_bits; | new_seg1->material_mask_bits = i_seg->material_mask_bits; | ||||
| new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits; | new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits; | ||||
| BLI_addtail(&e->segments, new_seg1); | BLI_addtail(&e->segments, new_seg1); | ||||
| } | } | ||||
| if (cut_end_before) { | if (cut_end_before) { | ||||
| /* The same manipulation as on "cut_start_before". */ | /* The same manipulation as on "cut_start_before". */ | ||||
| if (cut_end_before != new_seg2) { | if (cut_end_before != new_seg2) { | ||||
| i_seg = cut_end_before->prev ? cut_end_before->prev : NULL; | i_seg = cut_end_before->prev ? cut_end_before->prev : nullptr; | ||||
| if (i_seg) { | if (i_seg) { | ||||
| new_seg2->occlusion = i_seg->occlusion; | new_seg2->occlusion = i_seg->occlusion; | ||||
| new_seg2->material_mask_bits = i_seg->material_mask_bits; | new_seg2->material_mask_bits = i_seg->material_mask_bits; | ||||
| new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits; | new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits; | ||||
| } | } | ||||
| BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2); | BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| i_seg = e->segments.last; | i_seg = static_cast<LineartEdgeSegment *>(e->segments.last); | ||||
| new_seg2->occlusion = i_seg->occlusion; | new_seg2->occlusion = i_seg->occlusion; | ||||
| new_seg2->material_mask_bits = i_seg->material_mask_bits; | new_seg2->material_mask_bits = i_seg->material_mask_bits; | ||||
| new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits; | new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits; | ||||
| if (!untouched) { | if (!untouched) { | ||||
| BLI_addtail(&e->segments, new_seg2); | BLI_addtail(&e->segments, new_seg2); | ||||
| } | } | ||||
| } | } | ||||
| /* If we touched the cut list, we assign the new cut position based on new cut position, | /* If we touched the cut list, we assign the new cut position based on new cut position, | ||||
| * this way we accommodate precision lost due to multiple cut inserts. */ | * this way we accommodate precision lost due to multiple cut inserts. */ | ||||
| new_seg1->ratio = start; | new_seg1->ratio = start; | ||||
| if (!untouched) { | if (!untouched) { | ||||
| new_seg2->ratio = end; | new_seg2->ratio = end; | ||||
| } | } | ||||
| else { | else { | ||||
| /* For the convenience of the loop below. */ | /* For the convenience of the loop below. */ | ||||
| new_seg2 = new_seg2->next; | new_seg2 = new_seg2->next; | ||||
| } | } | ||||
| /* Register 1 level of occlusion for all touched segments. */ | /* Register 1 level of occlusion for all touched segments. */ | ||||
| for (seg = new_seg1; seg && seg != new_seg2; seg = seg->next) { | for (LineartEdgeSegment *seg = new_seg1; seg && seg != new_seg2; seg = seg->next) { | ||||
| seg->occlusion += mat_occlusion; | seg->occlusion += mat_occlusion; | ||||
| seg->material_mask_bits |= material_mask_bits; | seg->material_mask_bits |= material_mask_bits; | ||||
| /* The enclosed shape flag will override regular lit/shaded | /* The enclosed shape flag will override regular lit/shaded | ||||
| * flags. See LineartEdgeSegment::shadow_mask_bits for details. */ | * flags. See LineartEdgeSegment::shadow_mask_bits for details. */ | ||||
| if (shadow_bits == LRT_SHADOW_MASK_ENCLOSED_SHAPE) { | if (shadow_bits == LRT_SHADOW_MASK_ENCLOSED_SHAPE) { | ||||
| if (seg->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED || | if (seg->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED || | ||||
| e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) { | e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) { | ||||
| seg->shadow_mask_bits |= LRT_SHADOW_MASK_INHIBITED; | seg->shadow_mask_bits |= LRT_SHADOW_MASK_INHIBITED; | ||||
| } | } | ||||
| else if (seg->shadow_mask_bits & LRT_SHADOW_MASK_SHADED) { | else if (seg->shadow_mask_bits & LRT_SHADOW_MASK_SHADED) { | ||||
| seg->shadow_mask_bits |= LRT_SHADOW_MASK_ILLUMINATED_SHAPE; | seg->shadow_mask_bits |= LRT_SHADOW_MASK_ILLUMINATED_SHAPE; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| seg->shadow_mask_bits |= shadow_bits; | seg->shadow_mask_bits |= shadow_bits; | ||||
| } | } | ||||
| } | } | ||||
| /* Reduce adjacent cutting points of the same level, which saves memory. */ | /* Reduce adjacent cutting points of the same level, which saves memory. */ | ||||
| int8_t min_occ = 127; | int8_t min_occ = 127; | ||||
| prev_seg = NULL; | prev_seg = nullptr; | ||||
| for (seg = e->segments.first; seg; seg = next_seg) { | LISTBASE_FOREACH_MUTABLE (LineartEdgeSegment *, seg, &e->segments) { | ||||
| next_seg = seg->next; | |||||
| if (prev_seg && prev_seg->occlusion == seg->occlusion && | if (prev_seg && prev_seg->occlusion == seg->occlusion && | ||||
| prev_seg->material_mask_bits == seg->material_mask_bits && | prev_seg->material_mask_bits == seg->material_mask_bits && | ||||
| prev_seg->shadow_mask_bits == seg->shadow_mask_bits) { | prev_seg->shadow_mask_bits == seg->shadow_mask_bits) { | ||||
| BLI_remlink(&e->segments, seg); | BLI_remlink(&e->segments, seg); | ||||
| /* This puts the node back to the render buffer, if more cut happens, these unused nodes get | /* This puts the node back to the render buffer, if more cut happens, these unused nodes get | ||||
| * picked first. */ | * picked first. */ | ||||
| lineart_discard_segment(ld, seg); | lineart_discard_segment(ld, seg); | ||||
| Show All 14 Lines | |||||
| { | { | ||||
| return (((e->target_reference & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference) || | return (((e->target_reference & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference) || | ||||
| (((e->target_reference >> 32) & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference)); | (((e->target_reference >> 32) & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference)); | ||||
| } | } | ||||
| static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba) | static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba) | ||||
| { | { | ||||
| ba->max_triangle_count *= 2; | ba->max_triangle_count *= 2; | ||||
| ba->linked_triangles = MEM_recallocN(ba->linked_triangles, | ba->linked_triangles = static_cast<LineartTriangle **>( | ||||
| sizeof(LineartTriangle *) * ba->max_triangle_count); | MEM_recallocN(ba->linked_triangles, sizeof(LineartTriangle *) * ba->max_triangle_count)); | ||||
| } | } | ||||
| static void lineart_bounding_area_line_add(LineartBoundingArea *ba, LineartEdge *e) | static void lineart_bounding_area_line_add(LineartBoundingArea *ba, LineartEdge *e) | ||||
| { | { | ||||
| /* In case of too many lines concentrating in one point, do not add anymore, these lines will | /* In case of too many lines concentrating in one point, do not add anymore, these lines will | ||||
| * be either shorter than a single pixel, or will still be added into the list of other less | * be either shorter than a single pixel, or will still be added into the list of other less | ||||
| * dense areas. */ | * dense areas. */ | ||||
| if (ba->line_count >= 65535) { | if (ba->line_count >= 65535) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (ba->line_count >= ba->max_line_count) { | if (ba->line_count >= ba->max_line_count) { | ||||
| LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * ba->max_line_count * 2, | LineartEdge **new_array = static_cast<LineartEdge **>( | ||||
| "new ba_line_array"); | MEM_malloc_arrayN(ba->max_line_count * 2, sizeof(LineartEdge *), __func__)); | ||||
| memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count); | memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count); | ||||
| ba->max_line_count *= 2; | ba->max_line_count *= 2; | ||||
| MEM_freeN(ba->linked_lines); | MEM_freeN(ba->linked_lines); | ||||
| ba->linked_lines = new_array; | ba->linked_lines = new_array; | ||||
| } | } | ||||
| ba->linked_lines[ba->line_count] = e; | ba->linked_lines[ba->line_count] = e; | ||||
| ba->line_count++; | ba->line_count++; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | else { | ||||
| int remaining = ld->pending_edges.next - starting_index; | int remaining = ld->pending_edges.next - starting_index; | ||||
| rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT); | rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT); | ||||
| res = 1; | res = 1; | ||||
| } | } | ||||
| return res; | return res; | ||||
| } | } | ||||
| static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti) | static void lineart_occlusion_worker(TaskPool *__restrict /*pool*/, LineartRenderTaskInfo *rti) | ||||
| { | { | ||||
| LineartData *ld = rti->ld; | LineartData *ld = rti->ld; | ||||
| LineartEdge *eip; | LineartEdge *eip; | ||||
| while (lineart_occlusion_make_task_info(ld, rti)) { | while (lineart_occlusion_make_task_info(ld, rti)) { | ||||
| for (int i = 0; i < rti->pending_edges.max; i++) { | for (int i = 0; i < rti->pending_edges.max; i++) { | ||||
| eip = rti->pending_edges.array[i]; | eip = rti->pending_edges.array[i]; | ||||
| lineart_occlusion_single_line(ld, eip, rti->thread_id); | lineart_occlusion_single_line(ld, eip, rti->thread_id); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * All internal functions starting with lineart_main_ is called inside | * All internal functions starting with lineart_main_ is called inside | ||||
| * #MOD_lineart_compute_feature_lines function. | * #MOD_lineart_compute_feature_lines function. | ||||
| * This function handles all occlusion calculation. | * This function handles all occlusion calculation. | ||||
| */ | */ | ||||
| void lineart_main_occlusion_begin(LineartData *ld) | void lineart_main_occlusion_begin(LineartData *ld) | ||||
| { | { | ||||
| int thread_count = ld->thread_count; | int thread_count = ld->thread_count; | ||||
| LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count, | LineartRenderTaskInfo *rti = static_cast<LineartRenderTaskInfo *>( | ||||
| "Task Pool"); | MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count, __func__)); | ||||
| int i; | int i; | ||||
| TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH); | TaskPool *tp = BLI_task_pool_create(nullptr, TASK_PRIORITY_HIGH); | ||||
| for (i = 0; i < thread_count; i++) { | for (i = 0; i < thread_count; i++) { | ||||
| rti[i].thread_id = i; | rti[i].thread_id = i; | ||||
| rti[i].ld = ld; | rti[i].ld = ld; | ||||
| BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, NULL); | BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, nullptr); | ||||
| } | } | ||||
| BLI_task_pool_work_and_wait(tp); | BLI_task_pool_work_and_wait(tp); | ||||
| BLI_task_pool_free(tp); | BLI_task_pool_free(tp); | ||||
| MEM_freeN(rti); | MEM_freeN(rti); | ||||
| } | } | ||||
| /** | /** | ||||
| ▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | enum LineartPointTri { | ||||
| LRT_ON_TRIANGLE = 1, | LRT_ON_TRIANGLE = 1, | ||||
| LRT_INSIDE_TRIANGLE = 2, | LRT_INSIDE_TRIANGLE = 2, | ||||
| }; | }; | ||||
| /** | /** | ||||
| * Same algorithm as lineart_point_inside_triangle(), but returns differently: | * Same algorithm as lineart_point_inside_triangle(), but returns differently: | ||||
| * 0-outside 1-on the edge 2-inside. | * 0-outside 1-on the edge 2-inside. | ||||
| */ | */ | ||||
| static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[2], double v2[2]) | static LineartPointTri lineart_point_triangle_relation(double v[2], | ||||
| double v0[2], | |||||
| double v1[2], | |||||
| double v2[2]) | |||||
| { | { | ||||
| double cl, c; | double cl, c; | ||||
| double r; | double r; | ||||
| if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) || | if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) || | ||||
| lineart_point_on_line_segment(v, v2, v0)) { | lineart_point_on_line_segment(v, v2, v0)) { | ||||
| return LRT_ON_TRIANGLE; | return LRT_ON_TRIANGLE; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * The following `lineart_memory_get_XXX_space` functions are for allocating new memory for some | * The following `lineart_memory_get_XXX_space` functions are for allocating new memory for some | ||||
| * modified geometries in the culling stage. | * modified geometries in the culling stage. | ||||
| */ | */ | ||||
| static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartData *ld) | static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartData *ld) | ||||
| { | { | ||||
| LineartElementLinkNode *eln; | |||||
| /* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles | /* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles | ||||
| * are relatively small. */ | * are relatively small. */ | ||||
| LineartTriangle *render_triangles = lineart_mem_acquire(&ld->render_data_pool, | LineartTriangle *render_triangles = static_cast<LineartTriangle *>( | ||||
| 64 * ld->sizeof_triangle); | lineart_mem_acquire(&ld->render_data_pool, 64 * ld->sizeof_triangle)); | ||||
| eln = lineart_list_append_pointer_pool_sized(&ld->geom.triangle_buffer_pointers, | LineartElementLinkNode *eln = static_cast<LineartElementLinkNode *>( | ||||
| lineart_list_append_pointer_pool_sized(&ld->geom.triangle_buffer_pointers, | |||||
| &ld->render_data_pool, | &ld->render_data_pool, | ||||
| render_triangles, | render_triangles, | ||||
| sizeof(LineartElementLinkNode)); | sizeof(LineartElementLinkNode))); | ||||
| eln->element_count = 64; | eln->element_count = 64; | ||||
| eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; | eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; | ||||
| return eln; | return eln; | ||||
| } | } | ||||
| static LineartElementLinkNode *lineart_memory_get_vert_space(LineartData *ld) | static LineartElementLinkNode *lineart_memory_get_vert_space(LineartData *ld) | ||||
| { | { | ||||
| LineartElementLinkNode *eln; | LineartVert *render_vertices = static_cast<LineartVert *>( | ||||
| lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartVert) * 64)); | |||||
| LineartVert *render_vertices = lineart_mem_acquire(&ld->render_data_pool, | LineartElementLinkNode *eln = static_cast<LineartElementLinkNode *>( | ||||
| sizeof(LineartVert) * 64); | lineart_list_append_pointer_pool_sized(&ld->geom.vertex_buffer_pointers, | ||||
| eln = lineart_list_append_pointer_pool_sized(&ld->geom.vertex_buffer_pointers, | |||||
| &ld->render_data_pool, | &ld->render_data_pool, | ||||
| render_vertices, | render_vertices, | ||||
| sizeof(LineartElementLinkNode)); | sizeof(LineartElementLinkNode))); | ||||
| eln->element_count = 64; | eln->element_count = 64; | ||||
| eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; | eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; | ||||
| return eln; | return eln; | ||||
| } | } | ||||
| static LineartElementLinkNode *lineart_memory_get_edge_space(LineartData *ld) | static LineartElementLinkNode *lineart_memory_get_edge_space(LineartData *ld) | ||||
| { | { | ||||
| LineartElementLinkNode *eln; | LineartEdge *render_edges = static_cast<LineartEdge *>( | ||||
| lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * 64)); | |||||
| LineartEdge *render_edges = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * 64); | |||||
| eln = lineart_list_append_pointer_pool_sized(&ld->geom.line_buffer_pointers, | LineartElementLinkNode *eln = static_cast<LineartElementLinkNode *>( | ||||
| lineart_list_append_pointer_pool_sized(&ld->geom.line_buffer_pointers, | |||||
| ld->edge_data_pool, | ld->edge_data_pool, | ||||
| render_edges, | render_edges, | ||||
| sizeof(LineartElementLinkNode)); | sizeof(LineartElementLinkNode))); | ||||
| eln->element_count = 64; | eln->element_count = 64; | ||||
| eln->crease_threshold = ld->conf.crease_threshold; | eln->crease_threshold = ld->conf.crease_threshold; | ||||
| eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; | eln->flags |= LRT_ELEMENT_IS_ADDITIONAL; | ||||
| return eln; | return eln; | ||||
| } | } | ||||
| static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig) | static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig) | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | static void lineart_triangle_cull_single(LineartData *ld, | ||||
| double a; | double a; | ||||
| int v_count = *r_v_count; | int v_count = *r_v_count; | ||||
| int e_count = *r_e_count; | int e_count = *r_e_count; | ||||
| int t_count = *r_t_count; | int t_count = *r_t_count; | ||||
| uint16_t new_flag = 0; | uint16_t new_flag = 0; | ||||
| LineartEdge *new_e, *e, *old_e; | LineartEdge *new_e, *e, *old_e; | ||||
| LineartEdgeSegment *es; | LineartEdgeSegment *es; | ||||
| LineartTriangleAdjacent *tri_adj; | |||||
| if (tri->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) { | if (tri->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* See definition of tri->intersecting_verts and the usage in | /* See definition of tri->intersecting_verts and the usage in | ||||
| * lineart_geometry_object_load() for details. */ | * lineart_geometry_object_load() for details. */ | ||||
| tri_adj = (void *)tri->intersecting_verts; | LineartTriangleAdjacent *tri_adj = reinterpret_cast<LineartTriangleAdjacent *>( | ||||
| tri->intersecting_verts); | |||||
| LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count]; | LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count]; | ||||
| LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count); | LineartTriangle *tri1 = static_cast<LineartTriangle *>( | ||||
| LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) + | (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count)); | ||||
| ld->sizeof_triangle * (t_count + 1)); | LineartTriangle *tri2 = static_cast<LineartTriangle *>( | ||||
| (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * (t_count + 1))); | |||||
| new_e = &((LineartEdge *)e_eln->pointer)[e_count]; | new_e = &((LineartEdge *)e_eln->pointer)[e_count]; | ||||
| /* Init `edge` to the last `edge` entry. */ | /* Init `edge` to the last `edge` entry. */ | ||||
| e = new_e; | e = new_e; | ||||
| #define INCREASE_EDGE \ | #define INCREASE_EDGE \ | ||||
| new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \ | new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \ | ||||
| e_count++; \ | e_count++; \ | ||||
| e = new_e; \ | e = new_e; \ | ||||
| es = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment)); \ | es = static_cast<LineartEdgeSegment *>( \ | ||||
| lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment))); \ | |||||
| BLI_addtail(&e->segments, es); | BLI_addtail(&e->segments, es); | ||||
| #define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \ | #define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \ | ||||
| if (tri_adj->e[e_num]) { \ | if (tri_adj->e[e_num]) { \ | ||||
| old_e = tri_adj->e[e_num]; \ | old_e = tri_adj->e[e_num]; \ | ||||
| new_flag = old_e->flags; \ | new_flag = old_e->flags; \ | ||||
| old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ | old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \ | ||||
| lineart_discard_duplicated_edges(old_e); \ | lineart_discard_duplicated_edges(old_e); \ | ||||
| ▲ Show 20 Lines • Show All 492 Lines • ▼ Show 20 Lines | if (!ld->conf.cam_is_persp) { | ||||
| use_w = 2; | use_w = 2; | ||||
| } | } | ||||
| /* Then go through all the other triangles. */ | /* Then go through all the other triangles. */ | ||||
| LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) { | LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) { | ||||
| if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) { | if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ob = eln->object_ref; | ob = static_cast<Object *>(eln->object_ref); | ||||
| for (i = 0; i < eln->element_count; i++) { | for (i = 0; i < eln->element_count; i++) { | ||||
| /* Select the triangle in the array. */ | /* Select the triangle in the array. */ | ||||
| tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i); | tri = static_cast<LineartTriangle *>( | ||||
| (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i)); | |||||
| if (tri->flags & LRT_CULL_DISCARD) { | if (tri->flags & LRT_CULL_DISCARD) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| LRT_CULL_DECIDE_INSIDE | LRT_CULL_DECIDE_INSIDE | ||||
| LRT_CULL_ENSURE_MEMORY | LRT_CULL_ENSURE_MEMORY | ||||
| lineart_triangle_cull_single(ld, | lineart_triangle_cull_single(ld, | ||||
| Show All 23 Lines | |||||
| /** | /** | ||||
| * Adjacent data is only used during the initial stages of computing. | * Adjacent data is only used during the initial stages of computing. | ||||
| * So we can free it using this function when it is not needed anymore. | * So we can free it using this function when it is not needed anymore. | ||||
| */ | */ | ||||
| void lineart_main_free_adjacent_data(LineartData *ld) | void lineart_main_free_adjacent_data(LineartData *ld) | ||||
| { | { | ||||
| LinkData *link; | LinkData *link; | ||||
| while ((link = BLI_pophead(&ld->geom.triangle_adjacent_pointers)) != NULL) { | while ((link = static_cast<LinkData *>(BLI_pophead(&ld->geom.triangle_adjacent_pointers))) != | ||||
| nullptr) { | |||||
| MEM_freeN(link->data); | MEM_freeN(link->data); | ||||
| } | } | ||||
| LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) { | LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) { | ||||
| LineartTriangle *tri = eln->pointer; | LineartTriangle *tri = static_cast<LineartTriangle *>(eln->pointer); | ||||
| int i; | int i; | ||||
| for (i = 0; i < eln->element_count; i++) { | for (i = 0; i < eln->element_count; i++) { | ||||
| /* See definition of tri->intersecting_verts and the usage in | /* See definition of tri->intersecting_verts and the usage in | ||||
| * lineart_geometry_object_load() for detailed. */ | * lineart_geometry_object_load() for detailed. */ | ||||
| tri->intersecting_verts = NULL; | tri->intersecting_verts = nullptr; | ||||
| tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle); | tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void lineart_main_perspective_division(LineartData *ld) | void lineart_main_perspective_division(LineartData *ld) | ||||
| { | { | ||||
| LineartVert *vt; | |||||
| int i; | |||||
| LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.vertex_buffer_pointers) { | LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.vertex_buffer_pointers) { | ||||
| vt = eln->pointer; | LineartVert *vt = static_cast<LineartVert *>(eln->pointer); | ||||
| for (i = 0; i < eln->element_count; i++) { | for (int i = 0; i < eln->element_count; i++) { | ||||
| if (ld->conf.cam_is_persp) { | if (ld->conf.cam_is_persp) { | ||||
| /* Do not divide Z, we use Z to back transform cut points in later chaining process. */ | /* Do not divide Z, we use Z to back transform cut points in later chaining process. */ | ||||
| vt[i].fbcoord[0] /= vt[i].fbcoord[3]; | vt[i].fbcoord[0] /= vt[i].fbcoord[3]; | ||||
| vt[i].fbcoord[1] /= vt[i].fbcoord[3]; | vt[i].fbcoord[1] /= vt[i].fbcoord[3]; | ||||
| /* Re-map z into (0-1) range, because we no longer need NDC (Normalized Device Coordinates) | /* Re-map z into (0-1) range, because we no longer need NDC (Normalized Device Coordinates) | ||||
| * at the moment. | * at the moment. | ||||
| * The algorithm currently doesn't need Z for operation, we use W instead. If Z is needed | * The algorithm currently doesn't need Z for operation, we use W instead. If Z is needed | ||||
| * in the future, the line below correctly transforms it to view space coordinates. */ | * in the future, the line below correctly transforms it to view space coordinates. */ | ||||
| Show All 19 Lines | LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.line_buffer_pointers) { | ||||
| for (i = 0; i < eln->element_count; i++) { | for (i = 0; i < eln->element_count; i++) { | ||||
| if (LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2)) { | if (LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2)) { | ||||
| e[i].flags = LRT_EDGE_FLAG_CHAIN_PICKED; | e[i].flags = LRT_EDGE_FLAG_CHAIN_PICKED; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| typedef struct LineartEdgeNeighbor { | struct LineartEdgeNeighbor { | ||||
| int e; | int e; | ||||
| uint16_t flags; | uint16_t flags; | ||||
| int v1, v2; | int v1, v2; | ||||
| } LineartEdgeNeighbor; | }; | ||||
| typedef struct VertData { | struct VertData { | ||||
| const MVert *mvert; | const MVert *mvert; | ||||
| LineartVert *v_arr; | LineartVert *v_arr; | ||||
| double (*model_view)[4]; | double (*model_view)[4]; | ||||
| double (*model_view_proj)[4]; | double (*model_view_proj)[4]; | ||||
| } VertData; | }; | ||||
| static void lineart_mvert_transform_task(void *__restrict userdata, | static void lineart_mvert_transform_task(void *__restrict userdata, | ||||
| const int i, | const int i, | ||||
| const TaskParallelTLS *__restrict UNUSED(tls)) | const TaskParallelTLS *__restrict /*tls*/) | ||||
| { | { | ||||
| VertData *vert_task_data = (VertData *)userdata; | VertData *vert_task_data = (VertData *)userdata; | ||||
| const MVert *m_v = &vert_task_data->mvert[i]; | const MVert *m_v = &vert_task_data->mvert[i]; | ||||
| double co[4]; | double co[4]; | ||||
| LineartVert *v = &vert_task_data->v_arr[i]; | LineartVert *v = &vert_task_data->v_arr[i]; | ||||
| copy_v3db_v3fl(co, m_v->co); | copy_v3db_v3fl(co, m_v->co); | ||||
| mul_v3_m4v3_db(v->gloc, vert_task_data->model_view, co); | mul_v3_m4v3_db(v->gloc, vert_task_data->model_view, co); | ||||
| mul_v4_m4v3_db(v->fbcoord, vert_task_data->model_view_proj, co); | mul_v4_m4v3_db(v->fbcoord, vert_task_data->model_view_proj, co); | ||||
| Show All 31 Lines | static LineartTriangle *lineart_triangle_from_index(LineartData *ld, | ||||
| LineartTriangle *rt_array, | LineartTriangle *rt_array, | ||||
| int index) | int index) | ||||
| { | { | ||||
| int8_t *b = (int8_t *)rt_array; | int8_t *b = (int8_t *)rt_array; | ||||
| b += (index * ld->sizeof_triangle); | b += (index * ld->sizeof_triangle); | ||||
| return (LineartTriangle *)b; | return (LineartTriangle *)b; | ||||
| } | } | ||||
| typedef struct EdgeFeatData { | struct EdgeFeatData { | ||||
| LineartData *ld; | LineartData *ld; | ||||
| Mesh *me; | Mesh *me; | ||||
| Object *ob_eval; /* For evaluated materials. */ | Object *ob_eval; /* For evaluated materials. */ | ||||
| const MLoopTri *mlooptri; | const MLoopTri *mlooptri; | ||||
| const int *material_indices; | const int *material_indices; | ||||
| LineartTriangle *tri_array; | LineartTriangle *tri_array; | ||||
| LineartVert *v_array; | LineartVert *v_array; | ||||
| float crease_threshold; | float crease_threshold; | ||||
| bool use_auto_smooth; | bool use_auto_smooth; | ||||
| bool use_freestyle_face; | bool use_freestyle_face; | ||||
| int freestyle_face_index; | int freestyle_face_index; | ||||
| bool use_freestyle_edge; | bool use_freestyle_edge; | ||||
| int freestyle_edge_index; | int freestyle_edge_index; | ||||
| LineartEdgeNeighbor *edge_nabr; | LineartEdgeNeighbor *edge_nabr; | ||||
| } EdgeFeatData; | }; | ||||
| typedef struct EdgeFeatReduceData { | struct EdgeFeatReduceData { | ||||
| int feat_edges; | int feat_edges; | ||||
| } EdgeFeatReduceData; | }; | ||||
| static void feat_data_sum_reduce(const void *__restrict UNUSED(userdata), | static void feat_data_sum_reduce(const void *__restrict /*userdata*/, | ||||
| void *__restrict chunk_join, | void *__restrict chunk_join, | ||||
| void *__restrict chunk) | void *__restrict chunk) | ||||
| { | { | ||||
| EdgeFeatReduceData *feat_chunk_join = (EdgeFeatReduceData *)chunk_join; | EdgeFeatReduceData *feat_chunk_join = (EdgeFeatReduceData *)chunk_join; | ||||
| EdgeFeatReduceData *feat_chunk = (EdgeFeatReduceData *)chunk; | EdgeFeatReduceData *feat_chunk = (EdgeFeatReduceData *)chunk; | ||||
| feat_chunk_join->feat_edges += feat_chunk->feat_edges; | feat_chunk_join->feat_edges += feat_chunk->feat_edges; | ||||
| } | } | ||||
| Show All 28 Lines | if (index > -1) { | ||||
| ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly]; | ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly]; | ||||
| } | } | ||||
| if (edge_nabr[i].e > -1) { | if (edge_nabr[i].e > -1) { | ||||
| ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly]; | ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly]; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Handle mesh boundary cases: We want mesh boundaries to respect | /* Handle mesh boundary cases: We want mesh boundaries to respect | ||||
| * `filter_face_mark_boundaries` option the same way as face mark boundaries, and the code | * `filter_face_mark_boundaries` option the same way as face mark boundaries, and the code | ||||
| * path is simper when it's assuming both ff1 and ff2 not NULL. */ | * path is simper when it's assuming both ff1 and ff2 not nullptr. */ | ||||
| ff2 = ff1; | ff2 = ff1; | ||||
| } | } | ||||
| if (e_feat_data->ld->conf.filter_face_mark_boundaries ^ | if (e_feat_data->ld->conf.filter_face_mark_boundaries ^ | ||||
| e_feat_data->ld->conf.filter_face_mark_invert) { | e_feat_data->ld->conf.filter_face_mark_invert) { | ||||
| if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) { | if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) { | ||||
| face_mark_filtered = true; | face_mark_filtered = true; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (edge_flag_result) { | ||||
| * If allow duplicated edges, one edge gets added multiple times if it has multiple types. | * If allow duplicated edges, one edge gets added multiple times if it has multiple types. | ||||
| */ | */ | ||||
| reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ? | reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ? | ||||
| lineart_edge_type_duplication_count(edge_flag_result) : | lineart_edge_type_duplication_count(edge_flag_result) : | ||||
| 1; | 1; | ||||
| } | } | ||||
| } | } | ||||
| typedef struct LooseEdgeData { | struct LooseEdgeData { | ||||
| int loose_count; | int loose_count; | ||||
| int loose_max; | int loose_max; | ||||
| int *loose_array; | int *loose_array; | ||||
| const MEdge *edges; | const MEdge *edges; | ||||
| } LooseEdgeData; | }; | ||||
| static void lineart_loose_data_reallocate(LooseEdgeData *loose_data, int count) | static void lineart_loose_data_reallocate(LooseEdgeData *loose_data, int count) | ||||
| { | { | ||||
| int *new_arr = MEM_calloc_arrayN(count, sizeof(int), "loose edge array"); | int *new_arr = static_cast<int *>(MEM_calloc_arrayN(count, sizeof(int), "loose edge array")); | ||||
| if (loose_data->loose_array) { | if (loose_data->loose_array) { | ||||
| memcpy(new_arr, loose_data->loose_array, sizeof(int) * loose_data->loose_max); | memcpy(new_arr, loose_data->loose_array, sizeof(int) * loose_data->loose_max); | ||||
| MEM_SAFE_FREE(loose_data->loose_array); | MEM_SAFE_FREE(loose_data->loose_array); | ||||
| } | } | ||||
| loose_data->loose_max = count; | loose_data->loose_max = count; | ||||
| loose_data->loose_array = new_arr; | loose_data->loose_array = new_arr; | ||||
| } | } | ||||
| static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData *to_be_joined) | static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData *to_be_joined) | ||||
| { | { | ||||
| if (!to_be_joined->loose_array) { | if (!to_be_joined->loose_array) { | ||||
| return; | return; | ||||
| } | } | ||||
| int new_count = loose_data->loose_count + to_be_joined->loose_count; | int new_count = loose_data->loose_count + to_be_joined->loose_count; | ||||
| if (new_count >= loose_data->loose_max) { | if (new_count >= loose_data->loose_max) { | ||||
| lineart_loose_data_reallocate(loose_data, new_count); | lineart_loose_data_reallocate(loose_data, new_count); | ||||
| } | } | ||||
| memcpy(&loose_data->loose_array[loose_data->loose_count], | memcpy(&loose_data->loose_array[loose_data->loose_count], | ||||
| to_be_joined->loose_array, | to_be_joined->loose_array, | ||||
| sizeof(int) * to_be_joined->loose_count); | sizeof(int) * to_be_joined->loose_count); | ||||
| loose_data->loose_count += to_be_joined->loose_count; | loose_data->loose_count += to_be_joined->loose_count; | ||||
| MEM_freeN(to_be_joined->loose_array); | MEM_freeN(to_be_joined->loose_array); | ||||
| to_be_joined->loose_array = NULL; | to_be_joined->loose_array = nullptr; | ||||
| } | } | ||||
| static void lineart_add_loose_edge(LooseEdgeData *loose_data, const int i) | static void lineart_add_loose_edge(LooseEdgeData *loose_data, const int i) | ||||
| { | { | ||||
| if (loose_data->loose_count >= loose_data->loose_max) { | if (loose_data->loose_count >= loose_data->loose_max) { | ||||
| int min_amount = MAX2(100, loose_data->loose_count * 2); | int min_amount = MAX2(100, loose_data->loose_count * 2); | ||||
| lineart_loose_data_reallocate(loose_data, min_amount); | lineart_loose_data_reallocate(loose_data, min_amount); | ||||
| } | } | ||||
| loose_data->loose_array[loose_data->loose_count] = i; | loose_data->loose_array[loose_data->loose_count] = i; | ||||
| loose_data->loose_count++; | loose_data->loose_count++; | ||||
| } | } | ||||
| static void lineart_identify_loose_edges(void *__restrict UNUSED(userdata), | static void lineart_identify_loose_edges(void *__restrict /*userdata*/, | ||||
| const int i, | const int i, | ||||
| const TaskParallelTLS *__restrict tls) | const TaskParallelTLS *__restrict tls) | ||||
| { | { | ||||
| LooseEdgeData *loose_data = (LooseEdgeData *)tls->userdata_chunk; | LooseEdgeData *loose_data = (LooseEdgeData *)tls->userdata_chunk; | ||||
| if (loose_data->edges[i].flag & ME_LOOSEEDGE) { | if (loose_data->edges[i].flag & ME_LOOSEEDGE) { | ||||
| lineart_add_loose_edge(loose_data, i); | lineart_add_loose_edge(loose_data, i); | ||||
| } | } | ||||
| } | } | ||||
| static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata), | static void loose_data_sum_reduce(const void *__restrict /*userdata*/, | ||||
| void *__restrict chunk_join, | void *__restrict chunk_join, | ||||
| void *__restrict chunk) | void *__restrict chunk) | ||||
| { | { | ||||
| LooseEdgeData *final = (LooseEdgeData *)chunk_join; | LooseEdgeData *final = (LooseEdgeData *)chunk_join; | ||||
| LooseEdgeData *loose_chunk = (LooseEdgeData *)chunk; | LooseEdgeData *loose_chunk = (LooseEdgeData *)chunk; | ||||
| lineart_join_loose_edge_arr(final, loose_chunk); | lineart_join_loose_edge_arr(final, loose_chunk); | ||||
| } | } | ||||
| void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e) | void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e) | ||||
| { | { | ||||
| if (pe->next >= pe->max || !pe->max) { | if (pe->next >= pe->max || !pe->max) { | ||||
| if (!pe->max) { | if (!pe->max) { | ||||
| pe->max = 1000; | pe->max = 1000; | ||||
| } | } | ||||
| LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * pe->max * 2, | LineartEdge **new_array = static_cast<LineartEdge **>( | ||||
| "LineartPendingEdges array"); | MEM_mallocN(sizeof(LineartEdge *) * pe->max * 2, "LineartPendingEdges array")); | ||||
| if (LIKELY(pe->array)) { | if (LIKELY(pe->array)) { | ||||
| memcpy(new_array, pe->array, sizeof(LineartEdge *) * pe->max); | memcpy(new_array, pe->array, sizeof(LineartEdge *) * pe->max); | ||||
| MEM_freeN(pe->array); | MEM_freeN(pe->array); | ||||
| } | } | ||||
| pe->max *= 2; | pe->max *= 2; | ||||
| pe->array = new_array; | pe->array = new_array; | ||||
| } | } | ||||
| pe->array[pe->next] = e; | pe->array[pe->next] = e; | ||||
| pe->next++; | pe->next++; | ||||
| } | } | ||||
| static void lineart_add_edge_to_array_thread(LineartObjectInfo *obi, LineartEdge *e) | static void lineart_add_edge_to_array_thread(LineartObjectInfo *obi, LineartEdge *e) | ||||
| { | { | ||||
| lineart_add_edge_to_array(&obi->pending_edges, e); | lineart_add_edge_to_array(&obi->pending_edges, e); | ||||
| } | } | ||||
| /* NOTE: For simplicity, this function doesn't actually do anything if you already have data in | /* NOTE: For simplicity, this function doesn't actually do anything if you already have data in | ||||
| * #pe. */ | * #pe. */ | ||||
| void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count) | void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count) | ||||
| { | { | ||||
| if (pe->max || pe->array || count == 0) { | if (pe->max || pe->array || count == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| pe->max = count; | pe->max = count; | ||||
| LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * pe->max, | LineartEdge **new_array = static_cast<LineartEdge **>( | ||||
| "LineartPendingEdges array final"); | MEM_mallocN(sizeof(LineartEdge *) * pe->max, "LineartPendingEdges array final")); | ||||
| pe->array = new_array; | pe->array = new_array; | ||||
| } | } | ||||
| static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartObjectInfo *obi) | static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartObjectInfo *obi) | ||||
| { | { | ||||
| /* In case of line art "occlusion only" or contour not enabled, it's possible for an object to | /* In case of line art "occlusion only" or contour not enabled, it's possible for an object to | ||||
| * not produce any feature lines. */ | * not produce any feature lines. */ | ||||
| if (!obi->pending_edges.array) { | if (!obi->pending_edges.array) { | ||||
| Show All 16 Lines | static void lineart_triangle_adjacent_assign(LineartTriangle *tri, | ||||
| else if (lineart_edge_match(tri, e, 1, 2)) { | else if (lineart_edge_match(tri, e, 1, 2)) { | ||||
| tri_adj->e[1] = e; | tri_adj->e[1] = e; | ||||
| } | } | ||||
| else if (lineart_edge_match(tri, e, 2, 0)) { | else if (lineart_edge_match(tri, e, 2, 0)) { | ||||
| tri_adj->e[2] = e; | tri_adj->e[2] = e; | ||||
| } | } | ||||
| } | } | ||||
| typedef struct TriData { | struct TriData { | ||||
| LineartObjectInfo *ob_info; | LineartObjectInfo *ob_info; | ||||
| const MLoopTri *mlooptri; | const MLoopTri *mlooptri; | ||||
| const int *material_indices; | const int *material_indices; | ||||
| LineartVert *vert_arr; | LineartVert *vert_arr; | ||||
| LineartTriangle *tri_arr; | LineartTriangle *tri_arr; | ||||
| int lineart_triangle_size; | int lineart_triangle_size; | ||||
| LineartTriangleAdjacent *tri_adj; | LineartTriangleAdjacent *tri_adj; | ||||
| } TriData; | }; | ||||
| static void lineart_load_tri_task(void *__restrict userdata, | static void lineart_load_tri_task(void *__restrict userdata, | ||||
| const int i, | const int i, | ||||
| const TaskParallelTLS *__restrict UNUSED(tls)) | const TaskParallelTLS *__restrict /*tls*/) | ||||
| { | { | ||||
| TriData *tri_task_data = (TriData *)userdata; | TriData *tri_task_data = (TriData *)userdata; | ||||
| Mesh *me = tri_task_data->ob_info->original_me; | Mesh *me = tri_task_data->ob_info->original_me; | ||||
| LineartObjectInfo *ob_info = tri_task_data->ob_info; | LineartObjectInfo *ob_info = tri_task_data->ob_info; | ||||
| const MLoopTri *mlooptri = &tri_task_data->mlooptri[i]; | const MLoopTri *mlooptri = &tri_task_data->mlooptri[i]; | ||||
| const int *material_indices = tri_task_data->material_indices; | const int *material_indices = tri_task_data->material_indices; | ||||
| LineartVert *vert_arr = tri_task_data->vert_arr; | LineartVert *vert_arr = tri_task_data->vert_arr; | ||||
| LineartTriangle *tri = tri_task_data->tri_arr; | LineartTriangle *tri = tri_task_data->tri_arr; | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static void lineart_load_tri_task(void *__restrict userdata, | ||||
| else if (ob_info->usage == OBJECT_LRT_FORCE_INTERSECTION) { | else if (ob_info->usage == OBJECT_LRT_FORCE_INTERSECTION) { | ||||
| tri->flags |= LRT_TRIANGLE_FORCE_INTERSECTION; | tri->flags |= LRT_TRIANGLE_FORCE_INTERSECTION; | ||||
| } | } | ||||
| else if (ELEM(ob_info->usage, OBJECT_LRT_NO_INTERSECTION, OBJECT_LRT_OCCLUSION_ONLY)) { | else if (ELEM(ob_info->usage, OBJECT_LRT_NO_INTERSECTION, OBJECT_LRT_OCCLUSION_ONLY)) { | ||||
| tri->flags |= LRT_TRIANGLE_NO_INTERSECTION; | tri->flags |= LRT_TRIANGLE_NO_INTERSECTION; | ||||
| } | } | ||||
| /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */ | /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */ | ||||
| tri->intersecting_verts = (void *)&tri_task_data->tri_adj[i]; | tri->intersecting_verts = static_cast<LinkNode *>((void *)&tri_task_data->tri_adj[i]); | ||||
| } | } | ||||
| typedef struct EdgeNeighborData { | struct EdgeNeighborData { | ||||
| LineartEdgeNeighbor *edge_nabr; | LineartEdgeNeighbor *edge_nabr; | ||||
| LineartAdjacentEdge *adj_e; | LineartAdjacentEdge *adj_e; | ||||
| const MLoopTri *mlooptri; | const MLoopTri *mlooptri; | ||||
| const MLoop *mloop; | const MLoop *mloop; | ||||
| } EdgeNeighborData; | }; | ||||
| static void lineart_edge_neighbor_init_task(void *__restrict userdata, | static void lineart_edge_neighbor_init_task(void *__restrict userdata, | ||||
| const int i, | const int i, | ||||
| const TaskParallelTLS *__restrict UNUSED(tls)) | const TaskParallelTLS *__restrict /*tls*/) | ||||
| { | { | ||||
| EdgeNeighborData *en_data = (EdgeNeighborData *)userdata; | EdgeNeighborData *en_data = (EdgeNeighborData *)userdata; | ||||
| LineartAdjacentEdge *adj_e = &en_data->adj_e[i]; | LineartAdjacentEdge *adj_e = &en_data->adj_e[i]; | ||||
| const MLoopTri *looptri = &en_data->mlooptri[i / 3]; | const MLoopTri *looptri = &en_data->mlooptri[i / 3]; | ||||
| LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i]; | LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i]; | ||||
| const MLoop *mloop = en_data->mloop; | const MLoop *mloop = en_data->mloop; | ||||
| adj_e->e = i; | adj_e->e = i; | ||||
| adj_e->v1 = mloop[looptri->tri[i % 3]].v; | adj_e->v1 = mloop[looptri->tri[i % 3]].v; | ||||
| adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v; | adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v; | ||||
| if (adj_e->v1 > adj_e->v2) { | if (adj_e->v1 > adj_e->v2) { | ||||
| SWAP(uint32_t, adj_e->v1, adj_e->v2); | SWAP(uint32_t, adj_e->v1, adj_e->v2); | ||||
| } | } | ||||
| edge_nabr->e = -1; | edge_nabr->e = -1; | ||||
| edge_nabr->v1 = adj_e->v1; | edge_nabr->v1 = adj_e->v1; | ||||
| edge_nabr->v2 = adj_e->v2; | edge_nabr->v2 = adj_e->v2; | ||||
| edge_nabr->flags = 0; | edge_nabr->flags = 0; | ||||
| } | } | ||||
| static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edges) | static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edges) | ||||
| { | { | ||||
| /* Because the mesh is triangulated, so `me->totedge` should be reliable? */ | /* Because the mesh is triangulated, so `me->totedge` should be reliable? */ | ||||
| LineartAdjacentEdge *adj_e = MEM_mallocN(sizeof(LineartAdjacentEdge) * total_edges, | LineartAdjacentEdge *adj_e = static_cast<LineartAdjacentEdge *>( | ||||
| "LineartAdjacentEdge arr"); | MEM_mallocN(sizeof(LineartAdjacentEdge) * total_edges, "LineartAdjacentEdge arr")); | ||||
| LineartEdgeNeighbor *edge_nabr = MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges, | LineartEdgeNeighbor *edge_nabr = static_cast<LineartEdgeNeighbor *>( | ||||
| "LineartEdgeNeighbor arr"); | MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges, "LineartEdgeNeighbor arr")); | ||||
| TaskParallelSettings en_settings; | TaskParallelSettings en_settings; | ||||
| BLI_parallel_range_settings_defaults(&en_settings); | BLI_parallel_range_settings_defaults(&en_settings); | ||||
| /* Set the minimum amount of edges a thread has to process. */ | /* Set the minimum amount of edges a thread has to process. */ | ||||
| en_settings.min_iter_per_thread = 50000; | en_settings.min_iter_per_thread = 50000; | ||||
| EdgeNeighborData en_data; | EdgeNeighborData en_data; | ||||
| en_data.adj_e = adj_e; | en_data.adj_e = adj_e; | ||||
| Show All 16 Lines | static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edges) | ||||
| return edge_nabr; | return edge_nabr; | ||||
| } | } | ||||
| static void lineart_geometry_object_load(LineartObjectInfo *ob_info, | static void lineart_geometry_object_load(LineartObjectInfo *ob_info, | ||||
| LineartData *la_data, | LineartData *la_data, | ||||
| ListBase *shadow_elns) | ListBase *shadow_elns) | ||||
| { | { | ||||
| LineartElementLinkNode *elem_link_node; | |||||
| LineartVert *la_v_arr; | |||||
| LineartEdge *la_edge_arr; | |||||
| LineartEdgeSegment *la_seg_arr; | |||||
| LineartTriangle *la_tri_arr; | |||||
| Mesh *me = ob_info->original_me; | Mesh *me = ob_info->original_me; | ||||
| if (!me->totedge) { | if (!me->totedge) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Triangulate. */ | /* Triangulate. */ | ||||
| const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me); | const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me); | ||||
| const int tot_tri = BKE_mesh_runtime_looptri_len(me); | const int tot_tri = BKE_mesh_runtime_looptri_len(me); | ||||
| Show All 11 Lines | static void lineart_geometry_object_load(LineartObjectInfo *ob_info, | ||||
| layer_index = CustomData_get_active_layer_index(&me->pdata, CD_FREESTYLE_FACE); | layer_index = CustomData_get_active_layer_index(&me->pdata, CD_FREESTYLE_FACE); | ||||
| if (layer_index != -1) { | if (layer_index != -1) { | ||||
| can_find_freestyle_face = true; | can_find_freestyle_face = true; | ||||
| } | } | ||||
| /* If we allow duplicated edges, one edge should get added multiple times if is has been | /* If we allow duplicated edges, one edge should get added multiple times if is has been | ||||
| * classified as more than one edge type. This is so we can create multiple different line type | * classified as more than one edge type. This is so we can create multiple different line type | ||||
| * chains containing the same edge. */ | * chains containing the same edge. */ | ||||
| la_v_arr = lineart_mem_acquire_thread(&la_data->render_data_pool, | LineartVert *la_v_arr = static_cast<LineartVert *>( | ||||
| sizeof(LineartVert) * me->totvert); | lineart_mem_acquire_thread(&la_data->render_data_pool, sizeof(LineartVert) * me->totvert)); | ||||
| la_tri_arr = lineart_mem_acquire_thread(&la_data->render_data_pool, | LineartTriangle *la_tri_arr = static_cast<LineartTriangle *>( | ||||
| tot_tri * la_data->sizeof_triangle); | lineart_mem_acquire_thread(&la_data->render_data_pool, tot_tri * la_data->sizeof_triangle)); | ||||
| Object *orig_ob = ob_info->original_ob; | Object *orig_ob = ob_info->original_ob; | ||||
| BLI_spin_lock(&la_data->lock_task); | BLI_spin_lock(&la_data->lock_task); | ||||
| elem_link_node = lineart_list_append_pointer_pool_sized_thread( | LineartElementLinkNode *elem_link_node = static_cast<LineartElementLinkNode *>( | ||||
| &la_data->geom.vertex_buffer_pointers, | lineart_list_append_pointer_pool_sized_thread(&la_data->geom.vertex_buffer_pointers, | ||||
| &la_data->render_data_pool, | &la_data->render_data_pool, | ||||
| la_v_arr, | la_v_arr, | ||||
| sizeof(LineartElementLinkNode)); | sizeof(LineartElementLinkNode))); | ||||
| BLI_spin_unlock(&la_data->lock_task); | BLI_spin_unlock(&la_data->lock_task); | ||||
| elem_link_node->obindex = ob_info->obindex; | elem_link_node->obindex = ob_info->obindex; | ||||
| elem_link_node->element_count = me->totvert; | elem_link_node->element_count = me->totvert; | ||||
| elem_link_node->object_ref = orig_ob; | elem_link_node->object_ref = orig_ob; | ||||
| ob_info->v_eln = elem_link_node; | ob_info->v_eln = elem_link_node; | ||||
| bool use_auto_smooth = false; | bool use_auto_smooth = false; | ||||
| Show All 11 Lines | static void lineart_geometry_object_load(LineartObjectInfo *ob_info, | ||||
| /* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates | /* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates | ||||
| * erroneous detection on creases. Future configuration should allow options. */ | * erroneous detection on creases. Future configuration should allow options. */ | ||||
| if (orig_ob->type == OB_FONT) { | if (orig_ob->type == OB_FONT) { | ||||
| elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY; | elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY; | ||||
| } | } | ||||
| BLI_spin_lock(&la_data->lock_task); | BLI_spin_lock(&la_data->lock_task); | ||||
| elem_link_node = lineart_list_append_pointer_pool_sized_thread( | elem_link_node = static_cast<LineartElementLinkNode *>( | ||||
| &la_data->geom.triangle_buffer_pointers, | lineart_list_append_pointer_pool_sized_thread(&la_data->geom.triangle_buffer_pointers, | ||||
| &la_data->render_data_pool, | &la_data->render_data_pool, | ||||
| la_tri_arr, | la_tri_arr, | ||||
| sizeof(LineartElementLinkNode)); | sizeof(LineartElementLinkNode))); | ||||
| BLI_spin_unlock(&la_data->lock_task); | BLI_spin_unlock(&la_data->lock_task); | ||||
| int usage = ob_info->usage; | int usage = ob_info->usage; | ||||
| elem_link_node->element_count = tot_tri; | elem_link_node->element_count = tot_tri; | ||||
| elem_link_node->object_ref = orig_ob; | elem_link_node->object_ref = orig_ob; | ||||
| elem_link_node->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0); | elem_link_node->flags = eLineArtElementNodeFlag( | ||||
| elem_link_node->flags | | |||||
| ((usage == OBJECT_LRT_NO_INTERSECTION) ? LRT_ELEMENT_NO_INTERSECTION : 0)); | |||||
| /* Note this memory is not from pool, will be deleted after culling. */ | /* Note this memory is not from pool, will be deleted after culling. */ | ||||
| LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri, | LineartTriangleAdjacent *tri_adj = static_cast<LineartTriangleAdjacent *>( | ||||
| "LineartTriangleAdjacent"); | MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri, "LineartTriangleAdjacent")); | ||||
| /* Link is minimal so we use pool anyway. */ | /* Link is minimal so we use pool anyway. */ | ||||
| BLI_spin_lock(&la_data->lock_task); | BLI_spin_lock(&la_data->lock_task); | ||||
| lineart_list_append_pointer_pool_thread( | lineart_list_append_pointer_pool_thread( | ||||
| &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj); | &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj); | ||||
| BLI_spin_unlock(&la_data->lock_task); | BLI_spin_unlock(&la_data->lock_task); | ||||
| /* Convert all vertices to lineart verts. */ | /* Convert all vertices to lineart verts. */ | ||||
| TaskParallelSettings vert_settings; | TaskParallelSettings vert_settings; | ||||
| ▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | if (la_data->conf.use_loose) { | ||||
| edge_loose_settings.userdata_chunk_size = sizeof(LooseEdgeData); | edge_loose_settings.userdata_chunk_size = sizeof(LooseEdgeData); | ||||
| loose_data.edges = BKE_mesh_edges(me); | loose_data.edges = BKE_mesh_edges(me); | ||||
| BLI_task_parallel_range( | BLI_task_parallel_range( | ||||
| 0, me->totedge, &loose_data, lineart_identify_loose_edges, &edge_loose_settings); | 0, me->totedge, &loose_data, lineart_identify_loose_edges, &edge_loose_settings); | ||||
| } | } | ||||
| int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count; | int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count; | ||||
| la_edge_arr = lineart_mem_acquire_thread(la_data->edge_data_pool, | LineartEdge *la_edge_arr = static_cast<LineartEdge *>( | ||||
| sizeof(LineartEdge) * allocate_la_e); | lineart_mem_acquire_thread(la_data->edge_data_pool, sizeof(LineartEdge) * allocate_la_e)); | ||||
| la_seg_arr = lineart_mem_acquire_thread(la_data->edge_data_pool, | LineartEdgeSegment *la_seg_arr = static_cast<LineartEdgeSegment *>(lineart_mem_acquire_thread( | ||||
| sizeof(LineartEdgeSegment) * allocate_la_e); | la_data->edge_data_pool, sizeof(LineartEdgeSegment) * allocate_la_e)); | ||||
| BLI_spin_lock(&la_data->lock_task); | BLI_spin_lock(&la_data->lock_task); | ||||
| elem_link_node = lineart_list_append_pointer_pool_sized_thread( | elem_link_node = static_cast<LineartElementLinkNode *>( | ||||
| &la_data->geom.line_buffer_pointers, | lineart_list_append_pointer_pool_sized_thread(&la_data->geom.line_buffer_pointers, | ||||
| la_data->edge_data_pool, | la_data->edge_data_pool, | ||||
| la_edge_arr, | la_edge_arr, | ||||
| sizeof(LineartElementLinkNode)); | sizeof(LineartElementLinkNode))); | ||||
| BLI_spin_unlock(&la_data->lock_task); | BLI_spin_unlock(&la_data->lock_task); | ||||
| elem_link_node->element_count = allocate_la_e; | elem_link_node->element_count = allocate_la_e; | ||||
| elem_link_node->object_ref = orig_ob; | elem_link_node->object_ref = orig_ob; | ||||
| elem_link_node->obindex = ob_info->obindex; | elem_link_node->obindex = ob_info->obindex; | ||||
| LineartElementLinkNode *shadow_eln = NULL; | LineartElementLinkNode *shadow_eln = nullptr; | ||||
| if (shadow_elns) { | if (shadow_elns) { | ||||
| shadow_eln = lineart_find_matching_eln(shadow_elns, ob_info->obindex); | shadow_eln = lineart_find_matching_eln(shadow_elns, ob_info->obindex); | ||||
| } | } | ||||
| /* Start of the edge/seg arr */ | /* Start of the edge/seg arr */ | ||||
| LineartEdge *la_edge; | LineartEdge *la_edge; | ||||
| LineartEdgeSegment *la_seg; | LineartEdgeSegment *la_seg; | ||||
| la_edge = la_edge_arr; | la_edge = la_edge_arr; | ||||
| la_seg = la_seg_arr; | la_seg = la_seg_arr; | ||||
| for (int i = 0; i < total_edges; i++) { | for (int i = 0; i < total_edges; i++) { | ||||
| LineartEdgeNeighbor *edge_nabr = &edge_feat_data.edge_nabr[i]; | LineartEdgeNeighbor *edge_nabr = &edge_feat_data.edge_nabr[i]; | ||||
| if (i < edge_nabr->e) { | if (i < edge_nabr->e) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Not a feature line, so we skip. */ | /* Not a feature line, so we skip. */ | ||||
| if (edge_nabr->flags == 0) { | if (edge_nabr->flags == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| LineartEdge *edge_added = NULL; | LineartEdge *edge_added = nullptr; | ||||
| /* See eLineartEdgeFlag for details. */ | /* See eLineartEdgeFlag for details. */ | ||||
| for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) { | for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) { | ||||
| int use_type = LRT_MESH_EDGE_TYPES[flag_bit]; | int use_type = LRT_MESH_EDGE_TYPES[flag_bit]; | ||||
| if (!(use_type & edge_nabr->flags)) { | if (!(use_type & edge_nabr->flags)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | for (int i = 0; i < loose_data.loose_count; i++) { | ||||
| la_seg++; | la_seg++; | ||||
| } | } | ||||
| MEM_SAFE_FREE(loose_data.loose_array); | MEM_SAFE_FREE(loose_data.loose_array); | ||||
| } | } | ||||
| MEM_freeN(edge_feat_data.edge_nabr); | MEM_freeN(edge_feat_data.edge_nabr); | ||||
| if (ob_info->free_use_mesh) { | if (ob_info->free_use_mesh) { | ||||
| BKE_id_free(NULL, me); | BKE_id_free(nullptr, me); | ||||
| } | } | ||||
| } | } | ||||
| static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool), | static void lineart_object_load_worker(TaskPool *__restrict /*pool*/, | ||||
| LineartObjectLoadTaskInfo *olti) | LineartObjectLoadTaskInfo *olti) | ||||
| { | { | ||||
| for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) { | for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) { | ||||
| lineart_geometry_object_load(obi, olti->ld, olti->shadow_elns); | lineart_geometry_object_load(obi, olti->ld, olti->shadow_elns); | ||||
| } | } | ||||
| } | } | ||||
| static uchar lineart_intersection_mask_check(Collection *c, Object *ob) | static uchar lineart_intersection_mask_check(Collection *c, Object *ob) | ||||
| ▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Lines | static void lineart_object_load_single_instance(LineartData *ld, | ||||
| Object *ob, | Object *ob, | ||||
| Object *ref_ob, | Object *ref_ob, | ||||
| float use_mat[4][4], | float use_mat[4][4], | ||||
| bool is_render, | bool is_render, | ||||
| LineartObjectLoadTaskInfo *olti, | LineartObjectLoadTaskInfo *olti, | ||||
| int thread_count, | int thread_count, | ||||
| int obindex) | int obindex) | ||||
| { | { | ||||
| LineartObjectInfo *obi = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartObjectInfo)); | LineartObjectInfo *obi = static_cast<LineartObjectInfo *>( | ||||
| lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartObjectInfo))); | |||||
| obi->usage = lineart_usage_check(scene->master_collection, ob, is_render); | obi->usage = lineart_usage_check(scene->master_collection, ob, is_render); | ||||
| obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection, ob); | obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection, ob); | ||||
| obi->intersection_priority = lineart_intersection_priority_check(scene->master_collection, ob); | obi->intersection_priority = lineart_intersection_priority_check(scene->master_collection, ob); | ||||
| Mesh *use_mesh; | Mesh *use_mesh; | ||||
| if (obi->usage == OBJECT_LRT_EXCLUDE) { | if (obi->usage == OBJECT_LRT_EXCLUDE) { | ||||
| return; | return; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | void lineart_main_load_geometries(Depsgraph *depsgraph, | ||||
| bool allow_duplicates, | bool allow_duplicates, | ||||
| bool do_shadow_casting, | bool do_shadow_casting, | ||||
| ListBase *shadow_elns) | ListBase *shadow_elns) | ||||
| { | { | ||||
| double proj[4][4], view[4][4], result[4][4]; | double proj[4][4], view[4][4], result[4][4]; | ||||
| float inv[4][4]; | float inv[4][4]; | ||||
| if (!do_shadow_casting) { | if (!do_shadow_casting) { | ||||
| Camera *cam = camera->data; | Camera *cam = static_cast<Camera *>(camera->data); | ||||
| float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); | float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); | ||||
| int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h); | int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h); | ||||
| double asp = ((double)ld->w / (double)ld->h); | double asp = (double(ld->w) / double(ld->h)); | ||||
| if (cam->type == CAM_PERSP) { | if (cam->type == CAM_PERSP) { | ||||
| if (fit == CAMERA_SENSOR_FIT_VERT && asp > 1) { | if (fit == CAMERA_SENSOR_FIT_VERT && asp > 1) { | ||||
| sensor *= asp; | sensor *= asp; | ||||
| } | } | ||||
| if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) { | if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) { | ||||
| sensor /= asp; | sensor /= asp; | ||||
| } | } | ||||
| const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor); | const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor); | ||||
| Show All 21 Lines | if (G.debug_value == 4000) { | ||||
| t_start = PIL_check_seconds_timer(); | t_start = PIL_check_seconds_timer(); | ||||
| } | } | ||||
| int thread_count = ld->thread_count; | int thread_count = ld->thread_count; | ||||
| int bound_box_discard_count = 0; | int bound_box_discard_count = 0; | ||||
| int obindex = 0; | int obindex = 0; | ||||
| /* This memory is in render buffer memory pool. So we don't need to free those after loading. */ | /* This memory is in render buffer memory pool. So we don't need to free those after loading. */ | ||||
| LineartObjectLoadTaskInfo *olti = lineart_mem_acquire( | LineartObjectLoadTaskInfo *olti = static_cast<LineartObjectLoadTaskInfo *>(lineart_mem_acquire( | ||||
| &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count); | &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count)); | ||||
| eEvaluationMode eval_mode = DEG_get_mode(depsgraph); | eEvaluationMode eval_mode = DEG_get_mode(depsgraph); | ||||
| bool is_render = eval_mode == DAG_EVAL_RENDER; | bool is_render = eval_mode == DAG_EVAL_RENDER; | ||||
| int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | | int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | | ||||
| DEG_ITER_OBJECT_FLAG_VISIBLE; | DEG_ITER_OBJECT_FLAG_VISIBLE; | ||||
| /* Instance duplicated & particles. */ | /* Instance duplicated & particles. */ | ||||
| Show All 33 Lines | if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) { | ||||
| is_render, | is_render, | ||||
| olti, | olti, | ||||
| thread_count, | thread_count, | ||||
| obindex); | obindex); | ||||
| } | } | ||||
| } | } | ||||
| DEG_OBJECT_ITER_END; | DEG_OBJECT_ITER_END; | ||||
| TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH); | TaskPool *tp = BLI_task_pool_create(nullptr, TASK_PRIORITY_HIGH); | ||||
| if (G.debug_value == 4000) { | if (G.debug_value == 4000) { | ||||
| printf("thread count: %d\n", thread_count); | printf("thread count: %d\n", thread_count); | ||||
| } | } | ||||
| for (int i = 0; i < thread_count; i++) { | for (int i = 0; i < thread_count; i++) { | ||||
| olti[i].ld = ld; | olti[i].ld = ld; | ||||
| olti[i].shadow_elns = shadow_elns; | olti[i].shadow_elns = shadow_elns; | ||||
| olti[i].thread_id = i; | olti[i].thread_id = i; | ||||
| BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL); | BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, nullptr); | ||||
| } | } | ||||
| BLI_task_pool_work_and_wait(tp); | BLI_task_pool_work_and_wait(tp); | ||||
| BLI_task_pool_free(tp); | BLI_task_pool_free(tp); | ||||
| /* The step below is to serialize vertex index in the whole scene, so | /* The step below is to serialize vertex index in the whole scene, so | ||||
| * lineart_triangle_share_edge() can work properly from the lack of triangle adjacent info. */ | * lineart_triangle_share_edge() can work properly from the lack of triangle adjacent info. */ | ||||
| int global_i = 0; | int global_i = 0; | ||||
| ▲ Show 20 Lines • Show All 514 Lines • ▼ Show 20 Lines | if (l->v[2] == r->v[0]) { | ||||
| return r->v[0]; | return r->v[0]; | ||||
| } | } | ||||
| if (l->v[2] == r->v[1]) { | if (l->v[2] == r->v[1]) { | ||||
| return r->v[1]; | return r->v[1]; | ||||
| } | } | ||||
| if (l->v[2] == r->v[2]) { | if (l->v[2] == r->v[2]) { | ||||
| return r->v[2]; | return r->v[2]; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| static bool lineart_triangle_2v_intersection_math( | static bool lineart_triangle_2v_intersection_math( | ||||
| LineartVert *v1, LineartVert *v2, LineartTriangle *tri, const double *last, double *rv) | LineartVert *v1, LineartVert *v2, LineartTriangle *tri, const double *last, double *rv) | ||||
| { | { | ||||
| /* Direction vectors for the edge verts. We will check if the verts are on the same side of the | /* Direction vectors for the edge verts. We will check if the verts are on the same side of the | ||||
| * triangle or not. */ | * triangle or not. */ | ||||
| double dir_v1[3], dir_v2[3]; | double dir_v1[3], dir_v2[3]; | ||||
| Show All 30 Lines | static bool lineart_triangle_2v_intersection_math( | ||||
| return true; | return true; | ||||
| } | } | ||||
| static bool lineart_triangle_intersect_math(LineartTriangle *tri, | static bool lineart_triangle_intersect_math(LineartTriangle *tri, | ||||
| LineartTriangle *t2, | LineartTriangle *t2, | ||||
| double *v1, | double *v1, | ||||
| double *v2) | double *v2) | ||||
| { | { | ||||
| double *next = v1, *last = NULL; | double *next = v1, *last = nullptr; | ||||
| LineartVert *sv1, *sv2; | LineartVert *sv1, *sv2; | ||||
| LineartVert *share = lineart_triangle_share_point(t2, tri); | LineartVert *share = lineart_triangle_share_point(t2, tri); | ||||
| if (share) { | if (share) { | ||||
| /* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc` | /* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc` | ||||
| * against `acd` or `cd` against `abc`. */ | * against `acd` or `cd` against `abc`. */ | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
| static void lineart_add_isec_thread(LineartIsecThread *th, | static void lineart_add_isec_thread(LineartIsecThread *th, | ||||
| const double *v1, | const double *v1, | ||||
| const double *v2, | const double *v2, | ||||
| LineartTriangle *tri1, | LineartTriangle *tri1, | ||||
| LineartTriangle *tri2) | LineartTriangle *tri2) | ||||
| { | { | ||||
| if (th->current == th->max) { | if (th->current == th->max) { | ||||
| LineartIsecSingle *new_array = MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2, | LineartIsecSingle *new_array = static_cast<LineartIsecSingle *>( | ||||
| "LineartIsecSingle"); | MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2, "LineartIsecSingle")); | ||||
| memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max); | memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max); | ||||
| th->max *= 2; | th->max *= 2; | ||||
| MEM_freeN(th->array); | MEM_freeN(th->array); | ||||
| th->array = new_array; | th->array = new_array; | ||||
| } | } | ||||
| LineartIsecSingle *isec_single = &th->array[th->current]; | LineartIsecSingle *isec_single = &th->array[th->current]; | ||||
| copy_v3_v3_db(isec_single->v1, v1); | copy_v3_v3_db(isec_single->v1, v1); | ||||
| copy_v3_v3_db(isec_single->v2, v2); | copy_v3_v3_db(isec_single->v2, v2); | ||||
| Show All 32 Lines | if (remaining || added_count == remaining_this_eln) { | ||||
| ld->isect_scheduled_up_to = eln; | ld->isect_scheduled_up_to = eln; | ||||
| ld->isect_scheduled_up_to_index = 0; | ld->isect_scheduled_up_to_index = 0; | ||||
| } | } | ||||
| else { | else { | ||||
| ld->isect_scheduled_up_to_index += added_count; | ld->isect_scheduled_up_to_index += added_count; | ||||
| } | } | ||||
| } | } | ||||
| th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last; | th->pending_to = eln ? eln : | ||||
| static_cast<LineartElementLinkNode *>( | |||||
| ld->geom.triangle_buffer_pointers.last); | |||||
| th->index_to = ld->isect_scheduled_up_to_index; | th->index_to = ld->isect_scheduled_up_to_index; | ||||
| BLI_spin_unlock(&ld->lock_task); | BLI_spin_unlock(&ld->lock_task); | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* This function initializes two things: | /* This function initializes two things: | ||||
| * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler. | * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler. | ||||
| * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will | * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will | ||||
| * be finalized by #lineart_create_edges_from_isec_data | * be finalized by #lineart_create_edges_from_isec_data | ||||
| */ | */ | ||||
| static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count) | static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count) | ||||
| { | { | ||||
| d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr"); | d->threads = static_cast<LineartIsecThread *>( | ||||
| MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr")); | |||||
| d->ld = ld; | d->ld = ld; | ||||
| d->thread_count = thread_count; | d->thread_count = thread_count; | ||||
| ld->isect_scheduled_up_to = ld->geom.triangle_buffer_pointers.first; | ld->isect_scheduled_up_to = static_cast<LineartElementLinkNode *>( | ||||
| ld->geom.triangle_buffer_pointers.first); | |||||
| ld->isect_scheduled_up_to_index = 0; | ld->isect_scheduled_up_to_index = 0; | ||||
| for (int i = 0; i < thread_count; i++) { | for (int i = 0; i < thread_count; i++) { | ||||
| LineartIsecThread *it = &d->threads[i]; | LineartIsecThread *it = &d->threads[i]; | ||||
| it->array = MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr"); | it->array = static_cast<LineartIsecSingle *>( | ||||
| MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr")); | |||||
| it->max = 100; | it->max = 100; | ||||
| it->current = 0; | it->current = 0; | ||||
| it->thread_id = i; | it->thread_id = i; | ||||
| it->ld = ld; | it->ld = ld; | ||||
| } | } | ||||
| } | } | ||||
| static void lineart_destroy_isec_thread(LineartIsecData *d) | static void lineart_destroy_isec_thread(LineartIsecData *d) | ||||
| { | { | ||||
| for (int i = 0; i < d->thread_count; i++) { | for (int i = 0; i < d->thread_count; i++) { | ||||
| LineartIsecThread *it = &d->threads[i]; | LineartIsecThread *it = &d->threads[i]; | ||||
| MEM_freeN(it->array); | MEM_freeN(it->array); | ||||
| } | } | ||||
| MEM_freeN(d->threads); | MEM_freeN(d->threads); | ||||
| } | } | ||||
| static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri, | static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri, | ||||
| LineartBoundingArea *ba, | LineartBoundingArea *ba, | ||||
| LineartIsecThread *th, | LineartIsecThread *th, | ||||
| int up_to) | int up_to) | ||||
| { | { | ||||
| BLI_assert(th != NULL); | BLI_assert(th != nullptr); | ||||
| if (!th) { | if (!th) { | ||||
| return; | return; | ||||
| } | } | ||||
| double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc; | double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc; | ||||
| /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */ | /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */ | ||||
| ▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | if (ba->child) { | ||||
| for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
| lineart_end_bounding_area_recursive(&ba->child[i]); | lineart_end_bounding_area_recursive(&ba->child[i]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void lineart_destroy_render_data_keep_init(LineartData *ld) | void lineart_destroy_render_data_keep_init(LineartData *ld) | ||||
| { | { | ||||
| if (ld == NULL) { | if (ld == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| BLI_listbase_clear(&ld->chains); | BLI_listbase_clear(&ld->chains); | ||||
| BLI_listbase_clear(&ld->wasted_cuts); | BLI_listbase_clear(&ld->wasted_cuts); | ||||
| BLI_listbase_clear(&ld->geom.vertex_buffer_pointers); | BLI_listbase_clear(&ld->geom.vertex_buffer_pointers); | ||||
| BLI_listbase_clear(&ld->geom.line_buffer_pointers); | BLI_listbase_clear(&ld->geom.line_buffer_pointers); | ||||
| BLI_listbase_clear(&ld->geom.triangle_buffer_pointers); | BLI_listbase_clear(&ld->geom.triangle_buffer_pointers); | ||||
| if (ld->pending_edges.array) { | if (ld->pending_edges.array) { | ||||
| MEM_freeN(ld->pending_edges.array); | MEM_freeN(ld->pending_edges.array); | ||||
| } | } | ||||
| for (int i = 0; i < ld->qtree.initial_tile_count; i++) { | for (int i = 0; i < ld->qtree.initial_tile_count; i++) { | ||||
| lineart_end_bounding_area_recursive(&ld->qtree.initials[i]); | lineart_end_bounding_area_recursive(&ld->qtree.initials[i]); | ||||
| } | } | ||||
| lineart_free_bounding_area_memories(ld); | lineart_free_bounding_area_memories(ld); | ||||
| lineart_mem_destroy(&ld->render_data_pool); | lineart_mem_destroy(&ld->render_data_pool); | ||||
| } | } | ||||
| static void lineart_destroy_render_data(LineartData *ld) | static void lineart_destroy_render_data(LineartData *ld) | ||||
| { | { | ||||
| if (ld == NULL) { | if (ld == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| BLI_spin_end(&ld->lock_task); | BLI_spin_end(&ld->lock_task); | ||||
| BLI_spin_end(&ld->lock_cuts); | BLI_spin_end(&ld->lock_cuts); | ||||
| BLI_spin_end(&ld->render_data_pool.lock_mem); | BLI_spin_end(&ld->render_data_pool.lock_mem); | ||||
| lineart_destroy_render_data_keep_init(ld); | lineart_destroy_render_data_keep_init(ld); | ||||
| lineart_mem_destroy(&ld->render_data_pool); | lineart_mem_destroy(&ld->render_data_pool); | ||||
| } | } | ||||
| void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd) | void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd) | ||||
| { | { | ||||
| LineartData *ld = lmd->la_data_ptr; | LineartData *ld = lmd->la_data_ptr; | ||||
| lineart_destroy_render_data(ld); | lineart_destroy_render_data(ld); | ||||
| if (ld) { | if (ld) { | ||||
| MEM_freeN(ld); | MEM_freeN(ld); | ||||
| lmd->la_data_ptr = NULL; | lmd->la_data_ptr = nullptr; | ||||
| } | } | ||||
| if (G.debug_value == 4000) { | if (G.debug_value == 4000) { | ||||
| printf("LRT: Destroyed render data.\n"); | printf("LRT: Destroyed render data.\n"); | ||||
| } | } | ||||
| } | } | ||||
| static LineartCache *lineart_init_cache(void) | static LineartCache *lineart_init_cache(void) | ||||
| { | { | ||||
| LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache"); | LineartCache *lc = static_cast<LineartCache *>( | ||||
| MEM_callocN(sizeof(LineartCache), "Lineart Cache")); | |||||
| return lc; | return lc; | ||||
| } | } | ||||
| void MOD_lineart_clear_cache(struct LineartCache **lc) | void MOD_lineart_clear_cache(LineartCache **lc) | ||||
| { | { | ||||
| if (!(*lc)) { | if (!(*lc)) { | ||||
| return; | return; | ||||
| } | } | ||||
| lineart_mem_destroy(&((*lc)->chain_data_pool)); | lineart_mem_destroy(&((*lc)->chain_data_pool)); | ||||
| MEM_freeN(*lc); | MEM_freeN(*lc); | ||||
| (*lc) = NULL; | (*lc) = nullptr; | ||||
| } | } | ||||
| static LineartData *lineart_create_render_buffer(Scene *scene, | static LineartData *lineart_create_render_buffer(Scene *scene, | ||||
| LineartGpencilModifierData *lmd, | LineartGpencilModifierData *lmd, | ||||
| Object *camera, | Object *camera, | ||||
| Object *active_camera, | Object *active_camera, | ||||
| LineartCache *lc) | LineartCache *lc) | ||||
| { | { | ||||
| LineartData *ld = MEM_callocN(sizeof(LineartData), "Line Art render buffer"); | LineartData *ld = static_cast<LineartData *>( | ||||
| MEM_callocN(sizeof(LineartData), "Line Art render buffer")); | |||||
| lmd->cache = lc; | lmd->cache = lc; | ||||
| lmd->la_data_ptr = ld; | lmd->la_data_ptr = ld; | ||||
| lc->all_enabled_edge_types = lmd->edge_types_override; | lc->all_enabled_edge_types = lmd->edge_types_override; | ||||
| if (!scene || !camera || !lc) { | if (!scene || !camera || !lc) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| Camera *c = camera->data; | Camera *c = static_cast<Camera *>(camera->data); | ||||
| double clipping_offset = 0; | double clipping_offset = 0; | ||||
| if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) { | if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) { | ||||
| /* This way the clipped lines are "stably visible" by prevents depth buffer artifacts. */ | /* This way the clipped lines are "stably visible" by prevents depth buffer artifacts. */ | ||||
| clipping_offset = 0.0001; | clipping_offset = 0.0001; | ||||
| } | } | ||||
| copy_v3db_v3fl(ld->conf.camera_pos, camera->object_to_world[3]); | copy_v3db_v3fl(ld->conf.camera_pos, camera->object_to_world[3]); | ||||
| Show All 10 Lines | static LineartData *lineart_create_render_buffer(Scene *scene, | ||||
| if (ld->conf.cam_is_persp) { | if (ld->conf.cam_is_persp) { | ||||
| ld->qtree.recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE; | ld->qtree.recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE; | ||||
| } | } | ||||
| else { | else { | ||||
| ld->qtree.recursive_level = LRT_TILE_RECURSIVE_ORTHO; | ld->qtree.recursive_level = LRT_TILE_RECURSIVE_ORTHO; | ||||
| } | } | ||||
| double asp = ((double)ld->w / (double)ld->h); | double asp = (double(ld->w) / double(ld->h)); | ||||
| int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h); | int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h); | ||||
| ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp; | ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp; | ||||
| ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp; | ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp; | ||||
| ld->conf.overscan = lmd->overscan; | ld->conf.overscan = lmd->overscan; | ||||
| ld->conf.shift_x /= (1 + ld->conf.overscan); | ld->conf.shift_x /= (1 + ld->conf.overscan); | ||||
| ld->conf.shift_y /= (1 + ld->conf.overscan); | ld->conf.shift_y /= (1 + ld->conf.overscan); | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | static LineartData *lineart_create_render_buffer(Scene *scene, | ||||
| /* lmd->edge_types_override contains all used flags in the modifier stack. */ | /* lmd->edge_types_override contains all used flags in the modifier stack. */ | ||||
| ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0; | ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0; | ||||
| ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0; | ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0; | ||||
| ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0; | ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0; | ||||
| ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0; | ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0; | ||||
| ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0; | ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0; | ||||
| ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0; | ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0; | ||||
| ld->conf.use_light_contour = ((edge_types & LRT_EDGE_FLAG_LIGHT_CONTOUR) != 0 && | ld->conf.use_light_contour = ((edge_types & LRT_EDGE_FLAG_LIGHT_CONTOUR) != 0 && | ||||
| (lmd->light_contour_object != NULL)); | (lmd->light_contour_object != nullptr)); | ||||
| ld->conf.use_shadow = ((edge_types & LRT_EDGE_FLAG_PROJECTED_SHADOW) != 0 && | ld->conf.use_shadow = ((edge_types & LRT_EDGE_FLAG_PROJECTED_SHADOW) != 0 && | ||||
| (lmd->light_contour_object != NULL)); | (lmd->light_contour_object != nullptr)); | ||||
| ld->conf.shadow_selection = lmd->shadow_selection_override; | ld->conf.shadow_selection = lmd->shadow_selection_override; | ||||
| ld->conf.shadow_enclose_shapes = lmd->shadow_selection_override == | ld->conf.shadow_enclose_shapes = lmd->shadow_selection_override == | ||||
| LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES; | LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES; | ||||
| ld->conf.shadow_use_silhouette = lmd->shadow_use_silhouette_override != 0; | ld->conf.shadow_use_silhouette = lmd->shadow_use_silhouette_override != 0; | ||||
| ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0; | ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0; | ||||
| Show All 38 Lines | if (ld->w > ld->h) { | ||||
| sp_w = sp_h * ld->w / ld->h; | sp_w = sp_h * ld->w / ld->h; | ||||
| } | } | ||||
| else { | else { | ||||
| sp_h = sp_w * ld->h / ld->w; | sp_h = sp_w * ld->h / ld->w; | ||||
| } | } | ||||
| /* Because NDC (Normalized Device Coordinates) range is (-1,1), | /* Because NDC (Normalized Device Coordinates) range is (-1,1), | ||||
| * so the span for each initial tile is double of that in the (0,1) range. */ | * so the span for each initial tile is double of that in the (0,1) range. */ | ||||
| double span_w = (double)1 / sp_w * 2.0; | double span_w = 1.0 / sp_w * 2.0; | ||||
| double span_h = (double)1 / sp_h * 2.0; | double span_h = 1.0 / sp_h * 2.0; | ||||
| ld->qtree.count_x = sp_w; | ld->qtree.count_x = sp_w; | ||||
| ld->qtree.count_y = sp_h; | ld->qtree.count_y = sp_h; | ||||
| ld->qtree.tile_width = span_w; | ld->qtree.tile_width = span_w; | ||||
| ld->qtree.tile_height = span_h; | ld->qtree.tile_height = span_h; | ||||
| ld->qtree.initial_tile_count = sp_w * sp_h; | ld->qtree.initial_tile_count = sp_w * sp_h; | ||||
| ld->qtree.initials = lineart_mem_acquire( | ld->qtree.initials = static_cast<LineartBoundingArea *>(lineart_mem_acquire( | ||||
| &ld->render_data_pool, sizeof(LineartBoundingArea) * ld->qtree.initial_tile_count); | &ld->render_data_pool, sizeof(LineartBoundingArea) * ld->qtree.initial_tile_count)); | ||||
| for (int i = 0; i < ld->qtree.initial_tile_count; i++) { | for (int i = 0; i < ld->qtree.initial_tile_count; i++) { | ||||
| BLI_spin_init(&ld->qtree.initials[i].lock); | BLI_spin_init(&ld->qtree.initials[i].lock); | ||||
| } | } | ||||
| /* Initialize tiles. */ | /* Initialize tiles. */ | ||||
| for (row = 0; row < sp_h; row++) { | for (row = 0; row < sp_h; row++) { | ||||
| for (col = 0; col < sp_w; col++) { | for (col = 0; col < sp_w; col++) { | ||||
| ba = &ld->qtree.initials[row * ld->qtree.count_x + col]; | ba = &ld->qtree.initials[row * ld->qtree.count_x + col]; | ||||
| /* Set the four direction limits. */ | /* Set the four direction limits. */ | ||||
| ba->l = span_w * col - 1.0; | ba->l = span_w * col - 1.0; | ||||
| ba->r = (col == sp_w - 1) ? 1.0 : (span_w * (col + 1) - 1.0); | ba->r = (col == sp_w - 1) ? 1.0 : (span_w * (col + 1) - 1.0); | ||||
| ba->u = 1.0 - span_h * row; | ba->u = 1.0 - span_h * row; | ||||
| ba->b = (row == sp_h - 1) ? -1.0 : (1.0 - span_h * (row + 1)); | ba->b = (row == sp_h - 1) ? -1.0 : (1.0 - span_h * (row + 1)); | ||||
| ba->cx = (ba->l + ba->r) / 2; | ba->cx = (ba->l + ba->r) / 2; | ||||
| ba->cy = (ba->u + ba->b) / 2; | ba->cy = (ba->u + ba->b) / 2; | ||||
| /* Init linked_triangles array. */ | /* Init linked_triangles array. */ | ||||
| ba->max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT; | ba->max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT; | ||||
| ba->max_line_count = LRT_TILE_EDGE_COUNT_INITIAL; | ba->max_line_count = LRT_TILE_EDGE_COUNT_INITIAL; | ||||
| ba->linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba->max_triangle_count, | ba->linked_triangles = static_cast<LineartTriangle **>( | ||||
| "ba_linked_triangles"); | MEM_callocN(sizeof(LineartTriangle *) * ba->max_triangle_count, "ba_linked_triangles")); | ||||
| ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count, | ba->linked_lines = static_cast<LineartEdge **>( | ||||
| "ba_linked_lines"); | MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count, "ba_linked_lines")); | ||||
| BLI_spin_init(&ba->lock); | BLI_spin_init(&ba->lock); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Re-link adjacent tiles after one gets subdivided. | * Re-link adjacent tiles after one gets subdivided. | ||||
| Show All 15 Lines | static void lineart_bounding_areas_connect_new(LineartData *ld, LineartBoundingArea *root) | ||||
| lineart_list_append_pointer_pool(&ba[0].bp, mph, &ba[3]); | lineart_list_append_pointer_pool(&ba[0].bp, mph, &ba[3]); | ||||
| /* Connect 4 child bounding areas to other areas that are | /* Connect 4 child bounding areas to other areas that are | ||||
| * adjacent to their original parents. */ | * adjacent to their original parents. */ | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->lp) { | LISTBASE_FOREACH (LinkData *, lip, &root->lp) { | ||||
| /* For example, we are dealing with parent's left side | /* For example, we are dealing with parent's left side | ||||
| * "tba" represents each adjacent neighbor of the parent. */ | * "tba" represents each adjacent neighbor of the parent. */ | ||||
| tba = lip->data; | tba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| /* if this neighbor is adjacent to | /* if this neighbor is adjacent to | ||||
| * the two new areas on the left side of the parent, | * the two new areas on the left side of the parent, | ||||
| * then add them to the adjacent list as well. */ | * then add them to the adjacent list as well. */ | ||||
| if (ba[1].u > tba->b && ba[1].b < tba->u) { | if (ba[1].u > tba->b && ba[1].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&ba[1].lp, mph, tba); | lineart_list_append_pointer_pool(&ba[1].lp, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]); | lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]); | ||||
| } | } | ||||
| if (ba[2].u > tba->b && ba[2].b < tba->u) { | if (ba[2].u > tba->b && ba[2].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&ba[2].lp, mph, tba); | lineart_list_append_pointer_pool(&ba[2].lp, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]); | lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]); | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->rp) { | LISTBASE_FOREACH (LinkData *, lip, &root->rp) { | ||||
| tba = lip->data; | tba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba[0].u > tba->b && ba[0].b < tba->u) { | if (ba[0].u > tba->b && ba[0].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&ba[0].rp, mph, tba); | lineart_list_append_pointer_pool(&ba[0].rp, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]); | lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]); | ||||
| } | } | ||||
| if (ba[3].u > tba->b && ba[3].b < tba->u) { | if (ba[3].u > tba->b && ba[3].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&ba[3].rp, mph, tba); | lineart_list_append_pointer_pool(&ba[3].rp, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]); | lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]); | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->up) { | LISTBASE_FOREACH (LinkData *, lip, &root->up) { | ||||
| tba = lip->data; | tba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba[0].r > tba->l && ba[0].l < tba->r) { | if (ba[0].r > tba->l && ba[0].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&ba[0].up, mph, tba); | lineart_list_append_pointer_pool(&ba[0].up, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->bp, mph, &ba[0]); | lineart_list_append_pointer_pool(&tba->bp, mph, &ba[0]); | ||||
| } | } | ||||
| if (ba[1].r > tba->l && ba[1].l < tba->r) { | if (ba[1].r > tba->l && ba[1].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&ba[1].up, mph, tba); | lineart_list_append_pointer_pool(&ba[1].up, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->bp, mph, &ba[1]); | lineart_list_append_pointer_pool(&tba->bp, mph, &ba[1]); | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->bp) { | LISTBASE_FOREACH (LinkData *, lip, &root->bp) { | ||||
| tba = lip->data; | tba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba[2].r > tba->l && ba[2].l < tba->r) { | if (ba[2].r > tba->l && ba[2].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&ba[2].bp, mph, tba); | lineart_list_append_pointer_pool(&ba[2].bp, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->up, mph, &ba[2]); | lineart_list_append_pointer_pool(&tba->up, mph, &ba[2]); | ||||
| } | } | ||||
| if (ba[3].r > tba->l && ba[3].l < tba->r) { | if (ba[3].r > tba->l && ba[3].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&ba[3].bp, mph, tba); | lineart_list_append_pointer_pool(&ba[3].bp, mph, tba); | ||||
| lineart_list_append_pointer_pool(&tba->up, mph, &ba[3]); | lineart_list_append_pointer_pool(&tba->up, mph, &ba[3]); | ||||
| } | } | ||||
| } | } | ||||
| /* Then remove the parent bounding areas from | /* Then remove the parent bounding areas from | ||||
| * their original adjacent areas. */ | * their original adjacent areas. */ | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->lp) { | LISTBASE_FOREACH (LinkData *, lip, &root->lp) { | ||||
| for (lip2 = ((LineartBoundingArea *)lip->data)->rp.first; lip2; lip2 = next_lip) { | for (lip2 = static_cast<LinkData *>(((LineartBoundingArea *)lip->data)->rp.first); lip2; | ||||
| lip2 = next_lip) { | |||||
| next_lip = lip2->next; | next_lip = lip2->next; | ||||
| tba = lip2->data; | tba = static_cast<LineartBoundingArea *>(lip2->data); | ||||
| if (tba == root) { | if (tba == root) { | ||||
| lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->rp, lip2); | lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->rp, lip2); | ||||
| if (ba[1].u > tba->b && ba[1].b < tba->u) { | if (ba[1].u > tba->b && ba[1].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]); | lineart_list_append_pointer_pool(&tba->rp, mph, &ba[1]); | ||||
| } | } | ||||
| if (ba[2].u > tba->b && ba[2].b < tba->u) { | if (ba[2].u > tba->b && ba[2].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]); | lineart_list_append_pointer_pool(&tba->rp, mph, &ba[2]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->rp) { | LISTBASE_FOREACH (LinkData *, lip, &root->rp) { | ||||
| for (lip2 = ((LineartBoundingArea *)lip->data)->lp.first; lip2; lip2 = next_lip) { | for (lip2 = static_cast<LinkData *>(((LineartBoundingArea *)lip->data)->lp.first); lip2; | ||||
| lip2 = next_lip) { | |||||
| next_lip = lip2->next; | next_lip = lip2->next; | ||||
| tba = lip2->data; | tba = static_cast<LineartBoundingArea *>(lip2->data); | ||||
| if (tba == root) { | if (tba == root) { | ||||
| lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->lp, lip2); | lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->lp, lip2); | ||||
| if (ba[0].u > tba->b && ba[0].b < tba->u) { | if (ba[0].u > tba->b && ba[0].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]); | lineart_list_append_pointer_pool(&tba->lp, mph, &ba[0]); | ||||
| } | } | ||||
| if (ba[3].u > tba->b && ba[3].b < tba->u) { | if (ba[3].u > tba->b && ba[3].b < tba->u) { | ||||
| lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]); | lineart_list_append_pointer_pool(&tba->lp, mph, &ba[3]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->up) { | LISTBASE_FOREACH (LinkData *, lip, &root->up) { | ||||
| for (lip2 = ((LineartBoundingArea *)lip->data)->bp.first; lip2; lip2 = next_lip) { | for (lip2 = static_cast<LinkData *>(((LineartBoundingArea *)lip->data)->bp.first); lip2; | ||||
| lip2 = next_lip) { | |||||
| next_lip = lip2->next; | next_lip = lip2->next; | ||||
| tba = lip2->data; | tba = static_cast<LineartBoundingArea *>(lip2->data); | ||||
| if (tba == root) { | if (tba == root) { | ||||
| lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->bp, lip2); | lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->bp, lip2); | ||||
| if (ba[0].r > tba->l && ba[0].l < tba->r) { | if (ba[0].r > tba->l && ba[0].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&tba->up, mph, &ba[0]); | lineart_list_append_pointer_pool(&tba->up, mph, &ba[0]); | ||||
| } | } | ||||
| if (ba[1].r > tba->l && ba[1].l < tba->r) { | if (ba[1].r > tba->l && ba[1].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&tba->up, mph, &ba[1]); | lineart_list_append_pointer_pool(&tba->up, mph, &ba[1]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &root->bp) { | LISTBASE_FOREACH (LinkData *, lip, &root->bp) { | ||||
| for (lip2 = ((LineartBoundingArea *)lip->data)->up.first; lip2; lip2 = next_lip) { | for (lip2 = static_cast<LinkData *>(((LineartBoundingArea *)lip->data)->up.first); lip2; | ||||
| lip2 = next_lip) { | |||||
| next_lip = lip2->next; | next_lip = lip2->next; | ||||
| tba = lip2->data; | tba = static_cast<LineartBoundingArea *>(lip2->data); | ||||
| if (tba == root) { | if (tba == root) { | ||||
| lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->up, lip2); | lineart_list_remove_pointer_item_no_free(&((LineartBoundingArea *)lip->data)->up, lip2); | ||||
| if (ba[2].r > tba->l && ba[2].l < tba->r) { | if (ba[2].r > tba->l && ba[2].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&tba->bp, mph, &ba[2]); | lineart_list_append_pointer_pool(&tba->bp, mph, &ba[2]); | ||||
| } | } | ||||
| if (ba[3].r > tba->l && ba[3].l < tba->r) { | if (ba[3].r > tba->l && ba[3].l < tba->r) { | ||||
| lineart_list_append_pointer_pool(&tba->bp, mph, &ba[3]); | lineart_list_append_pointer_pool(&tba->bp, mph, &ba[3]); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * Subdivide a tile after one tile contains too many triangles, then re-link triangles into all the | * Subdivide a tile after one tile contains too many triangles, then re-link triangles into all the | ||||
| * child tiles. | * child tiles. | ||||
| */ | */ | ||||
| static void lineart_bounding_area_split(LineartData *ld, | static void lineart_bounding_area_split(LineartData *ld, | ||||
| LineartBoundingArea *root, | LineartBoundingArea *root, | ||||
| int recursive_level) | int recursive_level) | ||||
| { | { | ||||
| LineartBoundingArea *ba = static_cast<LineartBoundingArea *>( | |||||
| LineartBoundingArea *ba = lineart_mem_acquire_thread(&ld->render_data_pool, | lineart_mem_acquire_thread(&ld->render_data_pool, sizeof(LineartBoundingArea) * 4)); | ||||
| sizeof(LineartBoundingArea) * 4); | |||||
| ba[0].l = root->cx; | ba[0].l = root->cx; | ||||
| ba[0].r = root->r; | ba[0].r = root->r; | ||||
| ba[0].u = root->u; | ba[0].u = root->u; | ||||
| ba[0].b = root->cy; | ba[0].b = root->cy; | ||||
| ba[0].cx = (ba[0].l + ba[0].r) / 2; | ba[0].cx = (ba[0].l + ba[0].r) / 2; | ||||
| ba[0].cy = (ba[0].u + ba[0].b) / 2; | ba[0].cy = (ba[0].u + ba[0].b) / 2; | ||||
| ba[1].l = root->l; | ba[1].l = root->l; | ||||
| Show All 16 Lines | static void lineart_bounding_area_split(LineartData *ld, | ||||
| ba[3].b = root->b; | ba[3].b = root->b; | ||||
| ba[3].cx = (ba[3].l + ba[3].r) / 2; | ba[3].cx = (ba[3].l + ba[3].r) / 2; | ||||
| ba[3].cy = (ba[3].u + ba[3].b) / 2; | ba[3].cy = (ba[3].u + ba[3].b) / 2; | ||||
| /* Init linked_triangles array and locks. */ | /* Init linked_triangles array and locks. */ | ||||
| for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
| ba[i].max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT; | ba[i].max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT; | ||||
| ba[i].max_line_count = LRT_TILE_EDGE_COUNT_INITIAL; | ba[i].max_line_count = LRT_TILE_EDGE_COUNT_INITIAL; | ||||
| ba[i].linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count, | ba[i].linked_triangles = static_cast<LineartTriangle **>( | ||||
| "ba_linked_triangles"); | MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count, "ba_linked_triangles")); | ||||
| ba[i].linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count, | ba[i].linked_lines = static_cast<LineartEdge **>( | ||||
| "ba_linked_lines"); | MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count, "ba_linked_lines")); | ||||
| BLI_spin_init(&ba[i].lock); | BLI_spin_init(&ba[i].lock); | ||||
| } | } | ||||
| for (uint32_t i = 0; i < root->triangle_count; i++) { | for (uint32_t i = 0; i < root->triangle_count; i++) { | ||||
| LineartTriangle *tri = root->linked_triangles[i]; | LineartTriangle *tri = root->linked_triangles[i]; | ||||
| double b[4]; | double b[4]; | ||||
| b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | ||||
| b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | ||||
| b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | ||||
| b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | ||||
| /* Re-link triangles into child tiles, not doing intersection lines during this because this | /* Re-link triangles into child tiles, not doing intersection lines during this because this | ||||
| * batch of triangles are all tested with each other for intersections. */ | * batch of triangles are all tested with each other for intersections. */ | ||||
| if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) { | if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) { | ||||
| lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL); | lineart_bounding_area_link_triangle( | ||||
| ld, &ba[0], tri, b, 0, recursive_level + 1, false, nullptr); | |||||
| } | } | ||||
| if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) { | if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) { | ||||
| lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL); | lineart_bounding_area_link_triangle( | ||||
| ld, &ba[1], tri, b, 0, recursive_level + 1, false, nullptr); | |||||
| } | } | ||||
| if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) { | if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) { | ||||
| lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL); | lineart_bounding_area_link_triangle( | ||||
| ld, &ba[2], tri, b, 0, recursive_level + 1, false, nullptr); | |||||
| } | } | ||||
| if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) { | if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) { | ||||
| lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL); | lineart_bounding_area_link_triangle( | ||||
| ld, &ba[3], tri, b, 0, recursive_level + 1, false, nullptr); | |||||
| } | } | ||||
| } | } | ||||
| /* At this point the child tiles are fully initialized and it's safe for new triangles to be | /* At this point the child tiles are fully initialized and it's safe for new triangles to be | ||||
| * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */ | * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */ | ||||
| root->child = ba; | root->child = ba; | ||||
| } | } | ||||
| static bool lineart_bounding_area_edge_intersect(LineartData *UNUSED(fb), | static bool lineart_bounding_area_edge_intersect(LineartData * /*fb*/, | ||||
| const double l[2], | const double l[2], | ||||
| const double r[2], | const double r[2], | ||||
| LineartBoundingArea *ba) | LineartBoundingArea *ba) | ||||
| { | { | ||||
| double dx, dy; | double dx, dy; | ||||
| double converted[4]; | double converted[4]; | ||||
| double c1, c; | double c1, c; | ||||
| ▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
| */ | */ | ||||
| static void lineart_bounding_area_link_triangle(LineartData *ld, | static void lineart_bounding_area_link_triangle(LineartData *ld, | ||||
| LineartBoundingArea *root_ba, | LineartBoundingArea *root_ba, | ||||
| LineartTriangle *tri, | LineartTriangle *tri, | ||||
| double l_r_u_b[4], | double l_r_u_b[4], | ||||
| int recursive, | int recursive, | ||||
| int recursive_level, | int recursive_level, | ||||
| bool do_intersection, | bool do_intersection, | ||||
| struct LineartIsecThread *th) | LineartIsecThread *th) | ||||
| { | { | ||||
| bool triangle_vert_inside; | bool triangle_vert_inside; | ||||
| if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba, &triangle_vert_inside)) { | if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba, &triangle_vert_inside)) { | ||||
| return; | return; | ||||
| } | } | ||||
| LineartBoundingArea *old_ba = root_ba; | LineartBoundingArea *old_ba = root_ba; | ||||
| if (old_ba->child) { | if (old_ba->child) { | ||||
| /* If old_ba->child is not NULL, then tile splitting is fully finished, safe to directly insert | /* If old_ba->child is not nullptr, then tile splitting is fully finished, safe to directly | ||||
| * into child tiles. */ | * insert into child tiles. */ | ||||
| double *B1 = l_r_u_b; | double *B1 = l_r_u_b; | ||||
| double b[4]; | double b[4]; | ||||
| if (!l_r_u_b) { | if (!l_r_u_b) { | ||||
| b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | ||||
| b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | ||||
| b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | ||||
| b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | ||||
| B1 = b; | B1 = b; | ||||
| } | } | ||||
| for (int iba = 0; iba < 4; iba++) { | for (int iba = 0; iba < 4; iba++) { | ||||
| if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) { | if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) { | ||||
| lineart_bounding_area_link_triangle( | lineart_bounding_area_link_triangle( | ||||
| ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th); | ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th); | ||||
| } | } | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is NULL | /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is nullptr | ||||
| * in that situation. */ | * in that situation. */ | ||||
| if (th) { | if (th) { | ||||
| BLI_spin_lock(&old_ba->lock); | BLI_spin_lock(&old_ba->lock); | ||||
| } | } | ||||
| /* If there are still space left in this tile for insertion. */ | /* If there are still space left in this tile for insertion. */ | ||||
| if (old_ba->triangle_count < old_ba->max_triangle_count) { | if (old_ba->triangle_count < old_ba->max_triangle_count) { | ||||
| const uint32_t old_tri_count = old_ba->triangle_count; | const uint32_t old_tri_count = old_ba->triangle_count; | ||||
| Show All 14 Lines | if (th) { | ||||
| BLI_spin_unlock(&old_ba->lock); | BLI_spin_unlock(&old_ba->lock); | ||||
| } | } | ||||
| } | } | ||||
| else { /* We need to wait for either splitting or array extension to be done. */ | else { /* We need to wait for either splitting or array extension to be done. */ | ||||
| if (recursive_level < ld->qtree.recursive_level && | if (recursive_level < ld->qtree.recursive_level && | ||||
| old_ba->insider_triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT) { | old_ba->insider_triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT) { | ||||
| if (!old_ba->child) { | if (!old_ba->child) { | ||||
| /* old_ba->child==NULL, means we are the thread that's doing the splitting. */ | /* old_ba->child==nullptr, means we are the thread that's doing the splitting. */ | ||||
| lineart_bounding_area_split(ld, old_ba, recursive_level); | lineart_bounding_area_split(ld, old_ba, recursive_level); | ||||
| } /* Otherwise other thread has completed the splitting process. */ | } /* Otherwise other thread has completed the splitting process. */ | ||||
| } | } | ||||
| else { | else { | ||||
| if (old_ba->triangle_count == old_ba->max_triangle_count) { | if (old_ba->triangle_count == old_ba->max_triangle_count) { | ||||
| /* Means we are the thread that's doing the extension. */ | /* Means we are the thread that's doing the extension. */ | ||||
| lineart_bounding_area_triangle_reallocate(old_ba); | lineart_bounding_area_triangle_reallocate(old_ba); | ||||
| } /* Otherwise other thread has completed the extending the array. */ | } /* Otherwise other thread has completed the extending the array. */ | ||||
| Show All 33 Lines | for (int i = 0; i < ld->qtree.count_y; i++) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void lineart_bounding_area_link_edge(LineartData *ld, | static void lineart_bounding_area_link_edge(LineartData *ld, | ||||
| LineartBoundingArea *root_ba, | LineartBoundingArea *root_ba, | ||||
| LineartEdge *e) | LineartEdge *e) | ||||
| { | { | ||||
| if (root_ba->child == NULL) { | if (root_ba->child == nullptr) { | ||||
| lineart_bounding_area_line_add(root_ba, e); | lineart_bounding_area_line_add(root_ba, e); | ||||
| } | } | ||||
| else { | else { | ||||
| if (lineart_bounding_area_edge_intersect( | if (lineart_bounding_area_edge_intersect( | ||||
| ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) { | ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) { | ||||
| lineart_bounding_area_link_edge(ld, &root_ba->child[0], e); | lineart_bounding_area_link_edge(ld, &root_ba->child[0], e); | ||||
| } | } | ||||
| if (lineart_bounding_area_edge_intersect( | if (lineart_bounding_area_edge_intersect( | ||||
| Show All 18 Lines | for (int i = 0; i < 4; i++) { | ||||
| lineart_clear_linked_edges_recursive(ld, &root_ba->child[i]); | lineart_clear_linked_edges_recursive(ld, &root_ba->child[i]); | ||||
| } | } | ||||
| } | } | ||||
| if (root_ba->linked_lines) { | if (root_ba->linked_lines) { | ||||
| MEM_freeN(root_ba->linked_lines); | MEM_freeN(root_ba->linked_lines); | ||||
| } | } | ||||
| root_ba->line_count = 0; | root_ba->line_count = 0; | ||||
| root_ba->max_line_count = 128; | root_ba->max_line_count = 128; | ||||
| root_ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * root_ba->max_line_count, | root_ba->linked_lines = static_cast<LineartEdge **>( | ||||
| "cleared lineart edges"); | MEM_callocN(sizeof(LineartEdge *) * root_ba->max_line_count, "cleared lineart edges")); | ||||
| } | } | ||||
| void lineart_main_clear_linked_edges(LineartData *ld) | void lineart_main_clear_linked_edges(LineartData *ld) | ||||
| { | { | ||||
| LineartBoundingArea *ba = ld->qtree.initials; | LineartBoundingArea *ba = ld->qtree.initials; | ||||
| for (int i = 0; i < ld->qtree.count_y; i++) { | for (int i = 0; i < ld->qtree.count_y; i++) { | ||||
| for (int j = 0; j < ld->qtree.count_x; j++) { | for (int j = 0; j < ld->qtree.count_x; j++) { | ||||
| lineart_clear_linked_edges_recursive(ld, &ba[i * ld->qtree.count_x + j]); | lineart_clear_linked_edges_recursive(ld, &ba[i * ld->qtree.count_x + j]); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (int i = 0; i < ba->line_count; i++) { | ||||
| usable_count++; | usable_count++; | ||||
| } | } | ||||
| if (!usable_count) { | if (!usable_count) { | ||||
| ba->line_count = 0; | ba->line_count = 0; | ||||
| return; | return; | ||||
| } | } | ||||
| LineartEdge **new_array = MEM_callocN(sizeof(LineartEdge *) * usable_count, | LineartEdge **new_array = static_cast<LineartEdge **>( | ||||
| "cleaned lineart edge array"); | MEM_callocN(sizeof(LineartEdge *) * usable_count, "cleaned lineart edge array")); | ||||
| int new_i = 0; | int new_i = 0; | ||||
| for (int i = 0; i < ba->line_count; i++) { | for (int i = 0; i < ba->line_count; i++) { | ||||
| LineartEdge *e = ba->linked_lines[i]; | LineartEdge *e = ba->linked_lines[i]; | ||||
| if (e->min_occ > max_occlusion) { | if (e->min_occ > max_occlusion) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| new_array[new_i] = e; | new_array[new_i] = e; | ||||
| Show All 29 Lines | static bool lineart_get_triangle_bounding_areas( | ||||
| b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]); | ||||
| b[2] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | b[2] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | ||||
| b[3] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | b[3] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]); | ||||
| if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) { | if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| (*colbegin) = (int)((b[0] + 1.0) / sp_w); | (*colbegin) = int((b[0] + 1.0) / sp_w); | ||||
| (*colend) = (int)((b[1] + 1.0) / sp_w); | (*colend) = int((b[1] + 1.0) / sp_w); | ||||
| (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1; | (*rowend) = ld->qtree.count_y - int((b[2] + 1.0) / sp_h) - 1; | ||||
| (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1; | (*rowbegin) = ld->qtree.count_y - int((b[3] + 1.0) / sp_h) - 1; | ||||
| if ((*colend) >= ld->qtree.count_x) { | if ((*colend) >= ld->qtree.count_x) { | ||||
| (*colend) = ld->qtree.count_x - 1; | (*colend) = ld->qtree.count_x - 1; | ||||
| } | } | ||||
| if ((*rowend) >= ld->qtree.count_y) { | if ((*rowend) >= ld->qtree.count_y) { | ||||
| (*rowend) = ld->qtree.count_y - 1; | (*rowend) = ld->qtree.count_y - 1; | ||||
| } | } | ||||
| if ((*colbegin) < 0) { | if ((*colbegin) < 0) { | ||||
| Show All 24 Lines | static bool lineart_get_edge_bounding_areas( | ||||
| b[1] = MAX2(e->v1->fbcoord[0], e->v2->fbcoord[0]); | b[1] = MAX2(e->v1->fbcoord[0], e->v2->fbcoord[0]); | ||||
| b[2] = MIN2(e->v1->fbcoord[1], e->v2->fbcoord[1]); | b[2] = MIN2(e->v1->fbcoord[1], e->v2->fbcoord[1]); | ||||
| b[3] = MAX2(e->v1->fbcoord[1], e->v2->fbcoord[1]); | b[3] = MAX2(e->v1->fbcoord[1], e->v2->fbcoord[1]); | ||||
| if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) { | if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| (*colbegin) = (int)((b[0] + 1.0) / sp_w); | (*colbegin) = int((b[0] + 1.0) / sp_w); | ||||
| (*colend) = (int)((b[1] + 1.0) / sp_w); | (*colend) = int((b[1] + 1.0) / sp_w); | ||||
| (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1; | (*rowend) = ld->qtree.count_y - int((b[2] + 1.0) / sp_h) - 1; | ||||
| (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1; | (*rowbegin) = ld->qtree.count_y - int((b[3] + 1.0) / sp_h) - 1; | ||||
| /* It's possible that the line stretches too much out to the side, resulting negative value. */ | /* It's possible that the line stretches too much out to the side, resulting negative value. */ | ||||
| if ((*rowend) < (*rowbegin)) { | if ((*rowend) < (*rowbegin)) { | ||||
| (*rowend) = ld->qtree.count_y - 1; | (*rowend) = ld->qtree.count_y - 1; | ||||
| } | } | ||||
| if ((*colend) < (*colbegin)) { | if ((*colend) < (*colbegin)) { | ||||
| (*colend) = ld->qtree.count_x - 1; | (*colend) = ld->qtree.count_x - 1; | ||||
| Show All 11 Lines | |||||
| { | { | ||||
| double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; | double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; | ||||
| int col, row; | int col, row; | ||||
| if (x > 1 || x < -1 || y > 1 || y < -1) { | if (x > 1 || x < -1 || y > 1 || y < -1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| col = (int)((x + 1.0) / sp_w); | col = int((x + 1.0) / sp_w); | ||||
| row = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1; | row = ld->qtree.count_y - int((y + 1.0) / sp_h) - 1; | ||||
| if (col >= ld->qtree.count_x) { | if (col >= ld->qtree.count_x) { | ||||
| col = ld->qtree.count_x - 1; | col = ld->qtree.count_x - 1; | ||||
| } | } | ||||
| if (row >= ld->qtree.count_y) { | if (row >= ld->qtree.count_y) { | ||||
| row = ld->qtree.count_y - 1; | row = ld->qtree.count_y - 1; | ||||
| } | } | ||||
| if (col < 0) { | if (col < 0) { | ||||
| col = 0; | col = 0; | ||||
| } | } | ||||
| if (row < 0) { | if (row < 0) { | ||||
| row = 0; | row = 0; | ||||
| } | } | ||||
| return &ld->qtree.initials[row * ld->qtree.count_x + col]; | return &ld->qtree.initials[row * ld->qtree.count_x + col]; | ||||
| } | } | ||||
| static LineartBoundingArea *lineart_get_bounding_area(LineartData *ld, double x, double y) | static LineartBoundingArea *lineart_get_bounding_area(LineartData *ld, double x, double y) | ||||
| { | { | ||||
| LineartBoundingArea *iba; | LineartBoundingArea *iba; | ||||
| double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; | double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height; | ||||
| int c = (int)((x + 1.0) / sp_w); | int c = int((x + 1.0) / sp_w); | ||||
| int r = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1; | int r = ld->qtree.count_y - int((y + 1.0) / sp_h) - 1; | ||||
| if (r < 0) { | if (r < 0) { | ||||
| r = 0; | r = 0; | ||||
| } | } | ||||
| if (c < 0) { | if (c < 0) { | ||||
| c = 0; | c = 0; | ||||
| } | } | ||||
| if (r >= ld->qtree.count_y) { | if (r >= ld->qtree.count_y) { | ||||
| r = ld->qtree.count_y - 1; | r = ld->qtree.count_y - 1; | ||||
| Show All 22 Lines | while (iba->child) { | ||||
| } | } | ||||
| } | } | ||||
| return iba; | return iba; | ||||
| } | } | ||||
| LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y) | LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y) | ||||
| { | { | ||||
| LineartBoundingArea *ba; | LineartBoundingArea *ba; | ||||
| if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != NULL) { | if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != nullptr) { | ||||
| return lineart_get_bounding_area(ld, x, y); | return lineart_get_bounding_area(ld, x, y); | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), LineartIsecThread *th) | static void lineart_add_triangles_worker(TaskPool *__restrict /*pool*/, LineartIsecThread *th) | ||||
| { | { | ||||
| LineartData *ld = th->ld; | LineartData *ld = th->ld; | ||||
| int _dir_control = 0; | int _dir_control = 0; | ||||
| while (lineart_schedule_new_triangle_task(th)) { | while (lineart_schedule_new_triangle_task(th)) { | ||||
| for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next; | for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next; | ||||
| eln = eln->next) { | eln = eln->next) { | ||||
| int index_start = eln == th->pending_from ? th->index_from : 0; | int index_start = eln == th->pending_from ? th->index_from : 0; | ||||
| int index_end = eln == th->pending_to ? th->index_to : eln->element_count; | int index_end = eln == th->pending_to ? th->index_to : eln->element_count; | ||||
| LineartTriangle *tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start); | LineartTriangle *tri = static_cast<LineartTriangle *>( | ||||
| (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start)); | |||||
| for (int ei = index_start; ei < index_end; ei++) { | for (int ei = index_start; ei < index_end; ei++) { | ||||
| int x1, x2, y1, y2; | int x1, x2, y1, y2; | ||||
| int r, co; | int r, co; | ||||
| if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) { | if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) { | ||||
| tri = (void *)(((uchar *)tri) + ld->sizeof_triangle); | tri = static_cast<LineartTriangle *>((void *)(((uchar *)tri) + ld->sizeof_triangle)); | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) { | if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) { | ||||
| _dir_control++; | _dir_control++; | ||||
| for (co = x1; co <= x2; co++) { | for (co = x1; co <= x2; co++) { | ||||
| for (r = y1; r <= y2; r++) { | for (r = y1; r <= y2; r++) { | ||||
| lineart_bounding_area_link_triangle( | lineart_bounding_area_link_triangle( | ||||
| ld, &ld->qtree.initials[r * ld->qtree.count_x + co], tri, 0, 1, 0, 1, th); | ld, &ld->qtree.initials[r * ld->qtree.count_x + co], tri, 0, 1, 0, 1, th); | ||||
| } | } | ||||
| } | } | ||||
| } /* Else throw away. */ | } /* Else throw away. */ | ||||
| tri = (void *)(((uchar *)tri) + ld->sizeof_triangle); | tri = static_cast<LineartTriangle *>((void *)(((uchar *)tri) + ld->sizeof_triangle)); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void lineart_create_edges_from_isec_data(LineartIsecData *d) | static void lineart_create_edges_from_isec_data(LineartIsecData *d) | ||||
| { | { | ||||
| LineartData *ld = d->ld; | LineartData *ld = d->ld; | ||||
| Show All 13 Lines | static void lineart_create_edges_from_isec_data(LineartIsecData *d) | ||||
| } | } | ||||
| if (!total_lines) { | if (!total_lines) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* We don't care about removing duplicated vert in this method, chaining can handle that, | /* We don't care about removing duplicated vert in this method, chaining can handle that, | ||||
| * and it saves us from using locks and look up tables. */ | * and it saves us from using locks and look up tables. */ | ||||
| LineartVert *v = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartVert) * total_lines * 2); | LineartVert *v = static_cast<LineartVert *>( | ||||
| LineartEdge *e = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * total_lines); | lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartVert) * total_lines * 2)); | ||||
| LineartEdgeSegment *es = lineart_mem_acquire(ld->edge_data_pool, | LineartEdge *e = static_cast<LineartEdge *>( | ||||
| sizeof(LineartEdgeSegment) * total_lines); | lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * total_lines)); | ||||
| LineartEdgeSegment *es = static_cast<LineartEdgeSegment *>( | |||||
| lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdgeSegment) * total_lines)); | |||||
| LineartElementLinkNode *eln = lineart_mem_acquire(ld->edge_data_pool, | LineartElementLinkNode *eln = static_cast<LineartElementLinkNode *>( | ||||
| sizeof(LineartElementLinkNode)); | lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartElementLinkNode))); | ||||
| eln->element_count = total_lines; | eln->element_count = total_lines; | ||||
| eln->pointer = e; | eln->pointer = e; | ||||
| eln->flags |= LRT_ELEMENT_INTERSECTION_DATA; | eln->flags |= LRT_ELEMENT_INTERSECTION_DATA; | ||||
| BLI_addhead(&ld->geom.line_buffer_pointers, eln); | BLI_addhead(&ld->geom.line_buffer_pointers, eln); | ||||
| for (int i = 0; i < d->thread_count; i++) { | for (int i = 0; i < d->thread_count; i++) { | ||||
| LineartIsecThread *th = &d->threads[i]; | LineartIsecThread *th = &d->threads[i]; | ||||
| if (!th->current) { | if (!th->current) { | ||||
| Show All 36 Lines | for (int j = 0; j < th->current; j++) { | ||||
| int obi1 = (e->t1->target_reference & LRT_OBINDEX_HIGHER); | int obi1 = (e->t1->target_reference & LRT_OBINDEX_HIGHER); | ||||
| int obi2 = (e->t2->target_reference & LRT_OBINDEX_HIGHER); | int obi2 = (e->t2->target_reference & LRT_OBINDEX_HIGHER); | ||||
| LineartElementLinkNode *eln1 = lineart_find_matching_eln(&ld->geom.line_buffer_pointers, | LineartElementLinkNode *eln1 = lineart_find_matching_eln(&ld->geom.line_buffer_pointers, | ||||
| obi1); | obi1); | ||||
| LineartElementLinkNode *eln2 = obi1 == obi2 ? eln1 : | LineartElementLinkNode *eln2 = obi1 == obi2 ? eln1 : | ||||
| lineart_find_matching_eln( | lineart_find_matching_eln( | ||||
| &ld->geom.line_buffer_pointers, obi2); | &ld->geom.line_buffer_pointers, obi2); | ||||
| Object *ob1 = eln1 ? eln1->object_ref : NULL; | Object *ob1 = eln1 ? static_cast<Object *>(eln1->object_ref) : nullptr; | ||||
| Object *ob2 = eln2 ? eln2->object_ref : NULL; | Object *ob2 = eln2 ? static_cast<Object *>(eln2->object_ref) : nullptr; | ||||
| if (e->t1->intersection_priority > e->t2->intersection_priority) { | if (e->t1->intersection_priority > e->t2->intersection_priority) { | ||||
| e->object_ref = ob1; | e->object_ref = ob1; | ||||
| } | } | ||||
| else if (e->t1->intersection_priority < e->t2->intersection_priority) { | else if (e->t1->intersection_priority < e->t2->intersection_priority) { | ||||
| e->object_ref = ob2; | e->object_ref = ob2; | ||||
| } | } | ||||
| else { /* equal priority */ | else { /* equal priority */ | ||||
| if (ob1 == ob2) { | if (ob1 == ob2) { | ||||
| Show All 22 Lines | if (G.debug_value == 4000) { | ||||
| t_start = PIL_check_seconds_timer(); | t_start = PIL_check_seconds_timer(); | ||||
| } | } | ||||
| /* Initialize per-thread data for thread task scheduling information and storing intersection | /* Initialize per-thread data for thread task scheduling information and storing intersection | ||||
| * results. */ | * results. */ | ||||
| LineartIsecData d = {0}; | LineartIsecData d = {0}; | ||||
| lineart_init_isec_thread(&d, ld, ld->thread_count); | lineart_init_isec_thread(&d, ld, ld->thread_count); | ||||
| TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH); | TaskPool *tp = BLI_task_pool_create(nullptr, TASK_PRIORITY_HIGH); | ||||
| for (int i = 0; i < ld->thread_count; i++) { | for (int i = 0; i < ld->thread_count; i++) { | ||||
| BLI_task_pool_push(tp, (TaskRunFunction)lineart_add_triangles_worker, &d.threads[i], 0, NULL); | BLI_task_pool_push( | ||||
| tp, (TaskRunFunction)lineart_add_triangles_worker, &d.threads[i], 0, nullptr); | |||||
| } | } | ||||
| BLI_task_pool_work_and_wait(tp); | BLI_task_pool_work_and_wait(tp); | ||||
| BLI_task_pool_free(tp); | BLI_task_pool_free(tp); | ||||
| if (ld->conf.use_intersections) { | if (ld->conf.use_intersections) { | ||||
| lineart_create_edges_from_isec_data(&d); | lineart_create_edges_from_isec_data(&d); | ||||
| } | } | ||||
| Show All 38 Lines | LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld, | ||||
| return lineart_get_bounding_area(ld, data[0], data[1]); | return lineart_get_bounding_area(ld, data[0], data[1]); | ||||
| } | } | ||||
| /** | /** | ||||
| * This march along one render line in image space and | * This march along one render line in image space and | ||||
| * get the next bounding area the line is crossing. | * get the next bounding area the line is crossing. | ||||
| */ | */ | ||||
| LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this, | LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *self, | ||||
| double *fbcoord1, | double *fbcoord1, | ||||
| double *fbcoord2, | double *fbcoord2, | ||||
| double x, | double x, | ||||
| double y, | double y, | ||||
| double k, | double k, | ||||
| int positive_x, | int positive_x, | ||||
| int positive_y, | int positive_y, | ||||
| double *next_x, | double *next_x, | ||||
| double *next_y) | double *next_y) | ||||
| { | { | ||||
| double rx, ry, ux, uy, lx, ly, bx, by; | double rx, ry, ux, uy, lx, ly, bx, by; | ||||
| double r1, r2; | double r1, r2; | ||||
| LineartBoundingArea *ba; | LineartBoundingArea *ba; | ||||
| /* If we are marching towards the right. */ | /* If we are marching towards the right. */ | ||||
| if (positive_x > 0) { | if (positive_x > 0) { | ||||
| rx = this->r; | rx = self->r; | ||||
| ry = y + k * (rx - x); | ry = y + k * (rx - x); | ||||
| /* If we are marching towards the top. */ | /* If we are marching towards the top. */ | ||||
| if (positive_y > 0) { | if (positive_y > 0) { | ||||
| uy = this->u; | uy = self->u; | ||||
| ux = x + (uy - y) / k; | ux = x + (uy - y) / k; | ||||
| r1 = ratiod(fbcoord1[0], fbcoord2[0], rx); | r1 = ratiod(fbcoord1[0], fbcoord2[0], rx); | ||||
| r2 = ratiod(fbcoord1[0], fbcoord2[0], ux); | r2 = ratiod(fbcoord1[0], fbcoord2[0], ux); | ||||
| if (MIN2(r1, r2) > 1) { | if (MIN2(r1, r2) > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* We reached the right side before the top side. */ | /* We reached the right side before the top side. */ | ||||
| if (r1 <= r2) { | if (r1 <= r2) { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->rp) { | LISTBASE_FOREACH (LinkData *, lip, &self->rp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->u >= ry && ba->b < ry) { | if (ba->u >= ry && ba->b < ry) { | ||||
| *next_x = rx; | *next_x = rx; | ||||
| *next_y = ry; | *next_y = ry; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* We reached the top side before the right side. */ | /* We reached the top side before the right side. */ | ||||
| else { | else { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->up) { | LISTBASE_FOREACH (LinkData *, lip, &self->up) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->r >= ux && ba->l < ux) { | if (ba->r >= ux && ba->l < ux) { | ||||
| *next_x = ux; | *next_x = ux; | ||||
| *next_y = uy; | *next_y = uy; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* If we are marching towards the bottom. */ | /* If we are marching towards the bottom. */ | ||||
| else if (positive_y < 0) { | else if (positive_y < 0) { | ||||
| by = this->b; | by = self->b; | ||||
| bx = x + (by - y) / k; | bx = x + (by - y) / k; | ||||
| r1 = ratiod(fbcoord1[0], fbcoord2[0], rx); | r1 = ratiod(fbcoord1[0], fbcoord2[0], rx); | ||||
| r2 = ratiod(fbcoord1[0], fbcoord2[0], bx); | r2 = ratiod(fbcoord1[0], fbcoord2[0], bx); | ||||
| if (MIN2(r1, r2) > 1) { | if (MIN2(r1, r2) > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (r1 <= r2) { | if (r1 <= r2) { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->rp) { | LISTBASE_FOREACH (LinkData *, lip, &self->rp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->u >= ry && ba->b < ry) { | if (ba->u >= ry && ba->b < ry) { | ||||
| *next_x = rx; | *next_x = rx; | ||||
| *next_y = ry; | *next_y = ry; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->bp) { | LISTBASE_FOREACH (LinkData *, lip, &self->bp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->r >= bx && ba->l < bx) { | if (ba->r >= bx && ba->l < bx) { | ||||
| *next_x = bx; | *next_x = bx; | ||||
| *next_y = by; | *next_y = by; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* If the line is completely horizontal, in which Y difference == 0. */ | /* If the line is completely horizontal, in which Y difference == 0. */ | ||||
| else { | else { | ||||
| r1 = ratiod(fbcoord1[0], fbcoord2[0], this->r); | r1 = ratiod(fbcoord1[0], fbcoord2[0], self->r); | ||||
| if (r1 > 1) { | if (r1 > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->rp) { | LISTBASE_FOREACH (LinkData *, lip, &self->rp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->u >= y && ba->b < y) { | if (ba->u >= y && ba->b < y) { | ||||
| *next_x = this->r; | *next_x = self->r; | ||||
| *next_y = y; | *next_y = y; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* If we are marching towards the left. */ | /* If we are marching towards the left. */ | ||||
| else if (positive_x < 0) { | else if (positive_x < 0) { | ||||
| lx = this->l; | lx = self->l; | ||||
| ly = y + k * (lx - x); | ly = y + k * (lx - x); | ||||
| /* If we are marching towards the top. */ | /* If we are marching towards the top. */ | ||||
| if (positive_y > 0) { | if (positive_y > 0) { | ||||
| uy = this->u; | uy = self->u; | ||||
| ux = x + (uy - y) / k; | ux = x + (uy - y) / k; | ||||
| r1 = ratiod(fbcoord1[0], fbcoord2[0], lx); | r1 = ratiod(fbcoord1[0], fbcoord2[0], lx); | ||||
| r2 = ratiod(fbcoord1[0], fbcoord2[0], ux); | r2 = ratiod(fbcoord1[0], fbcoord2[0], ux); | ||||
| if (MIN2(r1, r2) > 1) { | if (MIN2(r1, r2) > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (r1 <= r2) { | if (r1 <= r2) { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->lp) { | LISTBASE_FOREACH (LinkData *, lip, &self->lp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->u >= ly && ba->b < ly) { | if (ba->u >= ly && ba->b < ly) { | ||||
| *next_x = lx; | *next_x = lx; | ||||
| *next_y = ly; | *next_y = ly; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->up) { | LISTBASE_FOREACH (LinkData *, lip, &self->up) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->r >= ux && ba->l < ux) { | if (ba->r >= ux && ba->l < ux) { | ||||
| *next_x = ux; | *next_x = ux; | ||||
| *next_y = uy; | *next_y = uy; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* If we are marching towards the bottom. */ | /* If we are marching towards the bottom. */ | ||||
| else if (positive_y < 0) { | else if (positive_y < 0) { | ||||
| by = this->b; | by = self->b; | ||||
| bx = x + (by - y) / k; | bx = x + (by - y) / k; | ||||
| r1 = ratiod(fbcoord1[0], fbcoord2[0], lx); | r1 = ratiod(fbcoord1[0], fbcoord2[0], lx); | ||||
| r2 = ratiod(fbcoord1[0], fbcoord2[0], bx); | r2 = ratiod(fbcoord1[0], fbcoord2[0], bx); | ||||
| if (MIN2(r1, r2) > 1) { | if (MIN2(r1, r2) > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (r1 <= r2) { | if (r1 <= r2) { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->lp) { | LISTBASE_FOREACH (LinkData *, lip, &self->lp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->u >= ly && ba->b < ly) { | if (ba->u >= ly && ba->b < ly) { | ||||
| *next_x = lx; | *next_x = lx; | ||||
| *next_y = ly; | *next_y = ly; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->bp) { | LISTBASE_FOREACH (LinkData *, lip, &self->bp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->r >= bx && ba->l < bx) { | if (ba->r >= bx && ba->l < bx) { | ||||
| *next_x = bx; | *next_x = bx; | ||||
| *next_y = by; | *next_y = by; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Again, horizontal. */ | /* Again, horizontal. */ | ||||
| else { | else { | ||||
| r1 = ratiod(fbcoord1[0], fbcoord2[0], this->l); | r1 = ratiod(fbcoord1[0], fbcoord2[0], self->l); | ||||
| if (r1 > 1) { | if (r1 > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->lp) { | LISTBASE_FOREACH (LinkData *, lip, &self->lp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->u >= y && ba->b < y) { | if (ba->u >= y && ba->b < y) { | ||||
| *next_x = this->l; | *next_x = self->l; | ||||
| *next_y = y; | *next_y = y; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* If the line is completely vertical, hence X difference == 0. */ | /* If the line is completely vertical, hence X difference == 0. */ | ||||
| else { | else { | ||||
| if (positive_y > 0) { | if (positive_y > 0) { | ||||
| r1 = ratiod(fbcoord1[1], fbcoord2[1], this->u); | r1 = ratiod(fbcoord1[1], fbcoord2[1], self->u); | ||||
| if (r1 > 1) { | if (r1 > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->up) { | LISTBASE_FOREACH (LinkData *, lip, &self->up) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->r > x && ba->l <= x) { | if (ba->r > x && ba->l <= x) { | ||||
| *next_x = x; | *next_x = x; | ||||
| *next_y = this->u; | *next_y = self->u; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (positive_y < 0) { | else if (positive_y < 0) { | ||||
| r1 = ratiod(fbcoord1[1], fbcoord2[1], this->b); | r1 = ratiod(fbcoord1[1], fbcoord2[1], self->b); | ||||
| if (r1 > 1) { | if (r1 > 1) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| LISTBASE_FOREACH (LinkData *, lip, &this->bp) { | LISTBASE_FOREACH (LinkData *, lip, &self->bp) { | ||||
| ba = lip->data; | ba = static_cast<LineartBoundingArea *>(lip->data); | ||||
| if (ba->r > x && ba->l <= x) { | if (ba->r > x && ba->l <= x) { | ||||
| *next_x = x; | *next_x = x; | ||||
| *next_y = this->b; | *next_y = self->b; | ||||
| return ba; | return ba; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* Segment has no length. */ | /* Segment has no length. */ | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, | ||||
| *cached_result = lc; | *cached_result = lc; | ||||
| ld = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc); | ld = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc); | ||||
| /* Triangle thread testing data size varies depending on the thread count. | /* Triangle thread testing data size varies depending on the thread count. | ||||
| * See definition of LineartTriangleThread for details. */ | * See definition of LineartTriangleThread for details. */ | ||||
| ld->sizeof_triangle = lineart_triangle_size_get(ld); | ld->sizeof_triangle = lineart_triangle_size_get(ld); | ||||
| LineartData *shadow_rb = NULL; | LineartData *shadow_rb = nullptr; | ||||
| LineartElementLinkNode *shadow_veln, *shadow_eeln; | LineartElementLinkNode *shadow_veln, *shadow_eeln; | ||||
| ListBase *shadow_elns = ld->conf.shadow_selection ? &lc->shadow_elns : NULL; | ListBase *shadow_elns = ld->conf.shadow_selection ? &lc->shadow_elns : nullptr; | ||||
| bool shadow_generated = lineart_main_try_generate_shadow(depsgraph, | bool shadow_generated = lineart_main_try_generate_shadow(depsgraph, | ||||
| scene, | scene, | ||||
| ld, | ld, | ||||
| lmd, | lmd, | ||||
| &lc->shadow_data_pool, | &lc->shadow_data_pool, | ||||
| &shadow_veln, | &shadow_veln, | ||||
| &shadow_eeln, | &shadow_eeln, | ||||
| shadow_elns, | shadow_elns, | ||||
| ▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, | ||||
| return true; | return true; | ||||
| } | } | ||||
| static void lineart_gpencil_generate(LineartCache *cache, | static void lineart_gpencil_generate(LineartCache *cache, | ||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| Object *gpencil_object, | Object *gpencil_object, | ||||
| float (*gp_obmat_inverse)[4], | float (*gp_obmat_inverse)[4], | ||||
| bGPDlayer *UNUSED(gpl), | bGPDlayer * /*gpl*/, | ||||
| bGPDframe *gpf, | bGPDframe *gpf, | ||||
| int level_start, | int level_start, | ||||
| int level_end, | int level_end, | ||||
| int material_nr, | int material_nr, | ||||
| Object *source_object, | Object *source_object, | ||||
| Collection *source_collection, | Collection *source_collection, | ||||
| int types, | int types, | ||||
| uchar mask_switches, | uchar mask_switches, | ||||
| uchar material_mask_bits, | uchar material_mask_bits, | ||||
| uchar intersection_mask, | uchar intersection_mask, | ||||
| int16_t thickness, | int16_t thickness, | ||||
| float opacity, | float opacity, | ||||
| uchar shaodow_selection, | uchar shaodow_selection, | ||||
| uchar silhouette_mode, | uchar silhouette_mode, | ||||
| const char *source_vgname, | const char *source_vgname, | ||||
| const char *vgname, | const char *vgname, | ||||
| int modifier_flags) | int modifier_flags) | ||||
| { | { | ||||
| if (cache == NULL) { | if (cache == nullptr) { | ||||
| if (G.debug_value == 4000) { | if (G.debug_value == 4000) { | ||||
| printf("NULL Lineart cache!\n"); | printf("nullptr Lineart cache!\n"); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| int stroke_count = 0; | int stroke_count = 0; | ||||
| int color_idx = 0; | int color_idx = 0; | ||||
| Object *orig_ob = NULL; | Object *orig_ob = nullptr; | ||||
| if (source_object) { | if (source_object) { | ||||
| orig_ob = source_object->id.orig_id ? (Object *)source_object->id.orig_id : source_object; | orig_ob = source_object->id.orig_id ? (Object *)source_object->id.orig_id : source_object; | ||||
| } | } | ||||
| Collection *orig_col = NULL; | Collection *orig_col = nullptr; | ||||
| if (source_collection) { | if (source_collection) { | ||||
| orig_col = source_collection->id.orig_id ? (Collection *)source_collection->id.orig_id : | orig_col = source_collection->id.orig_id ? (Collection *)source_collection->id.orig_id : | ||||
| source_collection; | source_collection; | ||||
| } | } | ||||
| /* (!orig_col && !orig_ob) means the whole scene is selected. */ | /* (!orig_col && !orig_ob) means the whole scene is selected. */ | ||||
| int enabled_types = cache->all_enabled_edge_types; | int enabled_types = cache->all_enabled_edge_types; | ||||
| ▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | if (source_vgname && vgname) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (G.debug_value == 4000) { | if (G.debug_value == 4000) { | ||||
| BKE_gpencil_stroke_set_random_color(gps); | BKE_gpencil_stroke_set_random_color(gps); | ||||
| } | } | ||||
| BKE_gpencil_stroke_geometry_update(gpencil_object->data, gps); | BKE_gpencil_stroke_geometry_update(static_cast<bGPdata *>(gpencil_object->data), gps); | ||||
| stroke_count++; | stroke_count++; | ||||
| } | } | ||||
| if (G.debug_value == 4000) { | if (G.debug_value == 4000) { | ||||
| printf("LRT: Generated %d strokes.\n", stroke_count); | printf("LRT: Generated %d strokes.\n", stroke_count); | ||||
| } | } | ||||
| } | } | ||||
| Show All 19 Lines | void MOD_lineart_gpencil_generate(LineartCache *cache, | ||||
| const char *vgname, | const char *vgname, | ||||
| int modifier_flags) | int modifier_flags) | ||||
| { | { | ||||
| if (!gpl || !gpf || !ob) { | if (!gpl || !gpf || !ob) { | ||||
| return; | return; | ||||
| } | } | ||||
| Object *source_object = NULL; | Object *source_object = nullptr; | ||||
| Collection *source_collection = NULL; | Collection *source_collection = nullptr; | ||||
| int16_t use_types = edge_types; | int16_t use_types = edge_types; | ||||
| if (source_type == LRT_SOURCE_OBJECT) { | if (source_type == LRT_SOURCE_OBJECT) { | ||||
| if (!source_reference) { | if (!source_reference) { | ||||
| return; | return; | ||||
| } | } | ||||
| source_object = (Object *)source_reference; | source_object = (Object *)source_reference; | ||||
| } | } | ||||
| else if (source_type == LRT_SOURCE_COLLECTION) { | else if (source_type == LRT_SOURCE_COLLECTION) { | ||||
| Show All 31 Lines | |||||