Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/gpencil_geom.cc
- This file was moved from source/blender/blenkernel/intern/gpencil_geom.c.
| Show All 15 Lines | |||||
| * The Original Code is Copyright (C) 2008, Blender Foundation | * The Original Code is Copyright (C) 2008, Blender Foundation | ||||
| * This is a new part of Blender | * This is a new part of Blender | ||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup bke | * \ingroup bke | ||||
| */ | */ | ||||
| #include <math.h> | #include <cmath> | ||||
| #include <stddef.h> | #include <cstddef> | ||||
| #include <stdio.h> | #include <cstdio> | ||||
| #include <stdlib.h> | #include <cstdlib> | ||||
| #include <string.h> | #include <cstring> | ||||
| #include "CLG_log.h" | #include "CLG_log.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_float3.hh" | |||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | ||||
| #include "BLI_hash.h" | #include "BLI_hash.h" | ||||
| #include "BLI_heap.h" | #include "BLI_heap.h" | ||||
| #include "BLI_math_vector.h" | #include "BLI_math_vector.h" | ||||
| #include "BLI_polyfill_2d.h" | #include "BLI_polyfill_2d.h" | ||||
| #include "BLI_span.hh" | |||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "DNA_gpencil_modifier_types.h" | #include "DNA_gpencil_modifier_types.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_material_types.h" | #include "DNA_material_types.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_gpencil_curve.h" | #include "BKE_gpencil_curve.h" | ||||
| #include "BKE_gpencil_geom.h" | #include "BKE_gpencil_geom.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| using blender::float3; | |||||
| using blender::Span; | |||||
| /* GP Object - Boundbox Support */ | /* GP Object - Boundbox Support */ | ||||
| /** | /** | ||||
| *Get min/max coordinate bounds for single stroke. | *Get min/max coordinate bounds for single stroke. | ||||
| * \param gps: Grease pencil stroke | * \param gps: Grease pencil stroke | ||||
| * \param use_select: Include only selected points | * \param use_select: Include only selected points | ||||
| * \param r_min: Result minimum coordinates | * \param r_min: Result minimum coordinates | ||||
| * \param r_max: Result maximum coordinates | * \param r_max: Result maximum coordinates | ||||
| * \return True if it was possible to calculate | * \return True if it was possible to calculate | ||||
| */ | */ | ||||
| bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps, | bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps, | ||||
| const bool use_select, | const bool use_select, | ||||
| float r_min[3], | float r_min[3], | ||||
| float r_max[3]) | float r_max[3]) | ||||
| { | { | ||||
| const bGPDspoint *pt; | if (gps == nullptr) { | ||||
| int i; | |||||
| bool changed = false; | |||||
| if (ELEM(NULL, gps, r_min, r_max)) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | bool changed = false; | ||||
| if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) { | if (use_select) { | ||||
| minmax_v3v3_v3(r_min, r_max, &pt->x); | for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) { | ||||
| if (pt.flag & GP_SPOINT_SELECT) { | |||||
| minmax_v3v3_v3(r_min, r_max, &pt.x); | |||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| else { | |||||
| for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) { | |||||
| minmax_v3v3_v3(r_min, r_max, &pt.x); | |||||
| changed = true; | |||||
| } | |||||
| } | |||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** | /** | ||||
| * Get min/max bounds of all strokes in grease pencil data-block. | * Get min/max bounds of all strokes in grease pencil data-block. | ||||
| * \param gpd: Grease pencil datablock | * \param gpd: Grease pencil datablock | ||||
| * \param r_min: Result minimum coordinates | * \param r_min: Result minimum coordinates | ||||
| * \param r_max: Result maximum coordinates | * \param r_max: Result maximum coordinates | ||||
| * \return True if it was possible to calculate | * \return True if it was possible to calculate | ||||
| */ | */ | ||||
| bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3]) | bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3]) | ||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| INIT_MINMAX(r_min, r_max); | INIT_MINMAX(r_min, r_max); | ||||
| if (gpd == NULL) { | if (gpd == nullptr) { | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | ||||
| bGPDframe *gpf = gpl->actframe; | bGPDframe *gpf = gpl->actframe; | ||||
| if (gpf != NULL) { | if (gpf != nullptr) { | ||||
| LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { | LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { | ||||
| changed |= BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); | changed |= BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** | /** | ||||
| * Compute center of bounding box. | * Compute center of bounding box. | ||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param r_centroid: Location of the center | * \param r_centroid: Location of the center | ||||
| */ | */ | ||||
| void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) | void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) | ||||
| { | { | ||||
| float min[3], max[3], tot[3]; | float3 min; | ||||
| float3 max; | |||||
| BKE_gpencil_data_minmax(gpd, min, max); | BKE_gpencil_data_minmax(gpd, min, max); | ||||
| add_v3_v3v3(tot, min, max); | const float3 tot = min + max; | ||||
| mul_v3_v3fl(r_centroid, tot, 0.5f); | mul_v3_v3fl(r_centroid, tot, 0.5f); | ||||
| } | } | ||||
| /** | /** | ||||
| * Compute stroke bounding box. | * Compute stroke bounding box. | ||||
| * \param gps: Grease pencil Stroke | * \param gps: Grease pencil Stroke | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps) | void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps) | ||||
| { | { | ||||
| INIT_MINMAX(gps->boundbox_min, gps->boundbox_max); | INIT_MINMAX(gps->boundbox_min, gps->boundbox_max); | ||||
| BKE_gpencil_stroke_minmax(gps, false, gps->boundbox_min, gps->boundbox_max); | BKE_gpencil_stroke_minmax(gps, false, gps->boundbox_min, gps->boundbox_max); | ||||
| } | } | ||||
| /** | /** | ||||
| * Create bounding box values. | * Create bounding box values. | ||||
| * \param ob: Grease pencil object | * \param ob: Grease pencil object | ||||
| */ | */ | ||||
| static void boundbox_gpencil(Object *ob) | static void boundbox_gpencil(Object *ob) | ||||
| { | { | ||||
| BoundBox *bb; | if (ob->runtime.bb == nullptr) { | ||||
| bGPdata *gpd; | ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); | ||||
| float min[3], max[3]; | |||||
| if (ob->runtime.bb == NULL) { | |||||
| ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); | |||||
| } | } | ||||
| bb = ob->runtime.bb; | BoundBox *bb = ob->runtime.bb; | ||||
| gpd = ob->data; | bGPdata *gpd = (bGPdata *)ob->data; | ||||
| float3 min; | |||||
| float3 max; | |||||
| if (!BKE_gpencil_data_minmax(gpd, min, max)) { | if (!BKE_gpencil_data_minmax(gpd, min, max)) { | ||||
| min[0] = min[1] = min[2] = -1.0f; | min = float3(-1); | ||||
| max[0] = max[1] = max[2] = 1.0f; | max = float3(1); | ||||
| } | } | ||||
| BKE_boundbox_init_from_minmax(bb, min, max); | BKE_boundbox_init_from_minmax(bb, min, max); | ||||
| bb->flag &= ~BOUNDBOX_DIRTY; | bb->flag &= ~BOUNDBOX_DIRTY; | ||||
| } | } | ||||
| /** | /** | ||||
| * Get grease pencil object bounding box. | * Get grease pencil object bounding box. | ||||
| * \param ob: Grease pencil object | * \param ob: Grease pencil object | ||||
| * \return Bounding box | * \return Bounding box | ||||
| */ | */ | ||||
| BoundBox *BKE_gpencil_boundbox_get(Object *ob) | BoundBox *BKE_gpencil_boundbox_get(Object *ob) | ||||
| { | { | ||||
| if (ELEM(NULL, ob, ob->data)) { | if (ELEM(nullptr, ob, ob->data)) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bGPdata *gpd = (bGPdata *)ob->data; | bGPdata *gpd = (bGPdata *)ob->data; | ||||
| if ((ob->runtime.bb) && ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) { | if ((ob->runtime.bb) && ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) { | ||||
| return ob->runtime.bb; | return ob->runtime.bb; | ||||
| } | } | ||||
| boundbox_gpencil(ob); | boundbox_gpencil(ob); | ||||
| Object *ob_orig = (Object *)DEG_get_original_id(&ob->id); | Object *ob_orig = (Object *)DEG_get_original_id(&ob->id); | ||||
| /* Update orig object's boundbox with re-computed evaluated values. This function can be | /* Update orig object's boundbox with re-computed evaluated values. This function can be | ||||
| * called with the evaluated object and need update the original object bound box data | * called with the evaluated object and need update the original object bound box data | ||||
| * to keep both values synchronized. */ | * to keep both values synchronized. */ | ||||
| if (!ELEM(ob_orig, NULL, ob)) { | if (!ELEM(ob_orig, nullptr, ob)) { | ||||
| if (ob_orig->runtime.bb == NULL) { | if (ob_orig->runtime.bb == nullptr) { | ||||
| ob_orig->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); | ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); | ||||
| } | } | ||||
| for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
| copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]); | copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]); | ||||
| } | } | ||||
| } | } | ||||
| return ob->runtime.bb; | return ob->runtime.bb; | ||||
| } | } | ||||
| Show All 12 Lines | static int stroke_march_next_point(const bGPDstroke *gps, | ||||
| int *index_from, | int *index_from, | ||||
| int *index_to) | int *index_to) | ||||
| { | { | ||||
| float remaining_till_next = 0.0f; | float remaining_till_next = 0.0f; | ||||
| float remaining_march = dist; | float remaining_march = dist; | ||||
| float step_start[3]; | float step_start[3]; | ||||
| float point[3]; | float point[3]; | ||||
| int next_point_index = index_next_pt; | int next_point_index = index_next_pt; | ||||
| bGPDspoint *pt = NULL; | bGPDspoint *pt = nullptr; | ||||
| if (!(next_point_index < gps->totpoints)) { | if (!(next_point_index < gps->totpoints)) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| copy_v3_v3(step_start, current); | copy_v3_v3(step_start, current); | ||||
| pt = &gps->points[next_point_index]; | pt = &gps->points[next_point_index]; | ||||
| copy_v3_v3(point, &pt->x); | copy_v3_v3(point, &pt->x); | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | static int stroke_march_next_point_no_interp(const bGPDstroke *gps, | ||||
| const float dist, | const float dist, | ||||
| float *result) | float *result) | ||||
| { | { | ||||
| float remaining_till_next = 0.0f; | float remaining_till_next = 0.0f; | ||||
| float remaining_march = dist; | float remaining_march = dist; | ||||
| float step_start[3]; | float step_start[3]; | ||||
| float point[3]; | float point[3]; | ||||
| int next_point_index = index_next_pt; | int next_point_index = index_next_pt; | ||||
| bGPDspoint *pt = NULL; | bGPDspoint *pt = nullptr; | ||||
| if (!(next_point_index < gps->totpoints)) { | if (!(next_point_index < gps->totpoints)) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| copy_v3_v3(step_start, current); | copy_v3_v3(step_start, current); | ||||
| pt = &gps->points[next_point_index]; | pt = &gps->points[next_point_index]; | ||||
| copy_v3_v3(point, &pt->x); | copy_v3_v3(point, &pt->x); | ||||
| Show All 24 Lines | static int stroke_march_next_point_no_interp(const bGPDstroke *gps, | ||||
| return next_point_index; | return next_point_index; | ||||
| } | } | ||||
| static int stroke_march_count(const bGPDstroke *gps, const float dist) | static int stroke_march_count(const bGPDstroke *gps, const float dist) | ||||
| { | { | ||||
| int point_count = 0; | int point_count = 0; | ||||
| float point[3]; | float point[3]; | ||||
| int next_point_index = 1; | int next_point_index = 1; | ||||
| bGPDspoint *pt = NULL; | bGPDspoint *pt = nullptr; | ||||
| pt = &gps->points[0]; | pt = &gps->points[0]; | ||||
| copy_v3_v3(point, &pt->x); | copy_v3_v3(point, &pt->x); | ||||
| point_count++; | point_count++; | ||||
| while ((next_point_index = stroke_march_next_point_no_interp( | while ((next_point_index = stroke_march_next_point_no_interp( | ||||
| gps, next_point_index, point, dist, point)) > -1) { | gps, next_point_index, point, dist, point)) > -1) { | ||||
| point_count++; | point_count++; | ||||
| Show All 16 Lines | static void stroke_defvert_create_nr_list(MDeformVert *dv_list, | ||||
| int tw = 0; | int tw = 0; | ||||
| for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | ||||
| dv = &dv_list[i]; | dv = &dv_list[i]; | ||||
| /* find def_nr in list, if not exist, then create one */ | /* find def_nr in list, if not exist, then create one */ | ||||
| for (j = 0; j < dv->totweight; j++) { | for (j = 0; j < dv->totweight; j++) { | ||||
| bool found = false; | bool found = false; | ||||
| dw = &dv->dw[j]; | dw = &dv->dw[j]; | ||||
| for (ld = result->first; ld; ld = ld->next) { | for (ld = (LinkData *)result->first; ld; ld = ld->next) { | ||||
| if (ld->data == POINTER_FROM_INT(dw->def_nr)) { | if (ld->data == POINTER_FROM_INT(dw->def_nr)) { | ||||
| found = true; | found = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (!found) { | if (!found) { | ||||
| ld = MEM_callocN(sizeof(LinkData), "def_nr_item"); | ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item"); | ||||
| ld->data = POINTER_FROM_INT(dw->def_nr); | ld->data = POINTER_FROM_INT(dw->def_nr); | ||||
| BLI_addtail(result, ld); | BLI_addtail(result, ld); | ||||
| tw++; | tw++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| *totweight = tw; | *totweight = tw; | ||||
| } | } | ||||
| static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase *def_nr_list) | static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase *def_nr_list) | ||||
| { | { | ||||
| int i, j; | int i, j; | ||||
| LinkData *ld; | LinkData *ld; | ||||
| MDeformVert *dst = MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert"); | MDeformVert *dst = (MDeformVert *)MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert"); | ||||
| for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | ||||
| dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * totweight, "new_deformWeight"); | dst[i].dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * totweight, | ||||
| "new_deformWeight"); | |||||
| dst[i].totweight = totweight; | dst[i].totweight = totweight; | ||||
| j = 0; | j = 0; | ||||
| /* re-assign deform groups */ | /* re-assign deform groups */ | ||||
| for (ld = def_nr_list->first; ld; ld = ld->next) { | for (ld = (LinkData *)def_nr_list->first; ld; ld = ld->next) { | ||||
| dst[i].dw[j].def_nr = POINTER_AS_INT(ld->data); | dst[i].dw[j].def_nr = POINTER_AS_INT(ld->data); | ||||
| j++; | j++; | ||||
| } | } | ||||
| } | } | ||||
| return dst; | return dst; | ||||
| } | } | ||||
| Show All 14 Lines | |||||
| * Resample a stroke | * Resample a stroke | ||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param gps: Stroke to sample | * \param gps: Stroke to sample | ||||
| * \param dist: Distance of one segment | * \param dist: Distance of one segment | ||||
| */ | */ | ||||
| bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select) | bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points; | bGPDspoint *pt = gps->points; | ||||
| bGPDspoint *pt1 = NULL; | bGPDspoint *pt1 = nullptr; | ||||
| bGPDspoint *pt2 = NULL; | bGPDspoint *pt2 = nullptr; | ||||
| LinkData *ld; | LinkData *ld; | ||||
| ListBase def_nr_list = {0}; | ListBase def_nr_list = {nullptr}; | ||||
| if (gps->totpoints < 2 || dist < FLT_EPSILON) { | if (gps->totpoints < 2 || dist < FLT_EPSILON) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* TODO: Implement feature point preservation. */ | /* TODO: Implement feature point preservation. */ | ||||
| int count = stroke_march_count(gps, dist); | int count = stroke_march_count(gps, dist); | ||||
| bGPDspoint *new_pt = MEM_callocN(sizeof(bGPDspoint) * count, "gp_stroke_points_sampled"); | bGPDspoint *new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * count, | ||||
| MDeformVert *new_dv = NULL; | "gp_stroke_points_sampled"); | ||||
| MDeformVert *new_dv = nullptr; | |||||
| int result_totweight; | int result_totweight; | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight); | stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight); | ||||
| new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list); | new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list); | ||||
| } | } | ||||
| int next_point_index = 1; | int next_point_index = 1; | ||||
| int i = 0; | int i = 0; | ||||
| float pressure, strength, ratio_result; | float pressure, strength, ratio_result; | ||||
| float vert_color[4]; | float vert_color[4]; | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select) | ||||
| gps->points = new_pt; | gps->points = new_pt; | ||||
| /* Free original vertex list. */ | /* Free original vertex list. */ | ||||
| MEM_freeN(pt); | MEM_freeN(pt); | ||||
| if (new_dv) { | if (new_dv) { | ||||
| /* Free original weight data. */ | /* Free original weight data. */ | ||||
| BKE_gpencil_free_stroke_weights(gps); | BKE_gpencil_free_stroke_weights(gps); | ||||
| MEM_freeN(gps->dvert); | MEM_freeN(gps->dvert); | ||||
| while ((ld = BLI_pophead(&def_nr_list))) { | while ((ld = (LinkData *)BLI_pophead(&def_nr_list))) { | ||||
| MEM_freeN(ld); | MEM_freeN(ld); | ||||
| } | } | ||||
| gps->dvert = new_dv; | gps->dvert = new_dv; | ||||
| } | } | ||||
| gps->totpoints = i; | gps->totpoints = i; | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to) | ||||
| if (new_count >= gps->totpoints) { | if (new_count >= gps->totpoints) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (new_count == 1) { | if (new_count == 1) { | ||||
| BKE_gpencil_free_stroke_weights(gps); | BKE_gpencil_free_stroke_weights(gps); | ||||
| MEM_freeN(gps->points); | MEM_freeN(gps->points); | ||||
| gps->points = NULL; | gps->points = nullptr; | ||||
| gps->dvert = NULL; | gps->dvert = nullptr; | ||||
| gps->totpoints = 0; | gps->totpoints = 0; | ||||
| return false; | return false; | ||||
| } | } | ||||
| new_pt = MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed"); | new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed"); | ||||
| for (int i = 0; i < new_count; i++) { | for (int i = 0; i < new_count; i++) { | ||||
| memcpy(&new_pt[i], &pt[i + index_from], sizeof(bGPDspoint)); | memcpy(&new_pt[i], &pt[i + index_from], sizeof(bGPDspoint)); | ||||
| } | } | ||||
| if (gps->dvert) { | if (gps->dvert) { | ||||
| new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_trimmed"); | new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count, | ||||
| "gp_stroke_dverts_trimmed"); | |||||
| for (int i = 0; i < new_count; i++) { | for (int i = 0; i < new_count; i++) { | ||||
| dv = &gps->dvert[i + index_from]; | dv = &gps->dvert[i + index_from]; | ||||
| new_dv[i].flag = dv->flag; | new_dv[i].flag = dv->flag; | ||||
| new_dv[i].totweight = dv->totweight; | new_dv[i].totweight = dv->totweight; | ||||
| new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight, | new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, | ||||
| "gp_stroke_dverts_dw_trimmed"); | "gp_stroke_dverts_dw_trimmed"); | ||||
| for (int j = 0; j < dv->totweight; j++) { | for (int j = 0; j < dv->totweight; j++) { | ||||
| new_dv[i].dw[j].weight = dv->dw[j].weight; | new_dv[i].dw[j].weight = dv->dw[j].weight; | ||||
| new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; | new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; | ||||
| } | } | ||||
| BKE_defvert_clear(dv); | BKE_defvert_clear(dv); | ||||
| } | } | ||||
| MEM_freeN(gps->dvert); | MEM_freeN(gps->dvert); | ||||
| gps->dvert = new_dv; | gps->dvert = new_dv; | ||||
| Show All 39 Lines | bool BKE_gpencil_stroke_split(bGPdata *gpd, | ||||
| new_pt = new_gps->points; /* Allocated from above. */ | new_pt = new_gps->points; /* Allocated from above. */ | ||||
| for (int i = 0; i < new_count; i++) { | for (int i = 0; i < new_count; i++) { | ||||
| memcpy(&new_pt[i], &pt[i + before_index], sizeof(bGPDspoint)); | memcpy(&new_pt[i], &pt[i + before_index], sizeof(bGPDspoint)); | ||||
| } | } | ||||
| if (gps->dvert) { | if (gps->dvert) { | ||||
| new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, | new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count, | ||||
| "gp_stroke_dverts_remaining(MDeformVert)"); | "gp_stroke_dverts_remaining(MDeformVert)"); | ||||
| for (int i = 0; i < new_count; i++) { | for (int i = 0; i < new_count; i++) { | ||||
| dv = &gps->dvert[i + before_index]; | dv = &gps->dvert[i + before_index]; | ||||
| new_dv[i].flag = dv->flag; | new_dv[i].flag = dv->flag; | ||||
| new_dv[i].totweight = dv->totweight; | new_dv[i].totweight = dv->totweight; | ||||
| new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight, | new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, | ||||
| "gp_stroke_dverts_dw_remaining(MDeformWeight)"); | "gp_stroke_dverts_dw_remaining(MDeformWeight)"); | ||||
| for (int j = 0; j < dv->totweight; j++) { | for (int j = 0; j < dv->totweight; j++) { | ||||
| new_dv[i].dw[j].weight = dv->dw[j].weight; | new_dv[i].dw[j].weight = dv->dw[j].weight; | ||||
| new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; | new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; | ||||
| } | } | ||||
| BKE_defvert_clear(dv); | BKE_defvert_clear(dv); | ||||
| } | } | ||||
| new_gps->dvert = new_dv; | new_gps->dvert = new_dv; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 592 Lines • ▼ Show 20 Lines | |||||
| * \param gps: Grease pencil stroke | * \param gps: Grease pencil stroke | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) | void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) | ||||
| { | { | ||||
| BLI_assert(gps->totpoints >= 3); | BLI_assert(gps->totpoints >= 3); | ||||
| /* allocate memory for temporary areas */ | /* allocate memory for temporary areas */ | ||||
| gps->tot_triangles = gps->totpoints - 2; | gps->tot_triangles = gps->totpoints - 2; | ||||
| uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, | uint(*tmp_triangles)[3] = (uint(*)[3])MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, | ||||
| "GP Stroke temp triangulation"); | "GP Stroke temp triangulation"); | ||||
| float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, | float(*points2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*points2d) * gps->totpoints, | ||||
| "GP Stroke temp 2d points"); | "GP Stroke temp 2d points"); | ||||
| float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data"); | float(*uv)[2] = (float(*)[2])MEM_mallocN(sizeof(*uv) * gps->totpoints, | ||||
| "GP Stroke temp 2d uv data"); | |||||
| int direction = 0; | int direction = 0; | ||||
| /* convert to 2d and triangulate */ | /* convert to 2d and triangulate */ | ||||
| BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); | BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); | ||||
| BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles); | BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles); | ||||
| /* calc texture coordinates automatically */ | /* calc texture coordinates automatically */ | ||||
| float minv[2]; | float minv[2]; | ||||
| float maxv[2]; | float maxv[2]; | ||||
| /* first needs bounding box data */ | /* first needs bounding box data */ | ||||
| ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); | ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); | ||||
| ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); | ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); | ||||
| /* calc uv data */ | /* calc uv data */ | ||||
| gpencil_calc_stroke_fill_uv(points2d, gps, minv, maxv, uv); | gpencil_calc_stroke_fill_uv(points2d, gps, minv, maxv, uv); | ||||
| /* Save triangulation data. */ | /* Save triangulation data. */ | ||||
| if (gps->tot_triangles > 0) { | if (gps->tot_triangles > 0) { | ||||
| MEM_SAFE_FREE(gps->triangles); | MEM_SAFE_FREE(gps->triangles); | ||||
| gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, | gps->triangles = (bGPDtriangle *)MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, | ||||
| "GP Stroke triangulation"); | "GP Stroke triangulation"); | ||||
| for (int i = 0; i < gps->tot_triangles; i++) { | for (int i = 0; i < gps->tot_triangles; i++) { | ||||
| memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); | memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); | ||||
| } | } | ||||
| /* Copy UVs to bGPDspoint. */ | /* Copy UVs to bGPDspoint. */ | ||||
| for (int i = 0; i < gps->totpoints; i++) { | for (int i = 0; i < gps->totpoints; i++) { | ||||
| copy_v2_v2(gps->points[i].uv_fill, uv[i]); | copy_v2_v2(gps->points[i].uv_fill, uv[i]); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* No triangles needed - Free anything allocated previously */ | /* No triangles needed - Free anything allocated previously */ | ||||
| if (gps->triangles) { | if (gps->triangles) { | ||||
| MEM_freeN(gps->triangles); | MEM_freeN(gps->triangles); | ||||
| } | } | ||||
| gps->triangles = NULL; | gps->triangles = nullptr; | ||||
| } | } | ||||
| /* clear memory */ | /* clear memory */ | ||||
| MEM_SAFE_FREE(tmp_triangles); | MEM_SAFE_FREE(tmp_triangles); | ||||
| MEM_SAFE_FREE(points2d); | MEM_SAFE_FREE(points2d); | ||||
| MEM_SAFE_FREE(uv); | MEM_SAFE_FREE(uv); | ||||
| } | } | ||||
| /** | /** | ||||
| * Update Stroke UV data. | * Update Stroke UV data. | ||||
| * \param gps: Grease pencil stroke | * \param gps: Grease pencil stroke | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) | void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) | ||||
| { | { | ||||
| if (gps == NULL || gps->totpoints == 0) { | if (gps == nullptr || gps->totpoints == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| bGPDspoint *pt = gps->points; | bGPDspoint *pt = gps->points; | ||||
| float totlen = 0.0f; | float totlen = 0.0f; | ||||
| pt[0].uv_fac = totlen; | pt[0].uv_fac = totlen; | ||||
| for (int i = 1; i < gps->totpoints; i++) { | for (int i = 1; i < gps->totpoints; i++) { | ||||
| totlen += len_v3v3(&pt[i - 1].x, &pt[i].x); | totlen += len_v3v3(&pt[i - 1].x, &pt[i].x); | ||||
| pt[i].uv_fac = totlen; | pt[i].uv_fac = totlen; | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Recalc all internal geometry data for the stroke | * Recalc all internal geometry data for the stroke | ||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param gps: Grease pencil stroke | * \param gps: Grease pencil stroke | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps) | void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps) | ||||
| { | { | ||||
| if (gps == NULL) { | if (gps == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (gps->editcurve != NULL) { | if (gps->editcurve != nullptr) { | ||||
| if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) { | if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) { | ||||
| /* curve geometry was updated: stroke needs recalculation */ | /* curve geometry was updated: stroke needs recalculation */ | ||||
| if (gps->flag & GP_STROKE_NEEDS_CURVE_UPDATE) { | if (gps->flag & GP_STROKE_NEEDS_CURVE_UPDATE) { | ||||
| bool is_adaptive = gpd->flag & GP_DATA_CURVE_ADAPTIVE_RESOLUTION; | bool is_adaptive = gpd->flag & GP_DATA_CURVE_ADAPTIVE_RESOLUTION; | ||||
| BKE_gpencil_stroke_update_geometry_from_editcurve( | BKE_gpencil_stroke_update_geometry_from_editcurve( | ||||
| gps, gpd->curve_edit_resolution, is_adaptive); | gps, gpd->curve_edit_resolution, is_adaptive); | ||||
| gps->flag &= ~GP_STROKE_NEEDS_CURVE_UPDATE; | gps->flag &= ~GP_STROKE_NEEDS_CURVE_UPDATE; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | if (intersect) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* trim unwanted points */ | /* trim unwanted points */ | ||||
| if (intersect) { | if (intersect) { | ||||
| /* save points */ | /* save points */ | ||||
| bGPDspoint *old_points = MEM_dupallocN(gps->points); | bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points); | ||||
| MDeformVert *old_dvert = NULL; | MDeformVert *old_dvert = nullptr; | ||||
| MDeformVert *dvert_src = NULL; | MDeformVert *dvert_src = nullptr; | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| old_dvert = MEM_dupallocN(gps->dvert); | old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert); | ||||
| } | } | ||||
| /* resize gps */ | /* resize gps */ | ||||
| int newtot = end - start + 1; | int newtot = end - start + 1; | ||||
| gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); | gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); | gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); | ||||
| } | } | ||||
| for (int i = 0; i < newtot; i++) { | for (int i = 0; i < newtot; i++) { | ||||
| int idx = start + i; | int idx = start + i; | ||||
| bGPDspoint *pt_src = &old_points[idx]; | bGPDspoint *pt_src = &old_points[idx]; | ||||
| bGPDspoint *pt_new = &gps->points[i]; | bGPDspoint *pt_new = &gps->points[i]; | ||||
| memcpy(pt_new, pt_src, sizeof(bGPDspoint)); | memcpy(pt_new, pt_src, sizeof(bGPDspoint)); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert_src = &old_dvert[idx]; | dvert_src = &old_dvert[idx]; | ||||
| MDeformVert *dvert = &gps->dvert[i]; | MDeformVert *dvert = &gps->dvert[i]; | ||||
| memcpy(dvert, dvert_src, sizeof(MDeformVert)); | memcpy(dvert, dvert_src, sizeof(MDeformVert)); | ||||
| if (dvert_src->dw) { | if (dvert_src->dw) { | ||||
| memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); | memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); | ||||
| } | } | ||||
| } | } | ||||
| if (ELEM(idx, start, end)) { | if (ELEM(idx, start, end)) { | ||||
| Show All 13 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * Close grease pencil stroke. | * Close grease pencil stroke. | ||||
| * \param gps: Stroke to close | * \param gps: Stroke to close | ||||
| */ | */ | ||||
| bool BKE_gpencil_stroke_close(bGPDstroke *gps) | bool BKE_gpencil_stroke_close(bGPDstroke *gps) | ||||
| { | { | ||||
| bGPDspoint *pt1 = NULL; | bGPDspoint *pt1 = nullptr; | ||||
| bGPDspoint *pt2 = NULL; | bGPDspoint *pt2 = nullptr; | ||||
| /* Only can close a stroke with 3 points or more. */ | /* Only can close a stroke with 3 points or more. */ | ||||
| if (gps->totpoints < 3) { | if (gps->totpoints < 3) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Calc average distance between points to get same level of sampling. */ | /* Calc average distance between points to get same level of sampling. */ | ||||
| float dist_tot = 0.0f; | float dist_tot = 0.0f; | ||||
| Show All 17 Lines | bool BKE_gpencil_stroke_close(bGPDstroke *gps) | ||||
| } | } | ||||
| /* Calc number of points required using the average distance. */ | /* Calc number of points required using the average distance. */ | ||||
| int tot_newpoints = MAX2(dist_close / dist_avg, 1); | int tot_newpoints = MAX2(dist_close / dist_avg, 1); | ||||
| /* Resize stroke array. */ | /* Resize stroke array. */ | ||||
| int old_tot = gps->totpoints; | int old_tot = gps->totpoints; | ||||
| gps->totpoints += tot_newpoints; | gps->totpoints += tot_newpoints; | ||||
| gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); | gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); | gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); | ||||
| } | } | ||||
| /* Generate new points */ | /* Generate new points */ | ||||
| pt1 = &gps->points[old_tot - 1]; | pt1 = &gps->points[old_tot - 1]; | ||||
| pt2 = &gps->points[0]; | pt2 = &gps->points[0]; | ||||
| bGPDspoint *pt = &gps->points[old_tot]; | bGPDspoint *pt = &gps->points[old_tot]; | ||||
| for (int i = 1; i < tot_newpoints + 1; i++, pt++) { | for (int i = 1; i < tot_newpoints + 1; i++, pt++) { | ||||
| float step = (tot_newpoints > 1) ? ((float)i / (float)tot_newpoints) : 0.99f; | float step = (tot_newpoints > 1) ? ((float)i / (float)tot_newpoints) : 0.99f; | ||||
| /* Clamp last point to be near, but not on top of first point. */ | /* Clamp last point to be near, but not on top of first point. */ | ||||
| if ((tot_newpoints > 1) && (i == tot_newpoints)) { | if ((tot_newpoints > 1) && (i == tot_newpoints)) { | ||||
| step *= 0.99f; | step *= 0.99f; | ||||
| } | } | ||||
| /* Average point. */ | /* Average point. */ | ||||
| interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step); | interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step); | ||||
| pt->pressure = interpf(pt2->pressure, pt1->pressure, step); | pt->pressure = interpf(pt2->pressure, pt1->pressure, step); | ||||
| pt->strength = interpf(pt2->strength, pt1->strength, step); | pt->strength = interpf(pt2->strength, pt1->strength, step); | ||||
| pt->flag = 0; | pt->flag = 0; | ||||
| interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step); | interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step); | ||||
| /* Set weights. */ | /* Set weights. */ | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| MDeformVert *dvert1 = &gps->dvert[old_tot - 1]; | MDeformVert *dvert1 = &gps->dvert[old_tot - 1]; | ||||
| MDeformWeight *dw1 = BKE_defvert_ensure_index(dvert1, 0); | MDeformWeight *dw1 = BKE_defvert_ensure_index(dvert1, 0); | ||||
| float weight_1 = dw1 ? dw1->weight : 0.0f; | float weight_1 = dw1 ? dw1->weight : 0.0f; | ||||
| MDeformVert *dvert2 = &gps->dvert[0]; | MDeformVert *dvert2 = &gps->dvert[0]; | ||||
| MDeformWeight *dw2 = BKE_defvert_ensure_index(dvert2, 0); | MDeformWeight *dw2 = BKE_defvert_ensure_index(dvert2, 0); | ||||
| float weight_2 = dw2 ? dw2->weight : 0.0f; | float weight_2 = dw2 ? dw2->weight : 0.0f; | ||||
| Show All 17 Lines | |||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param gpf: Grease pencil frame | * \param gpf: Grease pencil frame | ||||
| * \param gps: Grease pencil stroke | * \param gps: Grease pencil stroke | ||||
| * \param tag: Type of tag for point | * \param tag: Type of tag for point | ||||
| */ | */ | ||||
| void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag) | void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag) | ||||
| { | { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| MDeformVert *dvert = NULL; | MDeformVert *dvert = nullptr; | ||||
| int i; | int i; | ||||
| int tot = gps->totpoints; /* number of points in new buffer */ | int tot = gps->totpoints; /* number of points in new buffer */ | ||||
| /* first pass: count points to remove */ | /* first pass: count points to remove */ | ||||
| /* Count how many points are selected (i.e. how many to remove) */ | /* Count how many points are selected (i.e. how many to remove) */ | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| if (pt->flag & tag) { | if (pt->flag & tag) { | ||||
| /* selected point - one of the points to remove */ | /* selected point - one of the points to remove */ | ||||
| Show All 13 Lines | if (tot <= 0) { | ||||
| } | } | ||||
| if (gps->triangles) { | if (gps->triangles) { | ||||
| MEM_freeN(gps->triangles); | MEM_freeN(gps->triangles); | ||||
| } | } | ||||
| BLI_freelinkN(&gpf->strokes, gps); | BLI_freelinkN(&gpf->strokes, gps); | ||||
| } | } | ||||
| else { | else { | ||||
| /* just copy all points to keep into a smaller buffer */ | /* just copy all points to keep into a smaller buffer */ | ||||
| bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy"); | bGPDspoint *new_points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * tot, | ||||
| "new gp stroke points copy"); | |||||
| bGPDspoint *npt = new_points; | bGPDspoint *npt = new_points; | ||||
| MDeformVert *new_dvert = NULL; | MDeformVert *new_dvert = nullptr; | ||||
| MDeformVert *ndvert = NULL; | MDeformVert *ndvert = nullptr; | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy"); | new_dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * tot, | ||||
| "new gp stroke weights copy"); | |||||
| ndvert = new_dvert; | ndvert = new_dvert; | ||||
| } | } | ||||
| (gps->dvert != NULL) ? dvert = gps->dvert : NULL; | (gps->dvert != nullptr) ? dvert = gps->dvert : nullptr; | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| if ((pt->flag & tag) == 0) { | if ((pt->flag & tag) == 0) { | ||||
| *npt = *pt; | *npt = *pt; | ||||
| npt++; | npt++; | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| *ndvert = *dvert; | *ndvert = *dvert; | ||||
| ndvert->dw = MEM_dupallocN(dvert->dw); | ndvert->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw); | ||||
| ndvert++; | ndvert++; | ||||
| } | } | ||||
| } | } | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert++; | dvert++; | ||||
| } | } | ||||
| } | } | ||||
| /* free the old buffer */ | /* free the old buffer */ | ||||
| if (gps->points) { | if (gps->points) { | ||||
| MEM_freeN(gps->points); | MEM_freeN(gps->points); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
| * Ramer - Douglas - Peucker algorithm | * Ramer - Douglas - Peucker algorithm | ||||
| * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm | * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm | ||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param gps: Grease pencil stroke | * \param gps: Grease pencil stroke | ||||
| * \param epsilon: Epsilon value to define precision of the algorithm | * \param epsilon: Epsilon value to define precision of the algorithm | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon) | void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon) | ||||
| { | { | ||||
| bGPDspoint *old_points = MEM_dupallocN(gps->points); | bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points); | ||||
| int totpoints = gps->totpoints; | int totpoints = gps->totpoints; | ||||
| char *marked = NULL; | char *marked = nullptr; | ||||
| char work; | char work; | ||||
| int start = 0; | int start = 0; | ||||
| int end = gps->totpoints - 1; | int end = gps->totpoints - 1; | ||||
| marked = MEM_callocN(totpoints, "GP marked array"); | marked = (char *)MEM_callocN(totpoints, "GP marked array"); | ||||
| marked[start] = 1; | marked[start] = 1; | ||||
| marked[end] = 1; | marked[end] = 1; | ||||
| work = 1; | work = 1; | ||||
| int totmarked = 0; | int totmarked = 0; | ||||
| /* while still reducing */ | /* while still reducing */ | ||||
| while (work) { | while (work) { | ||||
| int ls, le; | int ls, le; | ||||
| Show All 35 Lines | while (ls < end) { | ||||
| } | } | ||||
| ls = le; | ls = le; | ||||
| le = ls + 1; | le = ls + 1; | ||||
| } | } | ||||
| } | } | ||||
| /* adding points marked */ | /* adding points marked */ | ||||
| MDeformVert *old_dvert = NULL; | MDeformVert *old_dvert = nullptr; | ||||
| MDeformVert *dvert_src = NULL; | MDeformVert *dvert_src = nullptr; | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| old_dvert = MEM_dupallocN(gps->dvert); | old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert); | ||||
| } | } | ||||
| /* resize gps */ | /* resize gps */ | ||||
| int j = 0; | int j = 0; | ||||
| for (int i = 0; i < totpoints; i++) { | for (int i = 0; i < totpoints; i++) { | ||||
| bGPDspoint *pt_src = &old_points[i]; | bGPDspoint *pt_src = &old_points[i]; | ||||
| bGPDspoint *pt = &gps->points[j]; | bGPDspoint *pt = &gps->points[j]; | ||||
| if ((marked[i]) || (i == 0) || (i == totpoints - 1)) { | if ((marked[i]) || (i == 0) || (i == totpoints - 1)) { | ||||
| memcpy(pt, pt_src, sizeof(bGPDspoint)); | memcpy(pt, pt_src, sizeof(bGPDspoint)); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert_src = &old_dvert[i]; | dvert_src = &old_dvert[i]; | ||||
| MDeformVert *dvert = &gps->dvert[j]; | MDeformVert *dvert = &gps->dvert[j]; | ||||
| memcpy(dvert, dvert_src, sizeof(MDeformVert)); | memcpy(dvert, dvert_src, sizeof(MDeformVert)); | ||||
| if (dvert_src->dw) { | if (dvert_src->dw) { | ||||
| memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); | memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); | ||||
| } | } | ||||
| } | } | ||||
| j++; | j++; | ||||
| } | } | ||||
| else { | else { | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert_src = &old_dvert[i]; | dvert_src = &old_dvert[i]; | ||||
| BKE_gpencil_free_point_weights(dvert_src); | BKE_gpencil_free_point_weights(dvert_src); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| gps->totpoints = j; | gps->totpoints = j; | ||||
| Show All 12 Lines | |||||
| */ | */ | ||||
| void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) | void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) | ||||
| { | { | ||||
| if (gps->totpoints < 5) { | if (gps->totpoints < 5) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* save points */ | /* save points */ | ||||
| bGPDspoint *old_points = MEM_dupallocN(gps->points); | bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points); | ||||
| MDeformVert *old_dvert = NULL; | MDeformVert *old_dvert = nullptr; | ||||
| MDeformVert *dvert_src = NULL; | MDeformVert *dvert_src = nullptr; | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| old_dvert = MEM_dupallocN(gps->dvert); | old_dvert = (MDeformVert *)MEM_dupallocN(gps->dvert); | ||||
| } | } | ||||
| /* resize gps */ | /* resize gps */ | ||||
| int newtot = (gps->totpoints - 2) / 2; | int newtot = (gps->totpoints - 2) / 2; | ||||
| if (((gps->totpoints - 2) % 2) > 0) { | if (((gps->totpoints - 2) % 2) > 0) { | ||||
| newtot++; | newtot++; | ||||
| } | } | ||||
| newtot += 2; | newtot += 2; | ||||
| gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); | gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); | gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); | ||||
| } | } | ||||
| int j = 0; | int j = 0; | ||||
| for (int i = 0; i < gps->totpoints; i++) { | for (int i = 0; i < gps->totpoints; i++) { | ||||
| bGPDspoint *pt_src = &old_points[i]; | bGPDspoint *pt_src = &old_points[i]; | ||||
| bGPDspoint *pt = &gps->points[j]; | bGPDspoint *pt = &gps->points[j]; | ||||
| if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) { | if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) { | ||||
| memcpy(pt, pt_src, sizeof(bGPDspoint)); | memcpy(pt, pt_src, sizeof(bGPDspoint)); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert_src = &old_dvert[i]; | dvert_src = &old_dvert[i]; | ||||
| MDeformVert *dvert = &gps->dvert[j]; | MDeformVert *dvert = &gps->dvert[j]; | ||||
| memcpy(dvert, dvert_src, sizeof(MDeformVert)); | memcpy(dvert, dvert_src, sizeof(MDeformVert)); | ||||
| if (dvert_src->dw) { | if (dvert_src->dw) { | ||||
| memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); | memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); | ||||
| } | } | ||||
| } | } | ||||
| j++; | j++; | ||||
| } | } | ||||
| else { | else { | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert_src = &old_dvert[i]; | dvert_src = &old_dvert[i]; | ||||
| BKE_gpencil_free_point_weights(dvert_src); | BKE_gpencil_free_point_weights(dvert_src); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| gps->totpoints = j; | gps->totpoints = j; | ||||
| /* Calc geometry data. */ | /* Calc geometry data. */ | ||||
| BKE_gpencil_stroke_geometry_update(gpd, gps); | BKE_gpencil_stroke_geometry_update(gpd, gps); | ||||
| MEM_SAFE_FREE(old_points); | MEM_SAFE_FREE(old_points); | ||||
| MEM_SAFE_FREE(old_dvert); | MEM_SAFE_FREE(old_dvert); | ||||
| } | } | ||||
| /** | /** | ||||
| * Subdivide a stroke | * Subdivide a stroke | ||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param gps: Stroke | * \param gps: Stroke | ||||
| * \param level: Level of subdivision | * \param level: Level of subdivision | ||||
| * \param type: Type of subdivision | * \param type: Type of subdivision | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type) | void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type) | ||||
| { | { | ||||
| bGPDspoint *temp_points; | bGPDspoint *temp_points; | ||||
| MDeformVert *temp_dverts = NULL; | MDeformVert *temp_dverts = nullptr; | ||||
| MDeformVert *dvert = NULL; | MDeformVert *dvert = nullptr; | ||||
| MDeformVert *dvert_final = NULL; | MDeformVert *dvert_final = nullptr; | ||||
| MDeformVert *dvert_next = NULL; | MDeformVert *dvert_next = nullptr; | ||||
| int totnewpoints, oldtotpoints; | int totnewpoints, oldtotpoints; | ||||
| int i2; | int i2; | ||||
| for (int s = 0; s < level; s++) { | for (int s = 0; s < level; s++) { | ||||
| totnewpoints = gps->totpoints - 1; | totnewpoints = gps->totpoints - 1; | ||||
| /* duplicate points in a temp area */ | /* duplicate points in a temp area */ | ||||
| temp_points = MEM_dupallocN(gps->points); | temp_points = (bGPDspoint *)MEM_dupallocN(gps->points); | ||||
| oldtotpoints = gps->totpoints; | oldtotpoints = gps->totpoints; | ||||
| /* resize the points arrays */ | /* resize the points arrays */ | ||||
| gps->totpoints += totnewpoints; | gps->totpoints += totnewpoints; | ||||
| gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); | gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| temp_dverts = MEM_dupallocN(gps->dvert); | temp_dverts = (MDeformVert *)MEM_dupallocN(gps->dvert); | ||||
| gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); | gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); | ||||
| } | } | ||||
| /* move points from last to first to new place */ | /* move points from last to first to new place */ | ||||
| i2 = gps->totpoints - 1; | i2 = gps->totpoints - 1; | ||||
| for (int i = oldtotpoints - 1; i > 0; i--) { | for (int i = oldtotpoints - 1; i > 0; i--) { | ||||
| bGPDspoint *pt = &temp_points[i]; | bGPDspoint *pt = &temp_points[i]; | ||||
| bGPDspoint *pt_final = &gps->points[i2]; | bGPDspoint *pt_final = &gps->points[i2]; | ||||
| copy_v3_v3(&pt_final->x, &pt->x); | copy_v3_v3(&pt_final->x, &pt->x); | ||||
| pt_final->pressure = pt->pressure; | pt_final->pressure = pt->pressure; | ||||
| pt_final->strength = pt->strength; | pt_final->strength = pt->strength; | ||||
| pt_final->time = pt->time; | pt_final->time = pt->time; | ||||
| pt_final->flag = pt->flag; | pt_final->flag = pt->flag; | ||||
| pt_final->runtime.pt_orig = pt->runtime.pt_orig; | pt_final->runtime.pt_orig = pt->runtime.pt_orig; | ||||
| pt_final->runtime.idx_orig = pt->runtime.idx_orig; | pt_final->runtime.idx_orig = pt->runtime.idx_orig; | ||||
| copy_v4_v4(pt_final->vert_color, pt->vert_color); | copy_v4_v4(pt_final->vert_color, pt->vert_color); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert = &temp_dverts[i]; | dvert = &temp_dverts[i]; | ||||
| dvert_final = &gps->dvert[i2]; | dvert_final = &gps->dvert[i2]; | ||||
| dvert_final->totweight = dvert->totweight; | dvert_final->totweight = dvert->totweight; | ||||
| dvert_final->dw = dvert->dw; | dvert_final->dw = dvert->dw; | ||||
| } | } | ||||
| i2 -= 2; | i2 -= 2; | ||||
| } | } | ||||
| /* interpolate mid points */ | /* interpolate mid points */ | ||||
| i2 = 1; | i2 = 1; | ||||
| for (int i = 0; i < oldtotpoints - 1; i++) { | for (int i = 0; i < oldtotpoints - 1; i++) { | ||||
| bGPDspoint *pt = &temp_points[i]; | bGPDspoint *pt = &temp_points[i]; | ||||
| bGPDspoint *next = &temp_points[i + 1]; | bGPDspoint *next = &temp_points[i + 1]; | ||||
| bGPDspoint *pt_final = &gps->points[i2]; | bGPDspoint *pt_final = &gps->points[i2]; | ||||
| /* add a half way point */ | /* add a half way point */ | ||||
| interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); | interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); | ||||
| pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f); | pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f); | ||||
| pt_final->strength = interpf(pt->strength, next->strength, 0.5f); | pt_final->strength = interpf(pt->strength, next->strength, 0.5f); | ||||
| CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); | CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); | ||||
| pt_final->time = interpf(pt->time, next->time, 0.5f); | pt_final->time = interpf(pt->time, next->time, 0.5f); | ||||
| pt_final->runtime.pt_orig = NULL; | pt_final->runtime.pt_orig = nullptr; | ||||
| pt_final->flag = 0; | pt_final->flag = 0; | ||||
| interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); | interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| dvert = &temp_dverts[i]; | dvert = &temp_dverts[i]; | ||||
| dvert_next = &temp_dverts[i + 1]; | dvert_next = &temp_dverts[i + 1]; | ||||
| dvert_final = &gps->dvert[i2]; | dvert_final = &gps->dvert[i2]; | ||||
| dvert_final->totweight = dvert->totweight; | dvert_final->totweight = dvert->totweight; | ||||
| dvert_final->dw = MEM_dupallocN(dvert->dw); | dvert_final->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw); | ||||
| /* interpolate weight values */ | /* interpolate weight values */ | ||||
| for (int d = 0; d < dvert->totweight; d++) { | for (int d = 0; d < dvert->totweight; d++) { | ||||
| MDeformWeight *dw_a = &dvert->dw[d]; | MDeformWeight *dw_a = &dvert->dw[d]; | ||||
| if (dvert_next->totweight > d) { | if (dvert_next->totweight > d) { | ||||
| MDeformWeight *dw_b = &dvert_next->dw[d]; | MDeformWeight *dw_b = &dvert_next->dw[d]; | ||||
| MDeformWeight *dw_final = &dvert_final->dw[d]; | MDeformWeight *dw_final = &dvert_final->dw[d]; | ||||
| dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f); | dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| i2 += 2; | i2 += 2; | ||||
| } | } | ||||
| MEM_SAFE_FREE(temp_points); | MEM_SAFE_FREE(temp_points); | ||||
| MEM_SAFE_FREE(temp_dverts); | MEM_SAFE_FREE(temp_dverts); | ||||
| /* Move points to smooth stroke (not simple type). */ | /* Move points to smooth stroke (not simple type). */ | ||||
| if (type != GP_SUBDIV_SIMPLE) { | if (type != GP_SUBDIV_SIMPLE) { | ||||
| /* duplicate points in a temp area with the new subdivide data */ | /* duplicate points in a temp area with the new subdivide data */ | ||||
| temp_points = MEM_dupallocN(gps->points); | temp_points = (bGPDspoint *)MEM_dupallocN(gps->points); | ||||
| /* extreme points are not changed */ | /* extreme points are not changed */ | ||||
| for (int i = 0; i < gps->totpoints - 2; i++) { | for (int i = 0; i < gps->totpoints - 2; i++) { | ||||
| bGPDspoint *pt = &temp_points[i]; | bGPDspoint *pt = &temp_points[i]; | ||||
| bGPDspoint *next = &temp_points[i + 1]; | bGPDspoint *next = &temp_points[i + 1]; | ||||
| bGPDspoint *pt_final = &gps->points[i + 1]; | bGPDspoint *pt_final = &gps->points[i + 1]; | ||||
| /* move point */ | /* move point */ | ||||
| interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); | interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); | ||||
| } | } | ||||
| /* free temp memory */ | /* free temp memory */ | ||||
| MEM_SAFE_FREE(temp_points); | MEM_SAFE_FREE(temp_points); | ||||
| } | } | ||||
| } | } | ||||
| /* Calc geometry data. */ | /* Calc geometry data. */ | ||||
| BKE_gpencil_stroke_geometry_update(gpd, gps); | BKE_gpencil_stroke_geometry_update(gpd, gps); | ||||
| } | } | ||||
| /* Merge by distance ------------------------------------- */ | /* Merge by distance ------------------------------------- */ | ||||
| /** | /** | ||||
| * Reduce a series of points when the distance is below a threshold. | * Reduce a series of points when the distance is below a threshold. | ||||
| * Special case for first and last points (both are keeped) for other points, | * Special case for first and last points (both are kept) for other points, | ||||
| * the merge point always is at first point. | * the merge point always is at first point. | ||||
| * \param gpd: Grease pencil data-block | * | ||||
| * \param gpf: Grease Pencil frame | * \param gpd: Grease pencil data-block. | ||||
| * \param gps: Grease Pencil stroke | * \param gpf: Grease Pencil frame. | ||||
| * \param threshold: Distance between points | * \param gps: Grease Pencil stroke. | ||||
| * \param use_unselected: Set to true to analyze all stroke and not only selected points | * \param threshold: Distance between points. | ||||
| * \param use_unselected: Set to true to analyze all stroke and not only selected points. | |||||
| */ | */ | ||||
| void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, | void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, | ||||
| bGPDframe *gpf, | bGPDframe *gpf, | ||||
| bGPDstroke *gps, | bGPDstroke *gps, | ||||
| const float threshold, | const float threshold, | ||||
| const bool use_unselected) | const bool use_unselected) | ||||
| { | { | ||||
| bGPDspoint *pt = NULL; | bGPDspoint *pt = nullptr; | ||||
| bGPDspoint *pt_next = NULL; | bGPDspoint *pt_next = nullptr; | ||||
| float tagged = false; | float tagged = false; | ||||
| /* Use square distance to speed up loop */ | /* Use square distance to speed up loop */ | ||||
| const float th_square = threshold * threshold; | const float th_square = threshold * threshold; | ||||
| /* Need to have something to merge. */ | /* Need to have something to merge. */ | ||||
| if (gps->totpoints < 2) { | if (gps->totpoints < 2) { | ||||
| return; | return; | ||||
| } | } | ||||
| int i = 0; | int i = 0; | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, | ||||
| if (tagged) { | if (tagged) { | ||||
| BKE_gpencil_dissolve_points(gpd, gpf, gps, GP_SPOINT_TAG); | BKE_gpencil_dissolve_points(gpd, gpf, gps, GP_SPOINT_TAG); | ||||
| } | } | ||||
| /* Calc geometry data. */ | /* Calc geometry data. */ | ||||
| BKE_gpencil_stroke_geometry_update(gpd, gps); | BKE_gpencil_stroke_geometry_update(gpd, gps); | ||||
| } | } | ||||
| typedef struct GpEdge { | struct GpEdge { | ||||
| uint v1, v2; | uint v1, v2; | ||||
| /* Coordinates. */ | /* Coordinates. */ | ||||
| float v1_co[3], v2_co[3]; | float v1_co[3], v2_co[3]; | ||||
| /* Normals. */ | /* Normals. */ | ||||
| float n1[3], n2[3]; | float n1[3], n2[3]; | ||||
| /* Direction of the segment. */ | /* Direction of the segment. */ | ||||
| float vec[3]; | float vec[3]; | ||||
| int flag; | int flag; | ||||
| } GpEdge; | }; | ||||
| static int gpencil_next_edge( | static int gpencil_next_edge( | ||||
| GpEdge *gp_edges, int totedges, GpEdge *gped_init, const float threshold, const bool reverse) | GpEdge *gp_edges, int totedges, GpEdge *gped_init, const float threshold, const bool reverse) | ||||
| { | { | ||||
| int edge = -1; | int edge = -1; | ||||
| float last_angle = 999999.0f; | float last_angle = 999999.0f; | ||||
| for (int i = 0; i < totedges; i++) { | for (int i = 0; i < totedges; i++) { | ||||
| GpEdge *gped = &gp_edges[i]; | GpEdge *gped = &gp_edges[i]; | ||||
| ▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | static void gpencil_generate_edgeloops(Object *ob, | ||||
| const bool use_seams) | const bool use_seams) | ||||
| { | { | ||||
| Mesh *me = (Mesh *)ob->data; | Mesh *me = (Mesh *)ob->data; | ||||
| if (me->totedge == 0) { | if (me->totedge == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Arrays for all edge vertices (forward and backward) that form a edge loop. | /* Arrays for all edge vertices (forward and backward) that form a edge loop. | ||||
| * This is reused for each edgeloop to create gpencil stroke. */ | * This is reused for each edge-loop to create gpencil stroke. */ | ||||
| uint *stroke = MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); | uint *stroke = (uint *)MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); | ||||
| uint *stroke_fw = MEM_callocN(sizeof(uint) * me->totedge, __func__); | uint *stroke_fw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); | ||||
| uint *stroke_bw = MEM_callocN(sizeof(uint) * me->totedge, __func__); | uint *stroke_bw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); | ||||
| /* Create array with all edges. */ | /* Create array with all edges. */ | ||||
| GpEdge *gp_edges = MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); | GpEdge *gp_edges = (GpEdge *)MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); | ||||
| GpEdge *gped = NULL; | GpEdge *gped = nullptr; | ||||
| for (int i = 0; i < me->totedge; i++) { | for (int i = 0; i < me->totedge; i++) { | ||||
| MEdge *ed = &me->medge[i]; | MEdge *ed = &me->medge[i]; | ||||
| gped = &gp_edges[i]; | gped = &gp_edges[i]; | ||||
| MVert *mv1 = &me->mvert[ed->v1]; | MVert *mv1 = &me->mvert[ed->v1]; | ||||
| normal_short_to_float_v3(gped->n1, mv1->no); | normal_short_to_float_v3(gped->n1, mv1->no); | ||||
| gped->v1 = ed->v1; | gped->v1 = ed->v1; | ||||
| copy_v3_v3(gped->v1_co, mv1->co); | copy_v3_v3(gped->v1_co, mv1->co); | ||||
| Show All 36 Lines | while (pending) { | ||||
| /* Hash used to avoid loop over same vertice. */ | /* Hash used to avoid loop over same vertice. */ | ||||
| GHash *v_table = BLI_ghash_int_new(__func__); | GHash *v_table = BLI_ghash_int_new(__func__); | ||||
| /* Look forward edges. */ | /* Look forward edges. */ | ||||
| int totedges = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_fw, e, angle, false); | int totedges = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_fw, e, angle, false); | ||||
| /* Look backward edges. */ | /* Look backward edges. */ | ||||
| int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, angle, true); | int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, angle, true); | ||||
| BLI_ghash_free(v_table, NULL, NULL); | BLI_ghash_free(v_table, nullptr, nullptr); | ||||
| /* Join both arrays. */ | /* Join both arrays. */ | ||||
| int array_len = 0; | int array_len = 0; | ||||
| for (int i = totbw - 1; i > 0; i--) { | for (int i = totbw - 1; i > 0; i--) { | ||||
| stroke[array_len] = stroke_bw[i]; | stroke[array_len] = stroke_bw[i]; | ||||
| array_len++; | array_len++; | ||||
| } | } | ||||
| for (int i = 0; i < totedges; i++) { | for (int i = 0; i < totedges; i++) { | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | static Material *gpencil_add_material(Main *bmain, | ||||
| return mat_gp; | return mat_gp; | ||||
| } | } | ||||
| static int gpencil_material_find_index_by_name(Object *ob, const char *name) | static int gpencil_material_find_index_by_name(Object *ob, const char *name) | ||||
| { | { | ||||
| for (int i = 0; i < ob->totcol; i++) { | for (int i = 0; i < ob->totcol; i++) { | ||||
| Material *ma = BKE_object_material_get(ob, i + 1); | Material *ma = BKE_object_material_get(ob, i + 1); | ||||
| if ((ma != NULL) && (ma->gp_style != NULL) && (STREQ(ma->id.name + 2, name))) { | if ((ma != nullptr) && (ma->gp_style != nullptr) && (STREQ(ma->id.name + 2, name))) { | ||||
| return i; | return i; | ||||
| } | } | ||||
| } | } | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| /** | /** | ||||
| Show All 13 Lines | |||||
| /** | /** | ||||
| * Convert a mesh object to grease pencil stroke. | * Convert a mesh object to grease pencil stroke. | ||||
| * | * | ||||
| * \param bmain: Main thread pointer. | * \param bmain: Main thread pointer. | ||||
| * \param depsgraph: Original depsgraph. | * \param depsgraph: Original depsgraph. | ||||
| * \param scene: Original scene. | * \param scene: Original scene. | ||||
| * \param ob_gp: Grease pencil object to add strokes. | * \param ob_gp: Grease pencil object to add strokes. | ||||
| * \param ob_mesh: Mesh to convert. | * \param ob_mesh: Mesh to convert. | ||||
| * \param angle: Limit angle to consider a edgeloop ends. | * \param angle: Limit angle to consider a edge-loop ends. | ||||
| * \param thickness: Thickness of the strokes. | * \param thickness: Thickness of the strokes. | ||||
| * \param offset: Offset along the normals. | * \param offset: Offset along the normals. | ||||
| * \param matrix: Transformation matrix. | * \param matrix: Transformation matrix. | ||||
| * \param frame_offset: Destination frame number offset. | * \param frame_offset: Destination frame number offset. | ||||
| * \param use_seams: Only export seam edges. | * \param use_seams: Only export seam edges. | ||||
| * \param use_faces: Export faces as filled strokes. | * \param use_faces: Export faces as filled strokes. | ||||
| */ | */ | ||||
| bool BKE_gpencil_convert_mesh(Main *bmain, | bool BKE_gpencil_convert_mesh(Main *bmain, | ||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob_gp, | Object *ob_gp, | ||||
| Object *ob_mesh, | Object *ob_mesh, | ||||
| const float angle, | const float angle, | ||||
| const int thickness, | const int thickness, | ||||
| const float offset, | const float offset, | ||||
| const float matrix[4][4], | const float matrix[4][4], | ||||
| const int frame_offset, | const int frame_offset, | ||||
| const bool use_seams, | const bool use_seams, | ||||
| const bool use_faces) | const bool use_faces) | ||||
| { | { | ||||
| if (ELEM(NULL, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { | if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| bGPdata *gpd = (bGPdata *)ob_gp->data; | bGPdata *gpd = (bGPdata *)ob_gp->data; | ||||
| /* Use evaluated data to get mesh with all modifiers on top. */ | /* Use evaluated data to get mesh with all modifiers on top. */ | ||||
| Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, ob_mesh); | Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, ob_mesh); | ||||
| const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); | const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); | ||||
| Show All 20 Lines | bool BKE_gpencil_convert_mesh(Main *bmain, | ||||
| /* Export faces as filled strokes. */ | /* Export faces as filled strokes. */ | ||||
| if (use_faces) { | if (use_faces) { | ||||
| /* Read all polygons and create fill for each. */ | /* Read all polygons and create fill for each. */ | ||||
| if (mpoly_len > 0) { | if (mpoly_len > 0) { | ||||
| make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); | make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); | ||||
| /* Create Layer and Frame. */ | /* Create Layer and Frame. */ | ||||
| bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); | bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); | ||||
| if (gpl_fill == NULL) { | if (gpl_fill == nullptr) { | ||||
| gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); | gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); | ||||
| } | } | ||||
| bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( | bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( | ||||
| gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); | gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); | ||||
| int i; | int i; | ||||
| for (i = 0; i < mpoly_len; i++) { | for (i = 0; i < mpoly_len; i++) { | ||||
| const MPoly *mp = &mpoly[i]; | const MPoly *mp = &mpoly[i]; | ||||
| /* Find material. */ | /* Find material. */ | ||||
| int mat_idx = 0; | int mat_idx = 0; | ||||
| Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); | Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); | ||||
| make_element_name( | make_element_name( | ||||
| ob_mesh->id.name + 2, (ma != NULL) ? ma->id.name + 2 : "Fill", 64, element_name); | ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); | ||||
| mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); | mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); | ||||
| if (mat_idx == -1) { | if (mat_idx == -1) { | ||||
| float color[4]; | float color[4]; | ||||
| if (ma != NULL) { | if (ma != nullptr) { | ||||
| copy_v3_v3(color, &ma->r); | copy_v3_v3(color, &ma->r); | ||||
| color[3] = 1.0f; | color[3] = 1.0f; | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v4_v4(color, default_colors[1]); | copy_v4_v4(color, default_colors[1]); | ||||
| } | } | ||||
| gpencil_add_material(bmain, ob_gp, element_name, color, false, true, &mat_idx); | gpencil_add_material(bmain, ob_gp, element_name, color, false, true, &mat_idx); | ||||
| } | } | ||||
| Show All 22 Lines | if (use_faces) { | ||||
| } | } | ||||
| } | } | ||||
| /* Create stroke from edges. */ | /* Create stroke from edges. */ | ||||
| make_element_name(ob_mesh->id.name + 2, "Lines", 128, element_name); | make_element_name(ob_mesh->id.name + 2, "Lines", 128, element_name); | ||||
| /* Create Layer and Frame. */ | /* Create Layer and Frame. */ | ||||
| bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, element_name); | bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, element_name); | ||||
| if (gpl_stroke == NULL) { | if (gpl_stroke == nullptr) { | ||||
| gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false); | gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false); | ||||
| } | } | ||||
| bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get( | bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get( | ||||
| gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); | gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); | ||||
| gpencil_generate_edgeloops( | gpencil_generate_edgeloops( | ||||
| ob_eval, gpd, gpf_stroke, stroke_mat_index, angle, thickness, offset, matrix, use_seams); | ob_eval, gpd, gpf_stroke, stroke_mat_index, angle, thickness, offset, matrix, use_seams); | ||||
| /* Tag for recalculation */ | /* Tag for recalculation */ | ||||
| DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); | ||||
| return true; | return true; | ||||
| } | } | ||||
| /** | /** | ||||
| * Apply grease pencil Transforms. | * Apply grease pencil Transforms. | ||||
| * \param gpd: Grease pencil data-block | * \param gpd: Grease pencil data-block | ||||
| * \param mat: Transformation matrix | * \param mat: Transformation matrix | ||||
| */ | */ | ||||
| void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4]) | void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4]) | ||||
| { | { | ||||
| if (gpd == NULL) { | if (gpd == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| const float scalef = mat4_to_scale(mat); | const float scalef = mat4_to_scale(mat); | ||||
| LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | ||||
| /* FIXME: For now, we just skip parented layers. | /* FIXME: For now, we just skip parented layers. | ||||
| * Otherwise, we have to update each frame to find | * Otherwise, we have to update each frame to find | ||||
| * the current parent position/effects. | * the current parent position/effects. | ||||
| Show All 19 Lines | void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4]) | ||||
| } | } | ||||
| } | } | ||||
| /* Used for "move only origins" in object_data_transform.c */ | /* Used for "move only origins" in object_data_transform.c */ | ||||
| int BKE_gpencil_stroke_point_count(const bGPdata *gpd) | int BKE_gpencil_stroke_point_count(const bGPdata *gpd) | ||||
| { | { | ||||
| int total_points = 0; | int total_points = 0; | ||||
| if (gpd == NULL) { | if (gpd == nullptr) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| LISTBASE_FOREACH (const bGPDlayer *, gpl, &gpd->layers) { | LISTBASE_FOREACH (const bGPDlayer *, gpl, &gpd->layers) { | ||||
| /* FIXME: For now, we just skip parented layers. | /* FIXME: For now, we just skip parented layers. | ||||
| * Otherwise, we have to update each frame to find | * Otherwise, we have to update each frame to find | ||||
| * the current parent position/effects. | * the current parent position/effects. | ||||
| */ | */ | ||||
| if (gpl->parent) { | if (gpl->parent) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| LISTBASE_FOREACH (const bGPDframe *, gpf, &gpl->frames) { | LISTBASE_FOREACH (const bGPDframe *, gpf, &gpl->frames) { | ||||
| LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { | LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { | ||||
| total_points += gps->totpoints; | total_points += gps->totpoints; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return total_points; | return total_points; | ||||
| } | } | ||||
| /* Used for "move only origins" in object_data_transform.c */ | /* Used for "move only origins" in object_data_transform.c */ | ||||
| void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data) | void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data) | ||||
| { | { | ||||
| if (gpd == NULL) { | if (gpd == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | ||||
| /* FIXME: For now, we just skip parented layers. | /* FIXME: For now, we just skip parented layers. | ||||
| * Otherwise, we have to update each frame to find | * Otherwise, we have to update each frame to find | ||||
| * the current parent position/effects. | * the current parent position/effects. | ||||
| */ | */ | ||||
| Show All 14 Lines | LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Used for "move only origins" in object_data_transform.c */ | /* Used for "move only origins" in object_data_transform.c */ | ||||
| void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data) | void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data) | ||||
| { | { | ||||
| if (gpd == NULL) { | if (gpd == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | ||||
| /* FIXME: For now, we just skip parented layers. | /* FIXME: For now, we just skip parented layers. | ||||
| * Otherwise, we have to update each frame to find | * Otherwise, we have to update each frame to find | ||||
| * the current parent position/effects. | * the current parent position/effects. | ||||
| */ | */ | ||||
| Show All 19 Lines | void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data) | ||||
| } | } | ||||
| } | } | ||||
| /* Used for "move only origins" in object_data_transform.c */ | /* Used for "move only origins" in object_data_transform.c */ | ||||
| void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd, | void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd, | ||||
| const GPencilPointCoordinates *elem_data, | const GPencilPointCoordinates *elem_data, | ||||
| const float mat[4][4]) | const float mat[4][4]) | ||||
| { | { | ||||
| if (gpd == NULL) { | if (gpd == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| const float scalef = mat4_to_scale(mat); | const float scalef = mat4_to_scale(mat); | ||||
| LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | ||||
| /* FIXME: For now, we just skip parented layers. | /* FIXME: For now, we just skip parented layers. | ||||
| * Otherwise, we have to update each frame to find | * Otherwise, we have to update each frame to find | ||||
| * the current parent position/effects. | * the current parent position/effects. | ||||
| ▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | for (int i = 0; i < gps->totpoints / 2; i++) { | ||||
| end--; | end--; | ||||
| } | } | ||||
| } | } | ||||
| /* Temp data for storing information about an "island" of points | /* Temp data for storing information about an "island" of points | ||||
| * that should be kept when splitting up a stroke. Used in: | * that should be kept when splitting up a stroke. Used in: | ||||
| * gpencil_stroke_delete_tagged_points() | * gpencil_stroke_delete_tagged_points() | ||||
| */ | */ | ||||
| typedef struct tGPDeleteIsland { | struct tGPDeleteIsland { | ||||
| int start_idx; | int start_idx; | ||||
| int end_idx; | int end_idx; | ||||
| } tGPDeleteIsland; | }; | ||||
| static void gpencil_stroke_join_islands(bGPdata *gpd, | static void gpencil_stroke_join_islands(bGPdata *gpd, | ||||
| bGPDframe *gpf, | bGPDframe *gpf, | ||||
| bGPDstroke *gps_first, | bGPDstroke *gps_first, | ||||
| bGPDstroke *gps_last) | bGPDstroke *gps_last) | ||||
| { | { | ||||
| bGPDspoint *pt = NULL; | bGPDspoint *pt = nullptr; | ||||
| bGPDspoint *pt_final = NULL; | bGPDspoint *pt_final = nullptr; | ||||
| const int totpoints = gps_first->totpoints + gps_last->totpoints; | const int totpoints = gps_first->totpoints + gps_last->totpoints; | ||||
| /* create new stroke */ | /* create new stroke */ | ||||
| bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true); | bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true); | ||||
| join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__); | join_stroke->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__); | ||||
| join_stroke->totpoints = totpoints; | join_stroke->totpoints = totpoints; | ||||
| join_stroke->flag &= ~GP_STROKE_CYCLIC; | join_stroke->flag &= ~GP_STROKE_CYCLIC; | ||||
| /* copy points (last before) */ | /* copy points (last before) */ | ||||
| int e1 = 0; | int e1 = 0; | ||||
| int e2 = 0; | int e2 = 0; | ||||
| float delta = 0.0f; | float delta = 0.0f; | ||||
| Show All 16 Lines | for (int i = 0; i < totpoints; i++) { | ||||
| pt_final->flag = pt->flag; | pt_final->flag = pt->flag; | ||||
| copy_v4_v4(pt_final->vert_color, pt->vert_color); | copy_v4_v4(pt_final->vert_color, pt->vert_color); | ||||
| /* retiming with fixed time interval (we cannot determine real time) */ | /* retiming with fixed time interval (we cannot determine real time) */ | ||||
| delta += 0.01f; | delta += 0.01f; | ||||
| } | } | ||||
| /* Copy over vertex weight data (if available) */ | /* Copy over vertex weight data (if available) */ | ||||
| if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) { | if ((gps_first->dvert != nullptr) || (gps_last->dvert != nullptr)) { | ||||
| join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__); | join_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * totpoints, __func__); | ||||
| MDeformVert *dvert_src = NULL; | MDeformVert *dvert_src = nullptr; | ||||
| MDeformVert *dvert_dst = NULL; | MDeformVert *dvert_dst = nullptr; | ||||
| /* Copy weights (last before). */ | /* Copy weights (last before). */ | ||||
| e1 = 0; | e1 = 0; | ||||
| e2 = 0; | e2 = 0; | ||||
| for (int i = 0; i < totpoints; i++) { | for (int i = 0; i < totpoints; i++) { | ||||
| dvert_dst = &join_stroke->dvert[i]; | dvert_dst = &join_stroke->dvert[i]; | ||||
| dvert_src = NULL; | dvert_src = nullptr; | ||||
| if (i < gps_last->totpoints) { | if (i < gps_last->totpoints) { | ||||
| if (gps_last->dvert) { | if (gps_last->dvert) { | ||||
| dvert_src = &gps_last->dvert[e1]; | dvert_src = &gps_last->dvert[e1]; | ||||
| e1++; | e1++; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (gps_first->dvert) { | if (gps_first->dvert) { | ||||
| dvert_src = &gps_first->dvert[e2]; | dvert_src = &gps_first->dvert[e2]; | ||||
| e2++; | e2++; | ||||
| } | } | ||||
| } | } | ||||
| if ((dvert_src) && (dvert_src->dw)) { | if ((dvert_src) && (dvert_src->dw)) { | ||||
| dvert_dst->dw = MEM_dupallocN(dvert_src->dw); | dvert_dst->dw = (MDeformWeight *)MEM_dupallocN(dvert_src->dw); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* add new stroke at head */ | /* add new stroke at head */ | ||||
| BLI_addhead(&gpf->strokes, join_stroke); | BLI_addhead(&gpf->strokes, join_stroke); | ||||
| /* Calc geometry data. */ | /* Calc geometry data. */ | ||||
| BKE_gpencil_stroke_geometry_update(gpd, join_stroke); | BKE_gpencil_stroke_geometry_update(gpd, join_stroke); | ||||
| Show All 24 Lines | |||||
| bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, | bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, | ||||
| bGPDframe *gpf, | bGPDframe *gpf, | ||||
| bGPDstroke *gps, | bGPDstroke *gps, | ||||
| bGPDstroke *next_stroke, | bGPDstroke *next_stroke, | ||||
| int tag_flags, | int tag_flags, | ||||
| bool select, | bool select, | ||||
| int limit) | int limit) | ||||
| { | { | ||||
| tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, | tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN( | ||||
| "gp_point_islands"); | sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); | ||||
| bool in_island = false; | bool in_island = false; | ||||
| int num_islands = 0; | int num_islands = 0; | ||||
| bGPDstroke *new_stroke = NULL; | bGPDstroke *new_stroke = nullptr; | ||||
| bGPDstroke *gps_first = NULL; | bGPDstroke *gps_first = nullptr; | ||||
| const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC); | const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC); | ||||
| /* First Pass: Identify start/end of islands */ | /* First Pass: Identify start/end of islands */ | ||||
| bGPDspoint *pt = gps->points; | bGPDspoint *pt = gps->points; | ||||
| for (int i = 0; i < gps->totpoints; i++, pt++) { | for (int i = 0; i < gps->totpoints; i++, pt++) { | ||||
| if (pt->flag & tag_flags) { | if (pt->flag & tag_flags) { | ||||
| /* selected - stop accumulating to island */ | /* selected - stop accumulating to island */ | ||||
| in_island = false; | in_island = false; | ||||
| Show All 25 Lines | if (num_islands) { | ||||
| int idx; | int idx; | ||||
| /* Create each new stroke... */ | /* Create each new stroke... */ | ||||
| for (idx = 0; idx < num_islands; idx++) { | for (idx = 0; idx < num_islands; idx++) { | ||||
| tGPDeleteIsland *island = &islands[idx]; | tGPDeleteIsland *island = &islands[idx]; | ||||
| new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true); | new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true); | ||||
| /* if cyclic and first stroke, save to join later */ | /* if cyclic and first stroke, save to join later */ | ||||
| if ((is_cyclic) && (gps_first == NULL)) { | if ((is_cyclic) && (gps_first == nullptr)) { | ||||
| gps_first = new_stroke; | gps_first = new_stroke; | ||||
| } | } | ||||
| new_stroke->flag &= ~GP_STROKE_CYCLIC; | new_stroke->flag &= ~GP_STROKE_CYCLIC; | ||||
| /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ | /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ | ||||
| new_stroke->totpoints = island->end_idx - island->start_idx + 1; | new_stroke->totpoints = island->end_idx - island->start_idx + 1; | ||||
| /* Copy over the relevant point data */ | /* Copy over the relevant point data */ | ||||
| new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, | new_stroke->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, | ||||
| "gp delete stroke fragment"); | "gp delete stroke fragment"); | ||||
| memcpy(new_stroke->points, | memcpy(new_stroke->points, | ||||
| gps->points + island->start_idx, | gps->points + island->start_idx, | ||||
| sizeof(bGPDspoint) * new_stroke->totpoints); | sizeof(bGPDspoint) * new_stroke->totpoints); | ||||
| /* Copy over vertex weight data (if available) */ | /* Copy over vertex weight data (if available) */ | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| /* Copy over the relevant vertex-weight points */ | /* Copy over the relevant vertex-weight points */ | ||||
| new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, | new_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, | ||||
| "gp delete stroke fragment weight"); | "gp delete stroke fragment weight"); | ||||
| memcpy(new_stroke->dvert, | memcpy(new_stroke->dvert, | ||||
| gps->dvert + island->start_idx, | gps->dvert + island->start_idx, | ||||
| sizeof(MDeformVert) * new_stroke->totpoints); | sizeof(MDeformVert) * new_stroke->totpoints); | ||||
| /* Copy weights */ | /* Copy weights */ | ||||
| int e = island->start_idx; | int e = island->start_idx; | ||||
| for (int i = 0; i < new_stroke->totpoints; i++) { | for (int i = 0; i < new_stroke->totpoints; i++) { | ||||
| MDeformVert *dvert_src = &gps->dvert[e]; | MDeformVert *dvert_src = &gps->dvert[e]; | ||||
| MDeformVert *dvert_dst = &new_stroke->dvert[i]; | MDeformVert *dvert_dst = &new_stroke->dvert[i]; | ||||
| if (dvert_src->dw) { | if (dvert_src->dw) { | ||||
| dvert_dst->dw = MEM_dupallocN(dvert_src->dw); | dvert_dst->dw = (MDeformWeight *)MEM_dupallocN(dvert_src->dw); | ||||
| } | } | ||||
| e++; | e++; | ||||
| } | } | ||||
| } | } | ||||
| /* Each island corresponds to a new stroke. | /* Each island corresponds to a new stroke. | ||||
| * We must adjust the timings of these new strokes: | * We must adjust the timings of these new strokes: | ||||
| * | * | ||||
| * Each point's timing data is a delta from stroke's inittime, so as we erase some points | * Each point's timing data is a delta from stroke's inittime, so as we erase some points | ||||
| Show All 17 Lines | for (idx = 0; idx < num_islands; idx++) { | ||||
| pts->flag |= GP_SPOINT_TAG; | pts->flag |= GP_SPOINT_TAG; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Add new stroke to the frame or delete if below limit */ | /* Add new stroke to the frame or delete if below limit */ | ||||
| if ((limit > 0) && (new_stroke->totpoints <= limit)) { | if ((limit > 0) && (new_stroke->totpoints <= limit)) { | ||||
| if (gps_first == new_stroke) { | if (gps_first == new_stroke) { | ||||
| gps_first = NULL; | gps_first = nullptr; | ||||
| } | } | ||||
| BKE_gpencil_free_stroke(new_stroke); | BKE_gpencil_free_stroke(new_stroke); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Calc geometry data. */ | /* Calc geometry data. */ | ||||
| BKE_gpencil_stroke_geometry_update(gpd, new_stroke); | BKE_gpencil_stroke_geometry_update(gpd, new_stroke); | ||||
| if (next_stroke) { | if (next_stroke) { | ||||
| BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke); | BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_addtail(&gpf->strokes, new_stroke); | BLI_addtail(&gpf->strokes, new_stroke); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* if cyclic, need to join last stroke with first stroke */ | /* if cyclic, need to join last stroke with first stroke */ | ||||
| if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) { | if ((is_cyclic) && (gps_first != nullptr) && (gps_first != new_stroke)) { | ||||
| gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke); | gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke); | ||||
| } | } | ||||
| } | } | ||||
| /* free islands */ | /* free islands */ | ||||
| MEM_freeN(islands); | MEM_freeN(islands); | ||||
| /* Delete the old stroke */ | /* Delete the old stroke */ | ||||
| BLI_remlink(&gpf->strokes, gps); | BLI_remlink(&gpf->strokes, gps); | ||||
| BKE_gpencil_free_stroke(gps); | BKE_gpencil_free_stroke(gps); | ||||
| return new_stroke; | return new_stroke; | ||||
| } | } | ||||
| void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, | void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, | ||||
| bGPDframe *gpf, | bGPDframe *gpf, | ||||
| bGPDstroke *gps, | bGPDstroke *gps, | ||||
| bGPDstroke *next_stroke, | bGPDstroke *next_stroke, | ||||
| bGPDcurve *gpc, | bGPDcurve *gpc, | ||||
| int tag_flags) | int tag_flags) | ||||
| { | { | ||||
| if (gpc == NULL) { | if (gpc == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC; | const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC; | ||||
| const int idx_last = gpc->tot_curve_points - 1; | const int idx_last = gpc->tot_curve_points - 1; | ||||
| bGPDstroke *gps_first = NULL; | bGPDstroke *gps_first = nullptr; | ||||
| bGPDstroke *gps_last = NULL; | bGPDstroke *gps_last = nullptr; | ||||
| int idx_start = 0; | int idx_start = 0; | ||||
| int idx_end = 0; | int idx_end = 0; | ||||
| bool prev_selected = gpc->curve_points[0].flag & tag_flags; | bool prev_selected = gpc->curve_points[0].flag & tag_flags; | ||||
| for (int i = 1; i < gpc->tot_curve_points; i++) { | for (int i = 1; i < gpc->tot_curve_points; i++) { | ||||
| bool selected = gpc->curve_points[i].flag & tag_flags; | bool selected = gpc->curve_points[i].flag & tag_flags; | ||||
| if (prev_selected == true && selected == false) { | if (prev_selected == true && selected == false) { | ||||
| idx_start = i; | idx_start = i; | ||||
| Show All 14 Lines | if ((prev_selected == false && selected == true) || (selected == false && i == idx_last)) { | ||||
| } | } | ||||
| else { | else { | ||||
| prev_selected = selected; | prev_selected = selected; | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false); | bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false); | ||||
| new_stroke->points = NULL; | new_stroke->points = nullptr; | ||||
| new_stroke->flag &= ~GP_STROKE_CYCLIC; | new_stroke->flag &= ~GP_STROKE_CYCLIC; | ||||
| new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length); | new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length); | ||||
| if (gps_first == NULL) { | if (gps_first == nullptr) { | ||||
| gps_first = new_stroke; | gps_first = new_stroke; | ||||
| } | } | ||||
| bGPDcurve *new_gpc = new_stroke->editcurve; | bGPDcurve *new_gpc = new_stroke->editcurve; | ||||
| memcpy(new_gpc->curve_points, | memcpy(new_gpc->curve_points, | ||||
| gpc->curve_points + idx_start, | gpc->curve_points + idx_start, | ||||
| sizeof(bGPDcurve_point) * island_length); | sizeof(bGPDcurve_point) * island_length); | ||||
| Show All 11 Lines | if ((prev_selected == false && selected == true) || (selected == false && i == idx_last)) { | ||||
| } | } | ||||
| gps_last = new_stroke; | gps_last = new_stroke; | ||||
| } | } | ||||
| prev_selected = selected; | prev_selected = selected; | ||||
| } | } | ||||
| /* join first and last stroke if cyclic */ | /* join first and last stroke if cyclic */ | ||||
| if (is_cyclic && gps_first != NULL && gps_last != NULL && gps_first != gps_last) { | if (is_cyclic && gps_first != nullptr && gps_last != nullptr && gps_first != gps_last) { | ||||
| bGPDcurve *gpc_first = gps_first->editcurve; | bGPDcurve *gpc_first = gps_first->editcurve; | ||||
| bGPDcurve *gpc_last = gps_last->editcurve; | bGPDcurve *gpc_last = gps_last->editcurve; | ||||
| int first_tot_points = gpc_first->tot_curve_points; | int first_tot_points = gpc_first->tot_curve_points; | ||||
| int old_tot_points = gpc_last->tot_curve_points; | int old_tot_points = gpc_last->tot_curve_points; | ||||
| gpc_last->tot_curve_points = first_tot_points + old_tot_points; | gpc_last->tot_curve_points = first_tot_points + old_tot_points; | ||||
| gpc_last->curve_points = MEM_recallocN(gpc_last->curve_points, | gpc_last->curve_points = (bGPDcurve_point *)MEM_recallocN( | ||||
| sizeof(bGPDcurve_point) * gpc_last->tot_curve_points); | gpc_last->curve_points, sizeof(bGPDcurve_point) * gpc_last->tot_curve_points); | ||||
| /* copy data from first to last */ | /* copy data from first to last */ | ||||
| memcpy(gpc_last->curve_points + old_tot_points, | memcpy(gpc_last->curve_points + old_tot_points, | ||||
| gpc_first->curve_points, | gpc_first->curve_points, | ||||
| sizeof(bGPDcurve_point) * first_tot_points); | sizeof(bGPDcurve_point) * first_tot_points); | ||||
| BKE_gpencil_editcurve_recalculate_handles(gps_last); | BKE_gpencil_editcurve_recalculate_handles(gps_last); | ||||
| gps_last->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; | gps_last->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; | ||||
| Show All 16 Lines | static void gpencil_stroke_copy_point(bGPDstroke *gps, | ||||
| bGPDspoint *point, | bGPDspoint *point, | ||||
| const float delta[3], | const float delta[3], | ||||
| float pressure, | float pressure, | ||||
| float strength, | float strength, | ||||
| float deltatime) | float deltatime) | ||||
| { | { | ||||
| bGPDspoint *newpoint; | bGPDspoint *newpoint; | ||||
| gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); | gps->points = (bGPDspoint *)MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1)); | gps->dvert = (MDeformVert *)MEM_reallocN(gps->dvert, | ||||
| sizeof(MDeformVert) * (gps->totpoints + 1)); | |||||
| } | } | ||||
| else { | else { | ||||
| /* If destination has weight add weight to origin. */ | /* If destination has weight add weight to origin. */ | ||||
| if (dvert != NULL) { | if (dvert != nullptr) { | ||||
| gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__); | gps->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), | ||||
| __func__); | |||||
| } | } | ||||
| } | } | ||||
| gps->totpoints++; | gps->totpoints++; | ||||
| newpoint = &gps->points[gps->totpoints - 1]; | newpoint = &gps->points[gps->totpoints - 1]; | ||||
| newpoint->x = point->x * delta[0]; | newpoint->x = point->x * delta[0]; | ||||
| newpoint->y = point->y * delta[1]; | newpoint->y = point->y * delta[1]; | ||||
| newpoint->z = point->z * delta[2]; | newpoint->z = point->z * delta[2]; | ||||
| newpoint->flag = point->flag; | newpoint->flag = point->flag; | ||||
| newpoint->pressure = pressure; | newpoint->pressure = pressure; | ||||
| newpoint->strength = strength; | newpoint->strength = strength; | ||||
| newpoint->time = point->time + deltatime; | newpoint->time = point->time + deltatime; | ||||
| copy_v4_v4(newpoint->vert_color, point->vert_color); | copy_v4_v4(newpoint->vert_color, point->vert_color); | ||||
| if (gps->dvert != NULL) { | if (gps->dvert != nullptr) { | ||||
| MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1]; | MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1]; | ||||
| if (dvert != NULL) { | if (dvert != nullptr) { | ||||
| newdvert->totweight = dvert->totweight; | newdvert->totweight = dvert->totweight; | ||||
| newdvert->dw = MEM_dupallocN(dvert->dw); | newdvert->dw = (MDeformWeight *)MEM_dupallocN(dvert->dw); | ||||
| } | } | ||||
| else { | else { | ||||
| newdvert->totweight = 0; | newdvert->totweight = 0; | ||||
| newdvert->dw = NULL; | newdvert->dw = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Join two strokes using the shortest distance (reorder stroke if necessary ) */ | /* Join two strokes using the shortest distance (reorder stroke if necessary ) */ | ||||
| void BKE_gpencil_stroke_join(bGPDstroke *gps_a, | void BKE_gpencil_stroke_join(bGPDstroke *gps_a, | ||||
| bGPDstroke *gps_b, | bGPDstroke *gps_b, | ||||
| const bool leave_gaps, | const bool leave_gaps, | ||||
| const bool fit_thickness) | const bool fit_thickness) | ||||
| { | { | ||||
| bGPDspoint point; | bGPDspoint point; | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| const float delta[3] = {1.0f, 1.0f, 1.0f}; | const float delta[3] = {1.0f, 1.0f, 1.0f}; | ||||
| float deltatime = 0.0f; | float deltatime = 0.0f; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gps_a, gps_b)) { | if (ELEM(nullptr, gps_a, gps_b)) { | ||||
| return; | return; | ||||
| } | } | ||||
| if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) { | if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* define start and end points of each stroke */ | /* define start and end points of each stroke */ | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | void BKE_gpencil_stroke_join(bGPDstroke *gps_a, | ||||
| } | } | ||||
| /* don't visibly link the first and last points? */ | /* don't visibly link the first and last points? */ | ||||
| if (leave_gaps) { | if (leave_gaps) { | ||||
| /* 1st: add one tail point to start invisible area */ | /* 1st: add one tail point to start invisible area */ | ||||
| point = gps_a->points[gps_a->totpoints - 1]; | point = gps_a->points[gps_a->totpoints - 1]; | ||||
| deltatime = point.time; | deltatime = point.time; | ||||
| gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f); | gpencil_stroke_copy_point(gps_a, nullptr, &point, delta, 0.0f, 0.0f, 0.0f); | ||||
| /* 2nd: add one head point to finish invisible area */ | /* 2nd: add one head point to finish invisible area */ | ||||
| point = gps_b->points[0]; | point = gps_b->points[0]; | ||||
| gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime); | gpencil_stroke_copy_point(gps_a, nullptr, &point, delta, 0.0f, 0.0f, deltatime); | ||||
| } | } | ||||
| const float ratio = (fit_thickness && gps_a->thickness > 0.0f) ? | const float ratio = (fit_thickness && gps_a->thickness > 0.0f) ? | ||||
| (float)gps_b->thickness / (float)gps_a->thickness : | (float)gps_b->thickness / (float)gps_a->thickness : | ||||
| 1.0f; | 1.0f; | ||||
| /* 3rd: add all points */ | /* 3rd: add all points */ | ||||
| for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { | for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { | ||||
| MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL; | MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : nullptr; | ||||
| gpencil_stroke_copy_point( | gpencil_stroke_copy_point( | ||||
| gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime); | gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime); | ||||
| } | } | ||||
| } | } | ||||
| /* Copy the stroke of the frame to all frames selected (except current). */ | /* Copy the stroke of the frame to all frames selected (except current). */ | ||||
| void BKE_gpencil_stroke_copy_to_keyframes( | void BKE_gpencil_stroke_copy_to_keyframes( | ||||
| bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const bool tail) | bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const bool tail) | ||||
| { | { | ||||
| GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64); | GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64); | ||||
| BKE_gpencil_frame_selected_hash(gpd, frame_list); | BKE_gpencil_frame_selected_hash(gpd, frame_list); | ||||
| GHashIterator gh_iter; | GHashIterator gh_iter; | ||||
| GHASH_ITER (gh_iter, frame_list) { | GHASH_ITER (gh_iter, frame_list) { | ||||
| int cfra = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); | int cfra = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); | ||||
| if (gpf->framenum != cfra) { | if (gpf->framenum != cfra) { | ||||
| bGPDframe *gpf_new = BKE_gpencil_layer_frame_find(gpl, cfra); | bGPDframe *gpf_new = BKE_gpencil_layer_frame_find(gpl, cfra); | ||||
| if (gpf_new == NULL) { | if (gpf_new == nullptr) { | ||||
| gpf_new = BKE_gpencil_frame_addnew(gpl, cfra); | gpf_new = BKE_gpencil_frame_addnew(gpl, cfra); | ||||
| } | } | ||||
| if (gpf_new == NULL) { | if (gpf_new == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, true, true); | bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, true, true); | ||||
| if (gps_new == NULL) { | if (gps_new == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (tail) { | if (tail) { | ||||
| BLI_addhead(&gpf_new->strokes, gps_new); | BLI_addhead(&gpf_new->strokes, gps_new); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_addtail(&gpf_new->strokes, gps_new); | BLI_addtail(&gpf_new->strokes, gps_new); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Free hash table. */ | /* Free hash table. */ | ||||
| BLI_ghash_free(frame_list, NULL, NULL); | BLI_ghash_free(frame_list, nullptr, nullptr); | ||||
| } | } | ||||
| /* Stroke Uniform Subdivide ------------------------------------- */ | /* Stroke Uniform Subdivide ------------------------------------- */ | ||||
| typedef struct tSamplePoint { | struct tSamplePoint { | ||||
| struct tSamplePoint *next, *prev; | struct tSamplePoint *next, *prev; | ||||
| float x, y, z; | float x, y, z; | ||||
| float pressure, strength, time; | float pressure, strength, time; | ||||
| float vertex_color[4]; | float vertex_color[4]; | ||||
| struct MDeformWeight *dw; | struct MDeformWeight *dw; | ||||
| int totweight; | int totweight; | ||||
| } tSamplePoint; | }; | ||||
| typedef struct tSampleEdge { | struct tSampleEdge { | ||||
| float length_sq; | float length_sq; | ||||
| tSamplePoint *from; | tSamplePoint *from; | ||||
| tSamplePoint *to; | tSamplePoint *to; | ||||
| } tSampleEdge; | }; | ||||
| /* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */ | /* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */ | ||||
| static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert) | static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert) | ||||
| { | { | ||||
| tSamplePoint *new_pt = MEM_callocN(sizeof(tSamplePoint), __func__); | tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__); | ||||
| copy_v3_v3(&new_pt->x, &pt->x); | copy_v3_v3(&new_pt->x, &pt->x); | ||||
| new_pt->pressure = pt->pressure; | new_pt->pressure = pt->pressure; | ||||
| new_pt->strength = pt->strength; | new_pt->strength = pt->strength; | ||||
| new_pt->time = pt->time; | new_pt->time = pt->time; | ||||
| copy_v4_v4((float *)&new_pt->vertex_color, (float *)&pt->vert_color); | copy_v4_v4((float *)&new_pt->vertex_color, (float *)&pt->vert_color); | ||||
| if (dvert != NULL) { | if (dvert != nullptr) { | ||||
| new_pt->totweight = dvert->totweight; | new_pt->totweight = dvert->totweight; | ||||
| new_pt->dw = MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__); | new_pt->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__); | ||||
| for (uint i = 0; i < new_pt->totweight; ++i) { | for (uint i = 0; i < new_pt->totweight; ++i) { | ||||
| MDeformWeight *dw = &new_pt->dw[i]; | MDeformWeight *dw = &new_pt->dw[i]; | ||||
| MDeformWeight *dw_from = &dvert->dw[i]; | MDeformWeight *dw_from = &dvert->dw[i]; | ||||
| dw->def_nr = dw_from->def_nr; | dw->def_nr = dw_from->def_nr; | ||||
| dw->weight = dw_from->weight; | dw->weight = dw_from->weight; | ||||
| } | } | ||||
| } | } | ||||
| return new_pt; | return new_pt; | ||||
| } | } | ||||
| /* Helper: creates a tSampleEdge from two tSamplePoints. Also calculates the length (squared) of | /* Helper: creates a tSampleEdge from two tSamplePoints. Also calculates the length (squared) of | ||||
| * the edge. */ | * the edge. */ | ||||
| static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to) | static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to) | ||||
| { | { | ||||
| tSampleEdge *new_edge = MEM_callocN(sizeof(tSampleEdge), __func__); | tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__); | ||||
| new_edge->from = from; | new_edge->from = from; | ||||
| new_edge->to = to; | new_edge->to = to; | ||||
| new_edge->length_sq = len_squared_v3v3(&from->x, &to->x); | new_edge->length_sq = len_squared_v3v3(&from->x, &to->x); | ||||
| return new_edge; | return new_edge; | ||||
| } | } | ||||
| /** | /** | ||||
| * Subdivide the grease pencil stroke so the number of points is target_number. | * Subdivide the grease pencil stroke so the number of points is target_number. | ||||
| * Does not change the shape of the stroke. The new points will be distributed as | * Does not change the shape of the stroke. The new points will be distributed as | ||||
| * uniformly as possible by repeatedly subdividing the current longest edge. | * uniformly as possible by repeatedly subdividing the current longest edge. | ||||
| * | * | ||||
| * \param gps: The stroke to be up-sampled. | * \param gps: The stroke to be up-sampled. | ||||
| * \param target_number: The number of points the up-sampled stroke should have. | * \param target_number: The number of points the up-sampled stroke should have. | ||||
| * \param select: Select/Deselect the stroke. | * \param select: Select/Deselect the stroke. | ||||
| */ | */ | ||||
| void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, | void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, | ||||
| bGPDstroke *gps, | bGPDstroke *gps, | ||||
| const uint32_t target_number, | const uint32_t target_number, | ||||
| const bool select) | const bool select) | ||||
| { | { | ||||
| /* Stroke needs at least two points and strictly less points than the target number. */ | /* Stroke needs at least two points and strictly less points than the target number. */ | ||||
| if (gps == NULL || gps->totpoints < 2 || gps->totpoints >= target_number) { | if (gps == nullptr || gps->totpoints < 2 || gps->totpoints >= target_number) { | ||||
| return; | return; | ||||
| } | } | ||||
| const int totpoints = gps->totpoints; | const int totpoints = gps->totpoints; | ||||
| const bool has_dverts = (gps->dvert != NULL); | const bool has_dverts = (gps->dvert != nullptr); | ||||
| const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC); | const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC); | ||||
| ListBase points = {NULL, NULL}; | ListBase points = {nullptr, nullptr}; | ||||
| Heap *edges = BLI_heap_new(); | Heap *edges = BLI_heap_new(); | ||||
| /* Add all points into list. */ | /* Add all points into list. */ | ||||
| for (uint32_t i = 0; i < totpoints; ++i) { | for (uint32_t i = 0; i < totpoints; ++i) { | ||||
| bGPDspoint *pt = &gps->points[i]; | bGPDspoint *pt = &gps->points[i]; | ||||
| MDeformVert *dvert = has_dverts ? &gps->dvert[i] : NULL; | MDeformVert *dvert = has_dverts ? &gps->dvert[i] : nullptr; | ||||
| tSamplePoint *sp = new_sample_point_from_gp_point(pt, dvert); | tSamplePoint *sp = new_sample_point_from_gp_point(pt, dvert); | ||||
| BLI_addtail(&points, sp); | BLI_addtail(&points, sp); | ||||
| } | } | ||||
| /* Iterate over edges and insert them into the heap. */ | /* Iterate over edges and insert them into the heap. */ | ||||
| for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != NULL; pt = pt->next) { | for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != nullptr; pt = pt->next) { | ||||
| tSampleEdge *se = new_sample_edge_from_sample_points(pt->prev, pt); | tSampleEdge *se = new_sample_edge_from_sample_points(pt->prev, pt); | ||||
| /* BLI_heap is a min-heap, but we need the largest key to be at the top, so we take the | /* BLI_heap is a min-heap, but we need the largest key to be at the top, so we take the | ||||
| * negative of the squared length. */ | * negative of the squared length. */ | ||||
| BLI_heap_insert(edges, -(se->length_sq), se); | BLI_heap_insert(edges, -(se->length_sq), se); | ||||
| } | } | ||||
| if (is_cyclic) { | if (is_cyclic) { | ||||
| tSamplePoint *sp_first = points.first; | tSamplePoint *sp_first = (tSamplePoint *)points.first; | ||||
| tSamplePoint *sp_last = points.last; | tSamplePoint *sp_last = (tSamplePoint *)points.last; | ||||
| tSampleEdge *se = new_sample_edge_from_sample_points(sp_last, sp_first); | tSampleEdge *se = new_sample_edge_from_sample_points(sp_last, sp_first); | ||||
| BLI_heap_insert(edges, -(se->length_sq), se); | BLI_heap_insert(edges, -(se->length_sq), se); | ||||
| } | } | ||||
| int num_points_needed = target_number - totpoints; | int num_points_needed = target_number - totpoints; | ||||
| BLI_assert(num_points_needed > 0); | BLI_assert(num_points_needed > 0); | ||||
| while (num_points_needed > 0) { | while (num_points_needed > 0) { | ||||
| tSampleEdge *se = BLI_heap_pop_min(edges); | tSampleEdge *se = (tSampleEdge *)BLI_heap_pop_min(edges); | ||||
| tSamplePoint *sp = se->from; | tSamplePoint *sp = se->from; | ||||
| tSamplePoint *sp_next = se->to; | tSamplePoint *sp_next = se->to; | ||||
| /* Subdivide the edge. */ | /* Subdivide the edge. */ | ||||
| tSamplePoint *new_sp = MEM_callocN(sizeof(tSamplePoint), __func__); | tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__); | ||||
| interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f); | interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f); | ||||
| new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f); | new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f); | ||||
| new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f); | new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f); | ||||
| new_sp->time = interpf(sp->time, sp_next->time, 0.5f); | new_sp->time = interpf(sp->time, sp_next->time, 0.5f); | ||||
| interp_v4_v4v4((float *)&new_sp->vertex_color, | interp_v4_v4v4((float *)&new_sp->vertex_color, | ||||
| (float *)&sp->vertex_color, | (float *)&sp->vertex_color, | ||||
| (float *)&sp_next->vertex_color, | (float *)&sp_next->vertex_color, | ||||
| 0.5f); | 0.5f); | ||||
| if (sp->dw && sp_next->dw) { | if (sp->dw && sp_next->dw) { | ||||
| new_sp->totweight = MIN2(sp->totweight, sp_next->totweight); | new_sp->totweight = MIN2(sp->totweight, sp_next->totweight); | ||||
| new_sp->dw = MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, __func__); | new_sp->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, | ||||
| __func__); | |||||
| for (uint32_t i = 0; i < new_sp->totweight; ++i) { | for (uint32_t i = 0; i < new_sp->totweight; ++i) { | ||||
| MDeformWeight *dw = &new_sp->dw[i]; | MDeformWeight *dw = &new_sp->dw[i]; | ||||
| MDeformWeight *dw_from = &sp->dw[i]; | MDeformWeight *dw_from = &sp->dw[i]; | ||||
| MDeformWeight *dw_to = &sp_next->dw[i]; | MDeformWeight *dw_to = &sp_next->dw[i]; | ||||
| dw->def_nr = dw_from->def_nr; | dw->def_nr = dw_from->def_nr; | ||||
| dw->weight = interpf(dw_from->weight, dw_to->weight, 0.5f); | dw->weight = interpf(dw_from->weight, dw_to->weight, 0.5f); | ||||
| } | } | ||||
| } | } | ||||
| BLI_insertlinkafter(&points, sp, new_sp); | BLI_insertlinkafter(&points, sp, new_sp); | ||||
| tSampleEdge *se_prev = new_sample_edge_from_sample_points(sp, new_sp); | tSampleEdge *se_prev = new_sample_edge_from_sample_points(sp, new_sp); | ||||
| tSampleEdge *se_next = new_sample_edge_from_sample_points(new_sp, sp_next); | tSampleEdge *se_next = new_sample_edge_from_sample_points(new_sp, sp_next); | ||||
| BLI_heap_insert(edges, -(se_prev->length_sq), se_prev); | BLI_heap_insert(edges, -(se_prev->length_sq), se_prev); | ||||
| BLI_heap_insert(edges, -(se_next->length_sq), se_next); | BLI_heap_insert(edges, -(se_next->length_sq), se_next); | ||||
| MEM_freeN(se); | MEM_freeN(se); | ||||
| num_points_needed--; | num_points_needed--; | ||||
| } | } | ||||
| /* Edges are no longer needed. Heap is freed. */ | /* Edges are no longer needed. Heap is freed. */ | ||||
| BLI_heap_free(edges, (HeapFreeFP)MEM_freeN); | BLI_heap_free(edges, (HeapFreeFP)MEM_freeN); | ||||
| gps->totpoints = target_number; | gps->totpoints = target_number; | ||||
| gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints); | gps->points = (bGPDspoint *)MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints); | ||||
| if (has_dverts) { | if (has_dverts) { | ||||
| gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints); | gps->dvert = (MDeformVert *)MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints); | ||||
| } | } | ||||
| /* Convert list back to stroke point array. */ | /* Convert list back to stroke point array. */ | ||||
| tSamplePoint *sp = points.first; | tSamplePoint *sp = (tSamplePoint *)points.first; | ||||
| for (uint32_t i = 0; i < gps->totpoints && sp; ++i, sp = sp->next) { | for (uint32_t i = 0; i < gps->totpoints && sp; ++i, sp = sp->next) { | ||||
| bGPDspoint *pt = &gps->points[i]; | bGPDspoint *pt = &gps->points[i]; | ||||
| MDeformVert *dvert = &gps->dvert[i]; | MDeformVert *dvert = &gps->dvert[i]; | ||||
| copy_v3_v3(&pt->x, &sp->x); | copy_v3_v3(&pt->x, &sp->x); | ||||
| pt->pressure = sp->pressure; | pt->pressure = sp->pressure; | ||||
| pt->strength = sp->strength; | pt->strength = sp->strength; | ||||
| pt->time = sp->time; | pt->time = sp->time; | ||||
| copy_v4_v4((float *)&pt->vert_color, (float *)&sp->vertex_color); | copy_v4_v4((float *)&pt->vert_color, (float *)&sp->vertex_color); | ||||
| if (sp->dw) { | if (sp->dw) { | ||||
| dvert->totweight = sp->totweight; | dvert->totweight = sp->totweight; | ||||
| dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__); | dvert->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__); | ||||
| for (uint32_t j = 0; j < dvert->totweight; ++j) { | for (uint32_t j = 0; j < dvert->totweight; ++j) { | ||||
| MDeformWeight *dw = &dvert->dw[j]; | MDeformWeight *dw = &dvert->dw[j]; | ||||
| MDeformWeight *dw_from = &sp->dw[j]; | MDeformWeight *dw_from = &sp->dw[j]; | ||||
| dw->def_nr = dw_from->def_nr; | dw->def_nr = dw_from->def_nr; | ||||
| dw->weight = dw_from->weight; | dw->weight = dw_from->weight; | ||||
| } | } | ||||
| } | } | ||||
| if (select) { | if (select) { | ||||
| pt->flag |= GP_SPOINT_SELECT; | pt->flag |= GP_SPOINT_SELECT; | ||||
| } | } | ||||
| } | } | ||||
| if (select) { | if (select) { | ||||
| gps->flag |= GP_STROKE_SELECT; | gps->flag |= GP_STROKE_SELECT; | ||||
| BKE_gpencil_stroke_select_index_set(gpd, gps); | BKE_gpencil_stroke_select_index_set(gpd, gps); | ||||
| } | } | ||||
| /* Free the sample points. Important to use the mutable loop here because we are erasing the list | /* Free the sample points. Important to use the mutable loop here because we are erasing the list | ||||
| * elements. */ | * elements. */ | ||||
| LISTBASE_FOREACH_MUTABLE (tSamplePoint *, temp, &points) { | LISTBASE_FOREACH_MUTABLE (tSamplePoint *, temp, &points) { | ||||
| if (temp->dw != NULL) { | if (temp->dw != nullptr) { | ||||
| MEM_freeN(temp->dw); | MEM_freeN(temp->dw); | ||||
| } | } | ||||
| MEM_SAFE_FREE(temp); | MEM_SAFE_FREE(temp); | ||||
| } | } | ||||
| /* Update the geometry of the stroke. */ | /* Update the geometry of the stroke. */ | ||||
| BKE_gpencil_stroke_geometry_update(gpd, gps); | BKE_gpencil_stroke_geometry_update(gpd, gps); | ||||
| } | } | ||||
| Show All 35 Lines | for (int i = 0; i < gps->totpoints; i++) { | ||||
| mul_v3_m4v3(&pt->x, rv3d->viewinv, &pt->x); | mul_v3_m4v3(&pt->x, rv3d->viewinv, &pt->x); | ||||
| mul_m4_v3(inverse_diff_mat, &pt->x); | mul_m4_v3(inverse_diff_mat, &pt->x); | ||||
| } | } | ||||
| } | } | ||||
| /* ----------------------------------------------------------------------------- */ | /* ----------------------------------------------------------------------------- */ | ||||
| /* Stroke to perimeter */ | /* Stroke to perimeter */ | ||||
| typedef struct tPerimeterPoint { | struct tPerimeterPoint { | ||||
| struct tPerimeterPoint *next, *prev; | struct tPerimeterPoint *next, *prev; | ||||
| float x, y, z; | float x, y, z; | ||||
| } tPerimeterPoint; | }; | ||||
| static tPerimeterPoint *new_perimeter_point(const float pt[3]) | static tPerimeterPoint *new_perimeter_point(const float pt[3]) | ||||
| { | { | ||||
| tPerimeterPoint *new_pt = MEM_callocN(sizeof(tPerimeterPoint), __func__); | tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__); | ||||
| copy_v3_v3(&new_pt->x, pt); | copy_v3_v3(&new_pt->x, pt); | ||||
| return new_pt; | return new_pt; | ||||
| } | } | ||||
| static int generate_arc_from_point_to_point(ListBase *list, | static int generate_arc_from_point_to_point(ListBase *list, | ||||
| tPerimeterPoint *from, | tPerimeterPoint *from, | ||||
| tPerimeterPoint *to, | tPerimeterPoint *to, | ||||
| float center_pt[3], | float center_pt[3], | ||||
| ▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | |||||
| static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, | static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, | ||||
| const bGPDlayer *gpl, | const bGPDlayer *gpl, | ||||
| const bGPDstroke *gps, | const bGPDstroke *gps, | ||||
| int subdivisions, | int subdivisions, | ||||
| int *r_num_perimeter_points) | int *r_num_perimeter_points) | ||||
| { | { | ||||
| /* sanity check */ | /* sanity check */ | ||||
| if (gps->totpoints < 1) { | if (gps->totpoints < 1) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| float defaultpixsize = 1000.0f / gpd->pixfactor; | float defaultpixsize = 1000.0f / gpd->pixfactor; | ||||
| float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f; | float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f; | ||||
| ListBase *perimeter_right_side = MEM_callocN(sizeof(ListBase), __func__); | ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); | ||||
| ListBase *perimeter_left_side = MEM_callocN(sizeof(ListBase), __func__); | ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); | ||||
| int num_perimeter_points = 0; | int num_perimeter_points = 0; | ||||
| bGPDspoint *first = &gps->points[0]; | bGPDspoint *first = &gps->points[0]; | ||||
| bGPDspoint *last = &gps->points[gps->totpoints - 1]; | bGPDspoint *last = &gps->points[gps->totpoints - 1]; | ||||
| float first_radius = stroke_radius * first->pressure; | float first_radius = stroke_radius * first->pressure; | ||||
| float last_radius = stroke_radius * last->pressure; | float last_radius = stroke_radius * last->pressure; | ||||
| ▲ Show 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | |||||
| bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, | bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, | ||||
| bGPdata *gpd, | bGPdata *gpd, | ||||
| const bGPDlayer *gpl, | const bGPDlayer *gpl, | ||||
| bGPDstroke *gps, | bGPDstroke *gps, | ||||
| const int subdivisions, | const int subdivisions, | ||||
| const float diff_mat[4][4]) | const float diff_mat[4][4]) | ||||
| { | { | ||||
| if (gps->totpoints == 0) { | if (gps->totpoints == 0) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false); | bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false); | ||||
| const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0); | const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0); | ||||
| /* If Cyclic, add a new point. */ | /* If Cyclic, add a new point. */ | ||||
| if (cyclic && (gps_temp->totpoints > 1)) { | if (cyclic && (gps_temp->totpoints > 1)) { | ||||
| gps_temp->totpoints++; | gps_temp->totpoints++; | ||||
| gps_temp->points = MEM_recallocN(gps_temp->points, | gps_temp->points = (bGPDspoint *)MEM_recallocN( | ||||
| sizeof(*gps_temp->points) * gps_temp->totpoints); | gps_temp->points, sizeof(*gps_temp->points) * gps_temp->totpoints); | ||||
| bGPDspoint *pt_src = &gps_temp->points[0]; | bGPDspoint *pt_src = &gps_temp->points[0]; | ||||
| bGPDspoint *pt_dst = &gps_temp->points[gps_temp->totpoints - 1]; | bGPDspoint *pt_dst = &gps_temp->points[gps_temp->totpoints - 1]; | ||||
| copy_v3_v3(&pt_dst->x, &pt_src->x); | copy_v3_v3(&pt_dst->x, &pt_src->x); | ||||
| pt_dst->pressure = pt_src->pressure; | pt_dst->pressure = pt_src->pressure; | ||||
| pt_dst->strength = pt_src->strength; | pt_dst->strength = pt_src->strength; | ||||
| pt_dst->uv_fac = 1.0f; | pt_dst->uv_fac = 1.0f; | ||||
| pt_dst->uv_rot = 0; | pt_dst->uv_rot = 0; | ||||
| } | } | ||||
| BKE_gpencil_stroke_to_view_space(rv3d, gps_temp, diff_mat); | BKE_gpencil_stroke_to_view_space(rv3d, gps_temp, diff_mat); | ||||
| int num_perimeter_points = 0; | int num_perimeter_points = 0; | ||||
| ListBase *perimeter_points = gpencil_stroke_perimeter_ex( | ListBase *perimeter_points = gpencil_stroke_perimeter_ex( | ||||
| gpd, gpl, gps_temp, subdivisions, &num_perimeter_points); | gpd, gpl, gps_temp, subdivisions, &num_perimeter_points); | ||||
| if (num_perimeter_points == 0) { | if (num_perimeter_points == 0) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* Create new stroke. */ | /* Create new stroke. */ | ||||
| bGPDstroke *perimeter_stroke = BKE_gpencil_stroke_new(gps_temp->mat_nr, num_perimeter_points, 1); | bGPDstroke *perimeter_stroke = BKE_gpencil_stroke_new(gps_temp->mat_nr, num_perimeter_points, 1); | ||||
| int i = 0; | int i = 0; | ||||
| LISTBASE_FOREACH_INDEX (tPerimeterPoint *, curr, perimeter_points, i) { | LISTBASE_FOREACH_INDEX (tPerimeterPoint *, curr, perimeter_points, i) { | ||||
| bGPDspoint *pt = &perimeter_stroke->points[i]; | bGPDspoint *pt = &perimeter_stroke->points[i]; | ||||
| ▲ Show 20 Lines • Show All 59 Lines • Show Last 20 Lines | |||||