diff options
Diffstat (limited to 'source/blender')
254 files changed, 7336 insertions, 5477 deletions
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 50aa13bea4f..3b143356c04 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -28,9 +28,9 @@ #include "abc_transform.h" #include "abc_util.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "DNA_curve_types.h" #include "DNA_object_types.h" diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc index 98387be2e61..7eaecd271f4 100644 --- a/source/blender/alembic/intern/abc_hair.cc +++ b/source/blender/alembic/intern/abc_hair.cc @@ -25,9 +25,9 @@ #include "abc_transform.h" #include "abc_util.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc index 732ceffe467..db4b9d82ebf 100644 --- a/source/blender/alembic/intern/abc_mball.cc +++ b/source/blender/alembic/intern/abc_mball.cc @@ -22,6 +22,8 @@ #include "abc_mesh.h" #include "abc_transform.h" +#include "MEM_guardedalloc.h" + extern "C" { #include "DNA_meta_types.h" #include "DNA_mesh_types.h" @@ -35,7 +37,6 @@ extern "C" { #include "BKE_object.h" #include "DEG_depsgraph.h" -#include "MEM_guardedalloc.h" } AbcMBallWriter::AbcMBallWriter(Main *bmain, diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index edcb6263da3..3eee390d7d3 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -25,6 +25,8 @@ #include "abc_transform.h" #include "abc_util.h" +#include "MEM_guardedalloc.h" + extern "C" { #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -46,8 +48,6 @@ extern "C" { #include "BKE_modifier.h" #include "BKE_object.h" -#include "MEM_guardedalloc.h" - #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc index 739276dffa6..c11ca7d57b9 100644 --- a/source/blender/alembic/intern/abc_nurbs.cc +++ b/source/blender/alembic/intern/abc_nurbs.cc @@ -23,9 +23,9 @@ #include "abc_transform.h" #include "abc_util.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "DNA_curve_types.h" #include "DNA_object_types.h" diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 5efa8c8a446..5519cbef53c 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -32,9 +32,9 @@ #include "abc_transform.h" #include "abc_util.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "DNA_cachefile_types.h" #include "DNA_curve_types.h" #include "DNA_modifier_types.h" diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 10bb1bd3c9c..2b592c9e550 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -935,10 +935,7 @@ void blf_draw_buffer__start(FontBLF *font) { FontBufInfoBLF *buf_info = &font->buf_info; - buf_info->col_char[0] = buf_info->col_init[0] * 255; - buf_info->col_char[1] = buf_info->col_init[1] * 255; - buf_info->col_char[2] = buf_info->col_init[2] * 255; - buf_info->col_char[3] = buf_info->col_init[3] * 255; + rgba_float_to_uchar(buf_info->col_char, buf_info->col_init); if (buf_info->display) { copy_v4_v4(buf_info->col_float, buf_info->col_init); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 963e3158d46..9da17d777cd 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -249,6 +249,10 @@ typedef enum eAnimData_Recalc { ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM), } eAnimData_Recalc; +bool BKE_animsys_store_rna_setting(struct PointerRNA *ptr, + const char *rna_path, + const int array_index, + struct PathResolvedRNA *r_result); bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value); bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 75e14b7efca..2acef7847bc 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -26,8 +26,8 @@ * * \note Use #STRINGIFY() rather than defining with quotes. */ -#define BLENDER_VERSION 282 -#define BLENDER_SUBVERSION 6 +#define BLENDER_VERSION 283 +#define BLENDER_SUBVERSION 2 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 @@ -36,7 +36,7 @@ /** Can be left blank, otherwise a,b,c... etc with no quotes. */ #define BLENDER_VERSION_CHAR /** alpha/beta/rc/release, docs use this. */ -#define BLENDER_VERSION_CYCLE beta +#define BLENDER_VERSION_CYCLE alpha /** Optionally set to 1,2,... for example to get alpha1 or rc2. */ #define BLENDER_VERSION_CYCLE_NUMBER diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 17de53be42a..2862dda8ead 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -74,11 +74,11 @@ typedef struct ClothSolverResult { * own connectivity of the mesh based on the actual edges in the mesh. */ typedef struct Cloth { - struct ClothVertex *verts; /* The vertices that represent this cloth. */ - struct LinkNode *springs; /* The springs connecting the mesh. */ - unsigned int numsprings; /* The count of springs. */ - unsigned int mvert_num; /* The number of verts == m * n. */ - unsigned int tri_num; + struct ClothVertex *verts; /* The vertices that represent this cloth. */ + struct LinkNode *springs; /* The springs connecting the mesh. */ + unsigned int numsprings; /* The count of springs. */ + unsigned int mvert_num; /* The number of verts == m * n. */ + unsigned int primitive_num; /* Number of triangles for cloth and edges for hair. */ unsigned char old_solver_type; /* unused, only 1 solver here */ unsigned char pad2; short pad3; @@ -89,6 +89,7 @@ typedef struct Cloth { struct EdgeSet *edgeset; /* used for selfcollisions */ int last_frame; float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */ + struct MEdge *edges; /* Used for hair collisions. */ } Cloth; /** @@ -265,15 +266,6 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph, float step, float dt); -void cloth_find_point_contacts(struct Depsgraph *depsgraph, - struct Object *ob, - struct ClothModifierData *clmd, - float step, - float dt, - ColliderContacts **r_collider_contacts, - int *r_totcolliders); -void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders); - //////////////////////////////////////////////// ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h index bd442c97000..153ad9bb915 100644 --- a/source/blender/blenkernel/BKE_lightprobe.h +++ b/source/blender/blenkernel/BKE_lightprobe.h @@ -29,6 +29,7 @@ struct LightProbe; struct Main; void BKE_lightprobe_init(struct LightProbe *probe); +void BKE_lightprobe_type_set(struct LightProbe *probe, const short lightprobe_type); void *BKE_lightprobe_add(struct Main *bmain, const char *name); void BKE_lightprobe_copy_data(struct Main *bmain, struct LightProbe *probe_dst, diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index ec6ec027810..54cd172655e 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -66,7 +66,6 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_free(struct Object *ob); void BKE_object_free_derived_caches(struct Object *ob); -void BKE_object_free_derived_mesh_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index b1186564dbd..bc312c7bb2b 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -507,6 +507,7 @@ enum { SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT, SEQ_SIDE_BOTH, + SEQ_SIDE_NO_CHANGE, }; int BKE_sequencer_find_next_prev_edit(struct Scene *scene, int cfra, diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 32420e2e894..be6622e5d42 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1665,11 +1665,11 @@ void BKE_keyingsets_free(ListBase *list) /* ***************************************** */ /* Evaluation Data-Setting Backend */ -static bool animsys_store_rna_setting(PointerRNA *ptr, - /* typically 'fcu->rna_path', 'fcu->array_index' */ - const char *rna_path, - const int array_index, - PathResolvedRNA *r_result) +bool BKE_animsys_store_rna_setting(PointerRNA *ptr, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, + const int array_index, + PathResolvedRNA *r_result) { bool success = false; const char *path = rna_path; @@ -1880,7 +1880,7 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr, } PathResolvedRNA orig_anim_rna; /* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */ - if (animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { + if (BKE_animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { BKE_animsys_write_rna_setting(&orig_anim_rna, value); } } @@ -1910,7 +1910,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, continue; } PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); BKE_animsys_write_rna_setting(&anim_rna, curval); if (flush_to_original) { @@ -1944,7 +1944,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime * NOTE: for 'layering' option later on, we should check if we should remove old value * before adding new to only be done when drivers only changed. */ PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); ok = BKE_animsys_write_rna_setting(&anim_rna, curval); } @@ -2023,7 +2023,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); BKE_animsys_write_rna_setting(&anim_rna, curval); } @@ -3803,7 +3803,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* for each override, simply execute... */ for (aor = adt->overrides.first; aor; aor = aor->next) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { BKE_animsys_write_rna_setting(&anim_rna, aor->value); } } @@ -4125,7 +4125,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu // printf("\told val = %f\n", fcu->curval); PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { /* Evaluate driver, and write results to COW-domain destination */ const float ctime = DEG_get_ctime(depsgraph); const float curval = calculate_fcurve(&anim_rna, fcu, ctime); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index c26800aefba..7332c3e0d43 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -190,22 +190,36 @@ static BVHTree *bvhtree_build_from_cloth(ClothModifierData *clmd, float epsilon) vt = cloth->tri; /* in the moment, return zero if no faces there */ - if (!cloth->tri_num) { + if (!cloth->primitive_num) { return NULL; } /* create quadtree with k=26 */ - bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26); + bvhtree = BLI_bvhtree_new(cloth->primitive_num, epsilon, 4, 26); /* fill tree */ - for (i = 0; i < cloth->tri_num; i++, vt++) { - float co[3][3]; + if (clmd->hairdata == NULL) { + for (i = 0; i < cloth->primitive_num; i++, vt++) { + float co[3][3]; - copy_v3_v3(co[0], verts[vt->tri[0]].xold); - copy_v3_v3(co[1], verts[vt->tri[1]].xold); - copy_v3_v3(co[2], verts[vt->tri[2]].xold); + copy_v3_v3(co[0], verts[vt->tri[0]].xold); + copy_v3_v3(co[1], verts[vt->tri[1]].xold); + copy_v3_v3(co[2], verts[vt->tri[2]].xold); - BLI_bvhtree_insert(bvhtree, i, co[0], 3); + BLI_bvhtree_insert(bvhtree, i, co[0], 3); + } + } + else { + MEdge *edges = cloth->edges; + + for (i = 0; i < cloth->primitive_num; i++) { + float co[2][3]; + + copy_v3_v3(co[0], verts[edges[i].v1].xold); + copy_v3_v3(co[1], verts[edges[i].v2].xold); + + BLI_bvhtree_insert(bvhtree, i, co[0], 2); + } } /* balance tree */ @@ -222,6 +236,8 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) ClothVertex *verts = cloth->verts; const MVertTri *vt; + BLI_assert(!(clmd->hairdata != NULL && self)); + if (self) { bvhtree = cloth->bvhselftree; } @@ -236,39 +252,59 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) vt = cloth->tri; /* update vertex position in bvh tree */ - if (verts && vt) { - for (i = 0; i < cloth->tri_num; i++, vt++) { - float co[3][3], co_moving[3][3]; - bool ret; - - /* copy new locations into array */ - if (moving) { - copy_v3_v3(co[0], verts[vt->tri[0]].txold); - copy_v3_v3(co[1], verts[vt->tri[1]].txold); - copy_v3_v3(co[2], verts[vt->tri[2]].txold); - - /* update moving positions */ - copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); - copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); - copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx); - - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); - } - else { - copy_v3_v3(co[0], verts[vt->tri[0]].tx); - copy_v3_v3(co[1], verts[vt->tri[1]].tx); - copy_v3_v3(co[2], verts[vt->tri[2]].tx); + if (clmd->hairdata == NULL) { + if (verts && vt) { + for (i = 0; i < cloth->primitive_num; i++, vt++) { + float co[3][3], co_moving[3][3]; + bool ret; + + /* copy new locations into array */ + if (moving) { + copy_v3_v3(co[0], verts[vt->tri[0]].txold); + copy_v3_v3(co[1], verts[vt->tri[1]].txold); + copy_v3_v3(co[2], verts[vt->tri[2]].txold); + + /* update moving positions */ + copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); + copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); + copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx); + + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); + } + else { + copy_v3_v3(co[0], verts[vt->tri[0]].tx); + copy_v3_v3(co[1], verts[vt->tri[1]].tx); + copy_v3_v3(co[2], verts[vt->tri[2]].tx); - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); - } + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); + } - /* check if tree is already full */ - if (ret == false) { - break; + /* check if tree is already full */ + if (ret == false) { + break; + } } + + BLI_bvhtree_update_tree(bvhtree); } + } + else { + if (verts) { + MEdge *edges = cloth->edges; + + for (i = 0; i < cloth->primitive_num; i++) { + float co[2][3]; - BLI_bvhtree_update_tree(bvhtree); + copy_v3_v3(co[0], verts[edges[i].v1].tx); + copy_v3_v3(co[1], verts[edges[i].v2].tx); + + if (!BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 2)) { + break; + } + } + + BLI_bvhtree_update_tree(bvhtree); + } } } @@ -900,7 +936,13 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) } /* save face information */ - clmd->clothObject->tri_num = looptri_num; + if (clmd->hairdata == NULL) { + clmd->clothObject->primitive_num = looptri_num; + } + else { + clmd->clothObject->primitive_num = mesh->totedge; + } + clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris"); if (clmd->clothObject->tri == NULL) { cloth_free_modifier(clmd); @@ -910,6 +952,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) } BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num); + clmd->clothObject->edges = mesh->medge; + /* Free the springs since they can't be correct if the vertices * changed. */ diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 220b9417a6c..5db42618a9e 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_task.h" #include "BLI_threads.h" @@ -193,17 +194,17 @@ BLI_INLINE int next_ind(int i) return (++i < 3) ? i : 0; } -static float compute_collision_point(float a1[3], - const float a2[3], - const float a3[3], - const float b1[3], - const float b2[3], - const float b3[3], - bool culling, - bool use_normal, - float r_a[3], - float r_b[3], - float r_vec[3]) +static float compute_collision_point_tri_tri(const float a1[3], + const float a2[3], + const float a3[3], + const float b1[3], + const float b2[3], + const float b3[3], + bool culling, + bool use_normal, + float r_a[3], + float r_b[3], + float r_vec[3]) { float a[3][3]; float b[3][3]; @@ -423,6 +424,179 @@ static float compute_collision_point(float a1[3], return dist; } +static float compute_collision_point_edge_tri(const float a1[3], + const float a2[3], + const float b1[3], + const float b2[3], + const float b3[3], + bool culling, + bool use_normal, + float r_a[3], + float r_b[3], + float r_vec[3]) +{ + float a[2][3]; + float b[3][3]; + float dist = FLT_MAX; + float tmp_co1[3], tmp_co2[3]; + float isect_a[3]; + bool isect = false; + float tmp, tmp_vec[3]; + float normal[3], cent[3]; + bool backside = false; + + copy_v3_v3(a[0], a1); + copy_v3_v3(a[1], a2); + + copy_v3_v3(b[0], b1); + copy_v3_v3(b[1], b2); + copy_v3_v3(b[2], b3); + + normal_tri_v3(normal, b[0], b[1], b[2]); + + /* Find intersection. */ + if (isect_line_segment_tri_v3(a[0], a[1], b[0], b[1], b[2], &tmp, NULL)) { + interp_v3_v3v3(isect_a, a[0], a[1], tmp); + isect = true; + } + + /* Determine collision side. */ + if (culling) { + if (isect) { + backside = true; + } + else { + mid_v3_v3v3v3(cent, b[0], b[1], b[2]); + + for (int i = 0; i < 2; i++) { + sub_v3_v3v3(tmp_vec, a[i], cent); + if (dot_v3v3(tmp_vec, normal) < 0.0f) { + backside = true; + break; + } + } + } + } + + if (isect) { + /* Edge intersection. */ + copy_v3_v3(r_a, isect_a); + copy_v3_v3(r_b, isect_a); + + copy_v3_v3(r_vec, normal); + + return 0.0f; + } + + if (backside) { + float maxdist = 0.0f; + bool found = false; + + /* Point projections. */ + for (int i = 0; i < 2; i++) { + if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) { + if (tmp > maxdist) { + maxdist = tmp; + copy_v3_v3(r_a, a[i]); + madd_v3_v3v3fl(r_b, a[i], normal, tmp); + found = true; + } + } + } + + /* Edge projections. */ + for (int i = 0; i < 3; i++) { + float dir[3]; + + sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]); + cross_v3_v3v3(dir, tmp_vec, normal); + + if (isect_line_plane_v3(tmp_co1, a[0], a[1], b[i], dir) && + point_in_slice_seg(tmp_co1, a[0], a[1]) && + point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) { + closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]); + sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2); + tmp = len_v3(tmp_vec); + + if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) { + maxdist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + found = true; + } + } + } + + /* If no point is found, will fallback onto regular proximity test below. */ + if (found) { + sub_v3_v3v3(r_vec, r_b, r_a); + + if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + + return 0.0f; + } + } + + /* Closest point. */ + for (int i = 0; i < 2; i++) { + closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]); + tmp = len_squared_v3v3(tmp_co1, a[i]); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, a[i]); + copy_v3_v3(r_b, tmp_co1); + } + } + + /* Closest edge. */ + if (!isect) { + for (int j = 0; j < 3; j++) { + isect_seg_seg_v3(a[0], a[1], b[j], b[next_ind(j)], tmp_co1, tmp_co2); + tmp = len_squared_v3v3(tmp_co1, tmp_co2); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + } + } + } + + if (isect) { + sub_v3_v3v3(r_vec, r_b, r_a); + dist = 0.0f; + } + else { + sub_v3_v3v3(r_vec, r_a, r_b); + dist = sqrtf(dist); + } + + if (culling && use_normal) { + copy_v3_v3(r_vec, normal); + } + else if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) { + return FLT_MAX; + } + + return dist; +} + // w3 is not perfect static void collision_compute_barycentric( const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3) @@ -494,6 +668,7 @@ static int cloth_collision_response_static(ClothModifierData *clmd, float v1[3], v2[3], relativeVelocity[3]; float magrelVel; float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + const bool is_hair = (clmd->hairdata != NULL); cloth1 = clmd->clothObject; @@ -509,14 +684,32 @@ static int cloth_collision_response_static(ClothModifierData *clmd, continue; } - /* Compute barycentric coordinates for both collision points. */ - collision_compute_barycentric(collpair->pa, - cloth1->verts[collpair->ap1].tx, - cloth1->verts[collpair->ap2].tx, - cloth1->verts[collpair->ap3].tx, - &w1, - &w2, - &w3); + /* Compute barycentric coordinates and relative "velocity" for both collision points. */ + if (is_hair) { + w2 = line_point_factor_v3( + collpair->pa, cloth1->verts[collpair->ap1].tx, cloth1->verts[collpair->ap2].tx); + + w1 = 1.0f - w2; + + interp_v3_v3v3(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w2); + } + else { + collision_compute_barycentric(collpair->pa, + cloth1->verts[collpair->ap1].tx, + cloth1->verts[collpair->ap2].tx, + cloth1->verts[collpair->ap3].tx, + &w1, + &w2, + &w3); + + collision_interpolateOnTriangle(v1, + cloth1->verts[collpair->ap1].tv, + cloth1->verts[collpair->ap2].tv, + cloth1->verts[collpair->ap3].tv, + w1, + w2, + w3); + } collision_compute_barycentric(collpair->pb, collmd->current_xnew[collpair->bp1].co, @@ -526,15 +719,6 @@ static int cloth_collision_response_static(ClothModifierData *clmd, &u2, &u3); - /* Calculate relative "velocity". */ - collision_interpolateOnTriangle(v1, - cloth1->verts[collpair->ap1].tv, - cloth1->verts[collpair->ap2].tv, - cloth1->verts[collpair->ap3].tv, - w1, - w2, - w3); - collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, @@ -576,7 +760,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, vrel_t_pre, w1 * impulse); VECADDMUL(i2, vrel_t_pre, w2 * impulse); - VECADDMUL(i3, vrel_t_pre, w3 * impulse); + + if (!is_hair) { + VECADDMUL(i3, vrel_t_pre, w3 * impulse); + } } /* Apply velocity stopping impulse. */ @@ -588,8 +775,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i2, collpair->normal, w2 * impulse); cloth1->verts[collpair->ap2].impulse_count++; - VECADDMUL(i3, collpair->normal, w3 * impulse); - cloth1->verts[collpair->ap3].impulse_count++; + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); + cloth1->verts[collpair->ap3].impulse_count++; + } time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); @@ -609,7 +798,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, impulse); VECADDMUL(i2, collpair->normal, impulse); - VECADDMUL(i3, collpair->normal, impulse); + + if (!is_hair) { + VECADDMUL(i3, collpair->normal, impulse); + } } result = 1; @@ -627,11 +819,17 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, w1 * impulse); VECADDMUL(i2, collpair->normal, w2 * impulse); - VECADDMUL(i3, collpair->normal, w3 * impulse); + + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); + } cloth1->verts[collpair->ap1].impulse_count++; cloth1->verts[collpair->ap2].impulse_count++; - cloth1->verts[collpair->ap3].impulse_count++; + + if (!is_hair) { + cloth1->verts[collpair->ap3].impulse_count++; + } result = 1; } @@ -656,9 +854,11 @@ static int cloth_collision_response_static(ClothModifierData *clmd, cloth1->verts[collpair->ap2].impulse[j] = i2[j]; } - if (cloth1->verts[collpair->ap3].impulse_count > 0 && - ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) { - cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + if (!is_hair) { + if (cloth1->verts[collpair->ap3].impulse_count > 0 && + ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) { + cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + } } } } @@ -875,17 +1075,17 @@ static void cloth_collision(void *__restrict userdata, tri_b = &collmd->tri[data->overlap[index].indexB]; /* Compute distance and normal. */ - distance = compute_collision_point(verts1[tri_a->tri[0]].tx, - verts1[tri_a->tri[1]].tx, - verts1[tri_a->tri[2]].tx, - collmd->current_xnew[tri_b->tri[0]].co, - collmd->current_xnew[tri_b->tri[1]].co, - collmd->current_xnew[tri_b->tri[2]].co, - data->culling, - data->use_normal, - pa, - pb, - vect); + distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, + verts1[tri_a->tri[1]].tx, + verts1[tri_a->tri[2]].tx, + collmd->current_xnew[tri_b->tri[0]].co, + collmd->current_xnew[tri_b->tri[1]].co, + collmd->current_xnew[tri_b->tri[2]].co, + data->culling, + data->use_normal, + pa, + pb, + vect); if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { collpair[index].ap1 = tri_a->tri[0]; @@ -946,17 +1146,17 @@ static void cloth_selfcollision(void *__restrict userdata, } /* Compute distance and normal. */ - distance = compute_collision_point(verts1[tri_a->tri[0]].tx, - verts1[tri_a->tri[1]].tx, - verts1[tri_a->tri[2]].tx, - verts1[tri_b->tri[0]].tx, - verts1[tri_b->tri[1]].tx, - verts1[tri_b->tri[2]].tx, - false, - false, - pa, - pb, - vect); + distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, + verts1[tri_a->tri[1]].tx, + verts1[tri_a->tri[2]].tx, + verts1[tri_b->tri[0]].tx, + verts1[tri_b->tri[1]].tx, + verts1[tri_b->tri[2]].tx, + false, + false, + pa, + pb, + vect); if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { collpair[index].ap1 = tri_a->tri[0]; @@ -983,6 +1183,64 @@ static void cloth_selfcollision(void *__restrict userdata, } } +static void hair_collision(void *__restrict userdata, + const int index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + ColDetectData *data = (ColDetectData *)userdata; + + ClothModifierData *clmd = data->clmd; + CollisionModifierData *collmd = data->collmd; + CollPair *collpair = data->collisions; + const MVertTri *tri_coll; + const MEdge *edge_coll; + ClothVertex *verts1 = clmd->clothObject->verts; + float distance = 0.0f; + float epsilon1 = clmd->coll_parms->epsilon; + float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + float pa[3], pb[3], vect[3]; + + /* TODO: This is not efficient. Might be wise to instead build an array before iterating, to + * avoid walking the list every time. */ + edge_coll = &clmd->clothObject->edges[data->overlap[index].indexA]; + tri_coll = &collmd->tri[data->overlap[index].indexB]; + + /* Compute distance and normal. */ + distance = compute_collision_point_edge_tri(verts1[edge_coll->v1].tx, + verts1[edge_coll->v2].tx, + collmd->current_x[tri_coll->tri[0]].co, + collmd->current_x[tri_coll->tri[1]].co, + collmd->current_x[tri_coll->tri[2]].co, + data->culling, + data->use_normal, + pa, + pb, + vect); + + if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { + collpair[index].ap1 = edge_coll->v1; + collpair[index].ap2 = edge_coll->v2; + + collpair[index].bp1 = tri_coll->tri[0]; + collpair[index].bp2 = tri_coll->tri[1]; + collpair[index].bp3 = tri_coll->tri[2]; + + copy_v3_v3(collpair[index].pa, pa); + copy_v3_v3(collpair[index].pb, pb); + copy_v3_v3(collpair[index].vector, vect); + + normalize_v3_v3(collpair[index].normal, collpair[index].vector); + + collpair[index].distance = distance; + collpair[index].flag = 0; + + data->collided = true; + } + else { + collpair[index].flag = COLLISION_INACTIVE; + } +} + static void add_collision_object(ListBase *relations, Object *ob, int level, @@ -1148,6 +1406,7 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd, bool culling, bool use_normal) { + const bool is_hair = (clmd->hairdata != NULL); *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array"); ColDetectData data = { @@ -1163,7 +1422,8 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd, TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = true; - BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings); + BLI_task_parallel_range( + 0, numresult, &data, is_hair ? hair_collision : cloth_collision, &settings); return data.collided; } @@ -1308,8 +1568,14 @@ int cloth_bvh_collision( if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { bvhtree_update_from_cloth(clmd, false, false); - collobjs = BKE_collision_objects_create( - depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); + /* Enable self collision if this is a hair sim */ + const bool is_hair = (clmd->hairdata != NULL); + + collobjs = BKE_collision_objects_create(depsgraph, + is_hair ? NULL : ob, + clmd->coll_parms->group, + &numcollobj, + eModifierType_Collision); if (collobjs) { coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts"); @@ -1474,286 +1740,3 @@ void collision_get_collider_velocity(float vel_old[3], /* XXX assume constant velocity of the collider for now */ copy_v3_v3(vel_old, vel_new); } - -BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], - const float p2[3], - const float v0[3], - const float v1[3], - const float v2[3], - float r_nor[3], - float *r_lambda, - float r_w[3]) -{ - float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3]; - float nor_v0p2, nor_p1p2; - - sub_v3_v3v3(edge1, v1, v0); - sub_v3_v3v3(edge2, v2, v0); - cross_v3_v3v3(r_nor, edge1, edge2); - normalize_v3(r_nor); - - sub_v3_v3v3(v0p2, p2, v0); - nor_v0p2 = dot_v3v3(v0p2, r_nor); - madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2); - interp_weights_tri_v3(r_w, v0, v1, v2, p2face); - - sub_v3_v3v3(p1p2, p2, p1); - nor_p1p2 = dot_v3v3(p1p2, r_nor); - *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f); - - return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f; -} - -static CollPair *cloth_point_collpair(float p1[3], - const float p2[3], - const MVert *mverts, - int bp1, - int bp2, - int bp3, - int index_cloth, - int index_coll, - float epsilon, - CollPair *collpair) -{ - const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co; - float lambda /*, distance1 */, distance2; - float facenor[3], v1p1[3], v1p2[3]; - float w[3]; - - if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) { - return collpair; - } - - sub_v3_v3v3(v1p1, p1, co1); - // distance1 = dot_v3v3(v1p1, facenor); - sub_v3_v3v3(v1p2, p2, co1); - distance2 = dot_v3v3(v1p2, facenor); - // if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f)) - if (distance2 > epsilon) { - return collpair; - } - - collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */ - collpair->face2 = index_coll; - collpair->ap1 = index_cloth; - collpair->ap2 = collpair->ap3 = -1; /* unused */ - collpair->bp1 = bp1; - collpair->bp2 = bp2; - collpair->bp3 = bp3; - - /* note: using the second point here, which is - * the current updated position that needs to be corrected - */ - copy_v3_v3(collpair->pa, p2); - collpair->distance = distance2; - mul_v3_v3fl(collpair->vector, facenor, -distance2); - - interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w); - - copy_v3_v3(collpair->normal, facenor); - collpair->time = lambda; - collpair->flag = 0; - - collpair++; - return collpair; -} - -/* Determines collisions on overlap, - * collisions are written to collpair[i] and collision+number_collision_found is returned. */ -static CollPair *cloth_point_collision(ModifierData *md1, - ModifierData *md2, - BVHTreeOverlap *overlap, - float epsilon, - CollPair *collpair, - float UNUSED(dt)) -{ - ClothModifierData *clmd = (ClothModifierData *)md1; - CollisionModifierData *collmd = (CollisionModifierData *)md2; - /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */ - ClothVertex *vert = NULL; - const MVertTri *vt; - const MVert *mverts = collmd->current_x; - - vert = &clmd->clothObject->verts[overlap->indexA]; - vt = &collmd->tri[overlap->indexB]; - - collpair = cloth_point_collpair(vert->tx, - vert->x, - mverts, - vt->tri[0], - vt->tri[1], - vt->tri[2], - overlap->indexA, - overlap->indexB, - epsilon, - collpair); - - return collpair; -} - -static void cloth_points_objcollisions_nearcheck(ClothModifierData *clmd, - CollisionModifierData *collmd, - CollPair **collisions, - CollPair **collisions_index, - int numresult, - BVHTreeOverlap *overlap, - float epsilon, - double dt) -{ - int i; - - /* can return 2 collisions in total */ - *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array"); - *collisions_index = *collisions; - - for (i = 0; i < numresult; i++) { - *collisions_index = cloth_point_collision( - (ModifierData *)clmd, (ModifierData *)collmd, overlap + i, epsilon, *collisions_index, dt); - } -} - -void cloth_find_point_contacts(Depsgraph *depsgraph, - Object *ob, - ClothModifierData *clmd, - float step, - float dt, - ColliderContacts **r_collider_contacts, - int *r_totcolliders) -{ - Cloth *cloth = clmd->clothObject; - BVHTree *cloth_bvh; - unsigned int i = 0, mvert_num = 0; - ClothVertex *verts = NULL; - - ColliderContacts *collider_contacts; - - Object **collobjs = NULL; - unsigned int numcollobj = 0; - - verts = cloth->verts; - mvert_num = cloth->mvert_num; - - //////////////////////////////////////////////////////////// - // static collisions - //////////////////////////////////////////////////////////// - - /* Check we do have collision objects to test against, before doing anything else. */ - collobjs = BKE_collision_objects_create( - depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); - if (!collobjs) { - *r_collider_contacts = NULL; - *r_totcolliders = 0; - return; - } - - // create temporary cloth points bvh - cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6); - /* fill tree */ - for (i = 0; i < mvert_num; i++) { - float co[6]; - - copy_v3_v3(&co[0 * 3], verts[i].x); - copy_v3_v3(&co[1 * 3], verts[i].tx); - - BLI_bvhtree_insert(cloth_bvh, i, co, 2); - } - /* balance tree */ - BLI_bvhtree_balance(cloth_bvh); - - /* move object to position (step) in time */ - for (i = 0; i < numcollobj; i++) { - Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( - collob, eModifierType_Collision); - if (!collmd->bvhtree) { - continue; - } - - /* move object to position (step) in time */ - collision_move_object(collmd, step + dt, step, true); - } - - collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair"); - - // check all collision objects - for (i = 0; i < numcollobj; i++) { - ColliderContacts *ct = collider_contacts + i; - Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( - collob, eModifierType_Collision); - BVHTreeOverlap *overlap; - unsigned int result = 0; - float epsilon; - - ct->ob = collob; - ct->collmd = collmd; - ct->collisions = NULL; - ct->totcollisions = 0; - - if (!collmd->bvhtree) { - continue; - } - - /* search for overlapping collision pairs */ - overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL); - epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree); - - // go to next object if no overlap is there - if (result && overlap) { - CollPair *collisions_index; - - /* check if collisions really happen (costly near check) */ - cloth_points_objcollisions_nearcheck( - clmd, collmd, &ct->collisions, &collisions_index, result, overlap, epsilon, dt); - ct->totcollisions = (int)(collisions_index - ct->collisions); - - /* Resolve nearby collisions. */ -#if 0 - ret += cloth_points_objcollisions_resolve( - clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt); -#endif - } - - if (overlap) { - MEM_freeN(overlap); - } - } - - BKE_collision_objects_free(collobjs); - - BLI_bvhtree_free(cloth_bvh); - - //////////////////////////////////////////////////////////// - // update positions - // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] - //////////////////////////////////////////////////////////// - - // verts come from clmd - for (i = 0; i < mvert_num; i++) { - if (clmd->sim_parms->vgroup_mass > 0) { - if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { - continue; - } - } - - add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv); - } - //////////////////////////////////////////////////////////// - - *r_collider_contacts = collider_contacts; - *r_totcolliders = numcollobj; -} - -void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders) -{ - if (collider_contacts) { - int i; - for (i = 0; i < totcolliders; i++) { - ColliderContacts *ct = collider_contacts + i; - if (ct->collisions) { - MEM_freeN(ct->collisions); - } - } - MEM_freeN(collider_contacts); - } -} diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 33f9b5b1012..85b58da61de 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -81,17 +81,16 @@ static void set_crazy_vertex_quat(float r_quat[4], sub_qt_qtqt(r_quat, q2, q1); } -static int modifiers_disable_subsurf_temporary(Object *ob) +static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) { - ModifierData *md; - int disabled = 0; + bool disabled = false; + int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); - for (md = ob->modifiers.first; md; md = md->next) { + ModifierData *md = ob->modifiers.first; + for (int i = 0; md && i <= cageIndex; i++, md = md->next) { if (md->type == eModifierType_Subsurf) { - if (md->mode & eModifierMode_OnCage) { - md->mode ^= eModifierMode_DisableTemporary; - disabled = 1; - } + md->mode ^= eModifierMode_DisableTemporary; + disabled = true; } } @@ -108,7 +107,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object BMEditMesh *editmesh_eval = mesh_eval->edit_mesh; /* disable subsurf temporal, get mapped cos, and enable it */ - if (modifiers_disable_subsurf_temporary(obedit_eval)) { + if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) { /* need to make new derivemesh */ makeDerivedMesh(depsgraph, scene_eval, obedit_eval, editmesh_eval, &CD_MASK_BAREMESH); } @@ -122,7 +121,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object mesh_get_mapped_verts_coords(mesh_eval_cage, vertexcos, nverts); /* set back the flag, no new cage needs to be built, transform does it */ - modifiers_disable_subsurf_temporary(obedit_eval); + modifiers_disable_subsurf_temporary(scene_eval, obedit_eval); return vertexcos; } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 12bb7b573bd..4f0ff8bdcd3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1805,91 +1805,88 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp) } } else { - short dnr; - - /* bevel now in three parts, for proper vertex normals */ - /* part 1, back */ - - if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; - } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->flag = DL_BACK_CURVE; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - dangle = ((float)M_PI_2 / (dnr - 1)); - angle = -(nr - 1) * dangle; - - for (a = 0; a < nr; a++) { + /* The general case for nonzero extrusion or an incomplete loop. */ + dl = MEM_callocN(sizeof(DispList), "makebevelcurve"); + if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { + /* The full loop. */ + nr = 4 * cu->bevresol + 6; + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + } + else if ((cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) { + /* Half the loop. */ + nr = 2 * (cu->bevresol + 1) + ((cu->ext1 == 0.0f) ? 1 : 2); + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + } + else { + /* One quarter of the loop (just front or back). */ + nr = (cu->ext1 == 0.0f) ? cu->bevresol + 2 : cu->bevresol + 3; + dl->flag = (cu->flag & CU_FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE; + } + + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve"); + BLI_addtail(disp, dl); + /* Use a different type depending on whether the loop is complete or not. */ + dl->type = ((cu->flag & (CU_FRONT | CU_BACK)) == 0) ? DL_POLY : DL_SEGM; + dl->parts = 1; + dl->nr = nr; + + fp = dl->verts; + dangle = (float)M_PI_2 / (cu->bevresol + 1); + angle = 0.0; + + /* Build the back section. */ + if (cu->flag & CU_BACK || !(cu->flag & CU_FRONT)) { + angle = (float)M_PI_2 * 3.0f; + for (a = 0; a < cu->bevresol + 2; a++) { fp[0] = 0.0; fp[1] = (float)(cosf(angle) * (cu->ext2)); fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; angle += dangle; fp += 3; } + if ((cu->ext1 != 0.0f) && !(cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) { + /* Add the extrusion if we're only building the back. */ + fp[0] = 0.0; + fp[1] = cu->ext2; + fp[2] = cu->ext1; + } } - /* part 2, sidefaces */ - if (cu->ext1 != 0.0f) { - nr = 2; - - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->nr = nr; - - fp = dl->verts; - fp[1] = cu->ext2; - fp[2] = -cu->ext1; - fp[4] = cu->ext2; - fp[5] = cu->ext1; - - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - dl = MEM_dupallocN(dl); - dl->verts = MEM_dupallocN(dl->verts); - BLI_addtail(disp, dl); - - fp = dl->verts; - fp[1] = -fp[1]; - fp[2] = -fp[2]; - fp[4] = -fp[4]; - fp[5] = -fp[5]; + /* Build the front section. */ + if (cu->flag & CU_FRONT || !(cu->flag & CU_BACK)) { + if ((cu->ext1 != 0.0f) && !(cu->flag & CU_BACK) && (cu->flag & CU_FRONT)) { + /* Add the extrusion if we're only building the back. */ + fp[0] = 0.0; + fp[1] = cu->ext2; + fp[2] = -cu->ext1; + fp += 3; + } + /* Don't duplicate the last back vertex. */ + angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0; + for (a = 0; a < cu->bevresol + 2; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; } } - /* part 3, front */ - if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; + /* Build the other half only if we're building the full loop. */ + if (!(cu->flag & (CU_FRONT | CU_BACK))) { + for (a = 0; a < cu->bevresol + 1; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->flag = DL_FRONT_CURVE; - dl->parts = 1; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - angle = 0.0; - dangle = ((float)M_PI_2 / (dnr - 1)); - for (a = 0; a < nr; a++) { + angle = (float)M_PI; + for (a = 0; a < cu->bevresol + 1; a++) { fp[0] = 0.0; fp[1] = (float)(cosf(angle) * (cu->ext2)); - fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; angle += dangle; fp += 3; } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index fe1f9097562..be354b04157 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1345,6 +1345,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) /* bw */ switch (imtype) { + case R_IMF_IMTYPE_BMP: case R_IMF_IMTYPE_PNG: case R_IMF_IMTYPE_JPEG90: case R_IMF_IMTYPE_TARGA: diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 974d6328fcb..5fd852ff089 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -340,7 +340,7 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas FOREACH_FINALIZE_VOID; } -/* Used by both real Collection data-blokcs, and the fake horror of master collection from Scene. +/* Used by both real Collection data-blocks, and the fake horror of master collection from Scene. */ static void library_foreach_collection(LibraryForeachIDData *data, Collection *collection) { diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index 06f1ee5050b..3cba3aa9611 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -41,6 +41,30 @@ void BKE_lightprobe_init(LightProbe *probe) MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id); } +void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type) +{ + probe->type = lightprobe_type; + + switch (probe->type) { + case LIGHTPROBE_TYPE_GRID: + probe->distinf = 0.3f; + probe->falloff = 1.0f; + probe->clipsta = 0.01f; + break; + case LIGHTPROBE_TYPE_PLANAR: + probe->distinf = 0.1f; + probe->falloff = 0.5f; + probe->clipsta = 0.001f; + break; + case LIGHTPROBE_TYPE_CUBE: + probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID; + break; + default: + BLI_assert(!"LightProbe type not configured."); + break; + } +} + void *BKE_lightprobe_add(Main *bmain, const char *name) { LightProbe *probe; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index a539aa45cf6..23fa8dd60d5 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1289,13 +1289,9 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) int i, j, numGrids, highGridSize, lowGridSize; const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - /* create subsurf DM from original mesh at high level */ - if (ob->derivedDeform) { - cddm = CDDM_copy(ob->derivedDeform); - } - else { - cddm = CDDM_from_mesh(me); - } + /* Create subsurf DM from original mesh at high level. */ + /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */ + cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, &CD_MASK_BAREMESH); highdm = subsurf_dm_create_local(scene, @@ -1369,12 +1365,8 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) DerivedMesh *cddm, *subdm; const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - if (ob->derivedDeform) { - cddm = CDDM_copy(ob->derivedDeform); - } - else { - cddm = CDDM_from_mesh(me); - } + /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */ + cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, &CD_MASK_BAREMESH); subdm = subsurf_dm_create_local(scene, diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index da3986d33df..90205286a72 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -430,7 +430,6 @@ void BKE_object_free_derived_caches(Object *ob) MEM_SAFE_FREE(ob->runtime.bb); object_update_from_subsurf_ccg(ob); - BKE_object_free_derived_mesh_caches(ob); /* Restore initial pointer. */ if (ob->runtime.mesh_orig != NULL) { @@ -457,20 +456,6 @@ void BKE_object_free_derived_caches(Object *ob) DRW_gpencil_freecache(ob); } -void BKE_object_free_derived_mesh_caches(struct Object *ob) -{ - if (ob->derivedFinal) { - ob->derivedFinal->needsFree = 1; - ob->derivedFinal->release(ob->derivedFinal); - ob->derivedFinal = NULL; - } - if (ob->derivedDeform) { - ob->derivedDeform->needsFree = 1; - ob->derivedDeform->release(ob->derivedDeform); - ob->derivedDeform = NULL; - } -} - void BKE_object_free_caches(Object *object) { ModifierData *md; @@ -804,6 +789,8 @@ static const char *get_obdata_defname(int type) return DATA_("Empty"); case OB_GPENCIL: return DATA_("GPencil"); + case OB_LIGHTPROBE: + return DATA_("LightProbe"); default: CLOG_ERROR(&LOG, "Internal error, bad type: %d", type); return DATA_("Empty"); @@ -1425,9 +1412,6 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata); - ob_dst->derivedDeform = NULL; - ob_dst->derivedFinal = NULL; - BLI_listbase_clear((ListBase *)&ob_dst->drawdata); BLI_listbase_clear(&ob_dst->pc_ids); diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 3e449fa6b25..f58c20a7d72 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -247,8 +247,12 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain, void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout) { - id_us_min(&layout->screen->id); - BKE_id_free(bmain, layout->screen); + /* Screen should usually be set, but we call this from file reading to get rid of invalid + * layouts. */ + if (layout->screen) { + id_us_min(&layout->screen->id); + BKE_id_free(bmain, layout->screen); + } BLI_freelinkN(&workspace->layouts, layout); } diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index 23a8f775576..2b11213d351 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -39,6 +39,10 @@ bool BLI_rcti_is_empty(const struct rcti *rect); bool BLI_rctf_is_empty(const struct rctf *rect); void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax); void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax); +bool BLI_rctf_is_valid(const struct rctf *rect); +bool BLI_rcti_is_valid(const struct rcti *rect); +void BLI_rctf_sanitize(struct rctf *rect); +void BLI_rcti_sanitize(struct rcti *rect); void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size); void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size); void BLI_rcti_init_minmax(struct rcti *rect); diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c index 4faaf1605e0..118949d1c46 100644 --- a/source/blender/blenlib/intern/delaunay_2d.c +++ b/source/blender/blenlib/intern/delaunay_2d.c @@ -17,8 +17,7 @@ /** \file * \ingroup bli * - * Dynamic Constrained Delaunay Triangulation. - * See paper by Marcelo Kallmann, Hanspeter Bieri, and Daniel Thalmann + * Constrained 2d Delaunay Triangulation. */ #include "MEM_guardedalloc.h" @@ -29,12 +28,11 @@ #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_mempool.h" -#include "BLI_rand.h" #include "BLI_delaunay_2d.h" /* Uncomment this define to get helpful debugging functions etc. defined. */ -// #define DEBUG_CDT +#define DEBUG_CDT struct CDTEdge; struct CDTFace; @@ -53,20 +51,21 @@ typedef struct CDTVert { SymEdge *symedge; /* Some edge attached to it. */ LinkNode *input_ids; /* List of corresponding vertex input ids. */ int index; /* Index into array that cdt keeps. */ - int visit_index; /* Which visit epoch has this been seen. */ + int merge_to_index; /* Index of a CDTVert that this has merged to. -1 if no merge. */ } CDTVert; typedef struct CDTEdge { LinkNode *input_ids; /* List of input edge ids that this is part of. */ SymEdge symedges[2]; /* The directed edges for this edge. */ + bool in_queue; /* Used in flipping algorithm. */ } CDTEdge; typedef struct CDTFace { - double centroid[2]; /* Average of vertex coords. */ SymEdge *symedge; /* A symedge in face; only used during output. */ LinkNode *input_ids; /* List of input face ids that this is part of. */ int visit_index; /* Which visit epoch has this been seen. */ bool deleted; /* Marks this face no longer used. */ + bool in_queue; /* Used in remove_small_features algorithm. */ } CDTFace; typedef struct CDT_state { @@ -76,6 +75,7 @@ typedef struct CDT_state { CDTVert **vert_array; int vert_array_len; int vert_array_len_alloc; + int input_vert_tot; double minx; double miny; double maxx; @@ -83,19 +83,13 @@ typedef struct CDT_state { double margin; int visit_count; int face_edge_offset; - RNG *rng; MemArena *arena; BLI_mempool *listpool; double epsilon; + double epsilon_squared; bool output_prepared; } CDT_state; -typedef struct LocateResult { - enum { OnVert, OnEdge, InFace } loc_kind; - SymEdge *se; - double edge_lambda; -} LocateResult; - #define DLNY_ARENASIZE 1 << 14 /** @@ -105,60 +99,57 @@ typedef struct LocateResult { #define DLNY_MARGIN_PCT 2000.0 #ifdef DEBUG_CDT +# ifdef __GNUC__ +# define ATTU __attribute__((unused)) +# else +# define ATTU +# endif # define F2(p) p[0], p[1] -static void dump_se(const SymEdge *se, const char *lab); -static void dump_v(const CDTVert *v, const char *lab); -static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit); -static void dump_id_list(const LinkNode *id_list, const char *lab); -static void dump_cdt(const CDT_state *cdt, const char *lab); -static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab); -static void cdt_draw(CDT_state *cdt, const char *lab); -static void write_cdt_input_to_file(const CDT_input *inp); -static void validate_face_centroid(SymEdge *se); -static void validate_cdt(CDT_state *cdt, bool check_all_tris); +# define F3(p) p[0], p[1], p[2] +ATTU static void dump_se(const SymEdge *se, const char *lab); +ATTU static void dump_v(const CDTVert *v, const char *lab); +ATTU static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit); +ATTU static void dump_id_list(const LinkNode *id_list, const char *lab); +ATTU static void dump_cdt(const CDT_state *cdt, const char *lab); +ATTU static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab); +ATTU static void cdt_draw(CDT_state *cdt, const char *lab); +ATTU static void cdt_draw_vertex_region(CDT_state *cdt, int v, double dist, const char *lab); +ATTU static void write_cdt_input_to_file(const CDT_input *inp); +ATTU static void validate_cdt(CDT_state *cdt, + bool check_all_tris, + bool check_delaunay, + bool check_visibility); #endif -/** - * Return 1 if a,b,c forms CCW angle, -1 if a CW angle, 0 if straight. - * For straight test, allow b to be withing eps of line. - */ -static int CCW_test(const double a[2], const double b[2], const double c[2], const double eps) +static void exactinit(void); +static double orient2d(const double *pa, const double *pb, const double *pc); +static double incircle(const double *pa, const double *pb, const double *pc, const double *pd); + +/** Return other #SymEdge for same #CDTEdge as se. */ +BLI_INLINE SymEdge *sym(const SymEdge *se) { - double det; - double ab; + return se->next->rot; +} - /* This is twice the signed area of triangle abc. */ - det = (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); - if (eps == 0.0) { - if (det > 0) { - return 1; - } - else if (det < 0) { - return -1; - } - else { - return 0; - } - } - ab = len_v2v2_db(a, b); - if (ab <= eps) { - return 0; - } - det /= ab; - if (det > eps) { - return 1; - } - else if (det < -eps) { - return -1; - } - return 0; +/** Return SymEdge whose next is se. */ +BLI_INLINE SymEdge *prev(const SymEdge *se) +{ + return se->rot->next->rot; } -/** return true if a -- b -- c are in that order, assuming they are on a straight line according to - * CCW_test. */ -static bool in_line(const double a[2], const double b[2], const double c[2], double eps) +/** Return true if a -- b -- c are in that order, assuming they are on a straight line according to + * orient2d and we know the order is either abc or bac. + * This means ab . ac and bc . ac must both be non-negative. */ +static bool in_line(const double a[2], const double b[2], const double c[2]) { - return fabs(len_v2v2_db(a, c) - (len_v2v2_db(a, b) + len_v2v2_db(b, c))) <= eps; + double ab[2], bc[2], ac[2]; + sub_v2_v2v2_db(ab, b, a); + sub_v2_v2v2_db(bc, c, b); + sub_v2_v2v2_db(ac, c, a); + if (dot_v2v2_db(ab, ac) < 0.0) { + return false; + } + return dot_v2v2_db(bc, ac) >= 0.0; } #ifndef NDEBUG @@ -176,21 +167,6 @@ static bool reachable(SymEdge *s1, SymEdge *s2, int limit) } #endif -static void calc_face_centroid(SymEdge *se) -{ - SymEdge *senext; - double *centroidp = se->face->centroid; - int count; - copy_v2_v2_db(centroidp, se->vert->co); - count = 1; - for (senext = se->next; senext != se; senext = senext->next) { - add_v2_v2_db(centroidp, senext->vert->co); - count++; - } - centroidp[0] /= count; - centroidp[1] /= count; -} - /** Using array to store these instead of linked list so can make a random selection from them. */ static CDTVert *add_cdtvert(CDT_state *cdt, double x, double y) { @@ -208,7 +184,7 @@ static CDTVert *add_cdtvert(CDT_state *cdt, double x, double y) } BLI_assert(cdt->vert_array_len < cdt->vert_array_len_alloc); v->index = cdt->vert_array_len; - v->visit_index = 0; + v->merge_to_index = -1; cdt->vert_array[cdt->vert_array_len++] = v; return v; } @@ -220,6 +196,7 @@ static CDTEdge *add_cdtedge( SymEdge *se = &e->symedges[0]; SymEdge *sesym = &e->symedges[1]; e->input_ids = NULL; + e->in_queue = false; BLI_linklist_prepend_arena(&cdt->edges, (void *)e, cdt->arena); se->edge = sesym->edge = e; se->face = fleft; @@ -243,6 +220,7 @@ static CDTFace *add_cdtface(CDT_state *cdt) f->deleted = false; f->symedge = NULL; f->input_ids = NULL; + f->in_queue = false; BLI_linklist_prepend_arena(&cdt->faces, (void *)f, cdt->arena); return f; } @@ -290,37 +268,24 @@ static void add_list_to_input_ids(LinkNode **dst, const LinkNode *src, CDT_state } } -/** Return other #SymEdge for same #CDTEdge as se. */ -static inline SymEdge *sym(const SymEdge *se) -{ - return se->next->rot; -} - -/** Return SymEdge whose next is se. */ -static inline SymEdge *prev(const SymEdge *se) -{ - return se->rot->next->rot; -} - -static inline bool is_border_edge(const CDTEdge *e, const CDT_state *cdt) +BLI_INLINE bool is_border_edge(const CDTEdge *e, const CDT_state *cdt) { return e->symedges[0].face == cdt->outer_face || e->symedges[1].face == cdt->outer_face; } -/** Does one edge of this edge touch the frame? */ -static bool edge_touches_frame(const CDTEdge *e) +BLI_INLINE bool is_constrained_edge(const CDTEdge *e) { - return e->symedges[0].vert->index < 4 || e->symedges[1].vert->index < 4; + return e->input_ids != NULL; } -static inline bool is_constrained_edge(const CDTEdge *e) +BLI_INLINE bool is_deleted_edge(const CDTEdge *e) { - return e->input_ids != NULL; + return e->symedges[0].next == NULL; } -static inline bool is_deleted_edge(const CDTEdge *e) +BLI_INLINE bool is_original_vert(const CDTVert *v, CDT_state *cdt) { - return e->symedges[0].next == NULL; + return (v->index < cdt->input_vert_tot); } /** Is there already an edge between a and b? */ @@ -357,7 +322,6 @@ static bool vert_touches_face(const CDTVert *v, const CDTFace *f) * Add an edge from s1->v to s2->v, splitting the face in two. * The original face will continue to be associated with the subface * that has s1, and a new face will be made for s2's new face. - * The centroids of both faces are recalculated. * Return the new diagonal's CDTEdge *. */ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2) @@ -366,8 +330,8 @@ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2) CDTFace *fold, *fnew; SymEdge *sdiag, *sdiagsym; SymEdge *s1prev, *s1prevsym, *s2prev, *s2prevsym, *se; - BLI_assert(reachable(s1, s2, 2000)); - BLI_assert(reachable(s2, s1, 2000)); + BLI_assert(reachable(s1, s2, 20000)); + BLI_assert(reachable(s2, s1, 20000)); fold = s1->face; fnew = add_cdtface(cdt); s1prev = prev(s1); @@ -392,12 +356,61 @@ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2) se->face = fnew; } add_list_to_input_ids(&fnew->input_ids, fold->input_ids, cdt); - calc_face_centroid(sdiag); - calc_face_centroid(sdiagsym); return ediag; } /** + * Add a dangling edge from an isolated v to the vert at se in the same face as se->face. + */ +static CDTEdge *add_vert_to_symedge_edge(CDT_state *cdt, CDTVert *v, SymEdge *se) +{ + CDTEdge *e; + SymEdge *se_rot, *se_rotsym, *new_se, *new_se_sym; + + se_rot = se->rot; + se_rotsym = sym(se_rot); + e = add_cdtedge(cdt, v, se->vert, se->face, se->face); + new_se = &e->symedges[0]; + new_se_sym = &e->symedges[1]; + new_se->next = se; + new_se_sym->next = new_se; + new_se->rot = new_se; + new_se_sym->rot = se_rot; + se->rot = new_se_sym; + se_rotsym->next = new_se_sym; + return e; +} + +/* Connect the verts of se1 and se2, assuming that currently those two SymEdges are on + * the outer boundary (have face == outer_face) of two components that are isolated from + * each other. + */ +static CDTEdge *connect_separate_parts(CDT_state *cdt, SymEdge *se1, SymEdge *se2) +{ + CDTEdge *e; + SymEdge *se1_rot, *se1_rotsym, *se2_rot, *se2_rotsym, *new_se, *new_se_sym; + ; + + BLI_assert(se1->face == cdt->outer_face && se2->face == cdt->outer_face); + se1_rot = se1->rot; + se1_rotsym = sym(se1_rot); + se2_rot = se2->rot; + se2_rotsym = sym(se2_rot); + e = add_cdtedge(cdt, se1->vert, se2->vert, cdt->outer_face, cdt->outer_face); + new_se = &e->symedges[0]; + new_se_sym = &e->symedges[1]; + new_se->next = se2; + new_se_sym->next = se1; + new_se->rot = se1_rot; + new_se_sym->rot = se2_rot; + se1->rot = new_se; + se2->rot = new_se_sym; + se1_rotsym->next = new_se; + se2_rotsym->next = new_se_sym; + return e; +} + +/** * Split \a se at fraction \a lambda, * and return the new #CDTEdge that is the new second half. * Copy the edge input_ids into the new one. @@ -435,14 +448,12 @@ static CDTEdge *split_edge(CDT_state *cdt, SymEdge *se, double lambda) newsesym->vert->symedge = newsesym; } add_list_to_input_ids(&e->input_ids, se->edge->input_ids, cdt); - calc_face_centroid(se); - calc_face_centroid(sesym); return e; } /** * Delete an edge from the structure. The new combined face on either side of - * the deleted edge will be the one that was e's face; the centroid is updated. + * the deleted edge will be the one that was e's face. * There will be now an unused face, marked by setting its deleted flag, * and an unused #CDTEdge, marked by setting the next and rot pointers of * its SymEdges to NULL. @@ -519,820 +530,486 @@ static void delete_edge(CDT_state *cdt, SymEdge *e) cdt->outer_face = aface; } } - if (aface != cdt->outer_face) { - calc_face_centroid(f); - } } -/** - * The initial structure will be the rectangle with opposite corners (minx,miny) - * and (maxx,maxy), and a diagonal going between those two corners. - * We keep track of the outer face (surrounding the entire structure; its boundary - * is the clockwise traversal of the bounding box rectangle initially) in cdt->outer_face. - * - * The vertices are kept as pointers in an array (which may need to be reallocated from - * time to time); the edges and faces are kept in lists. Sometimes edges and faces are deleted, - * marked by setting all pointers to NULL (for edges), or setting the deleted flag to true (for - * faces). - * - * A #MemArena is allocated to do all allocations from except for link list nodes; a listpool - * is created for link list node allocations. - * - * The epsilon argument is stored and used in "near enough" distance calculations. - * - * When done, caller must call BLI_constrained_delaunay_free to free - * the memory used by the returned #CDT_state. - */ -static CDT_state *cdt_init(double minx, double maxx, double miny, double maxy, double epsilon) +static CDT_state *new_cdt_init(const CDT_input *in) { - double x0, x1, y0, y1; - double margin; - CDTVert *v[4]; - CDTEdge *e[4]; - CDTFace *f0, *fouter; - int i, inext, iprev; + int i; MemArena *arena = BLI_memarena_new(DLNY_ARENASIZE, __func__); - CDT_state *cdt = BLI_memarena_alloc(arena, sizeof(CDT_state)); - cdt->edges = NULL; - cdt->faces = NULL; - cdt->vert_array_len = 0; - cdt->vert_array_len_alloc = 32; + CDT_state *cdt = BLI_memarena_calloc(arena, sizeof(CDT_state)); + + cdt->epsilon = (double)in->epsilon; + cdt->epsilon_squared = cdt->epsilon * cdt->epsilon; + cdt->arena = arena; + cdt->input_vert_tot = in->verts_len; + cdt->vert_array_len_alloc = 2 * in->verts_len; cdt->vert_array = BLI_memarena_alloc(arena, cdt->vert_array_len_alloc * sizeof(*cdt->vert_array)); - cdt->minx = minx; - cdt->miny = miny; - cdt->maxx = maxx; - cdt->maxy = maxy; - cdt->arena = arena; - cdt->listpool = BLI_mempool_create(sizeof(LinkNode), 128, 128, 0); - cdt->rng = BLI_rng_new(0); - cdt->epsilon = epsilon; - - /* Expand bounding box a bit and make initial CDT from it. */ - margin = DLNY_MARGIN_PCT * max_dd(maxx - minx, maxy - miny) / 100.0; - if (margin <= 0.0) { - margin = 1.0; - } - if (margin < epsilon) { - margin = 4 * epsilon; /* Make sure constraint verts don't merge with border verts. */ - } - cdt->margin = margin; - x0 = minx - margin; - y0 = miny - margin; - x1 = maxx + margin; - y1 = maxy + margin; - - /* Make a quad, then split it with a diagonal. */ - v[0] = add_cdtvert(cdt, x0, y0); - v[1] = add_cdtvert(cdt, x1, y0); - v[2] = add_cdtvert(cdt, x1, y1); - v[3] = add_cdtvert(cdt, x0, y1); - cdt->outer_face = fouter = add_cdtface(cdt); - f0 = add_cdtface(cdt); - for (i = 0; i < 4; i++) { - e[i] = add_cdtedge(cdt, v[i], v[(i + 1) % 4], f0, fouter); - } - for (i = 0; i < 4; i++) { - inext = (i + 1) % 4; - iprev = (i + 3) % 4; - e[i]->symedges[0].next = &e[inext]->symedges[0]; - e[inext]->symedges[1].next = &e[i]->symedges[1]; - e[i]->symedges[0].rot = &e[iprev]->symedges[1]; - e[iprev]->symedges[1].rot = &e[i]->symedges[0]; - } - calc_face_centroid(&e[0]->symedges[0]); - add_diagonal(cdt, &e[0]->symedges[0], &e[2]->symedges[0]); - fouter->centroid[0] = fouter->centroid[1] = 0.0; - - cdt->visit_count = 0; - cdt->output_prepared = false; - cdt->face_edge_offset = 0; + cdt->listpool = BLI_mempool_create( + sizeof(LinkNode), 128 + 4 * in->verts_len, 128 + in->verts_len, 0); + + for (i = 0; i < in->verts_len; i++) { + add_cdtvert(cdt, (double)(in->vert_coords[i][0]), (double)(in->vert_coords[i][1])); + } + cdt->outer_face = add_cdtface(cdt); return cdt; } -static void cdt_free(CDT_state *cdt) +static void new_cdt_free(CDT_state *cdt) { - BLI_rng_free(cdt->rng); BLI_mempool_destroy(cdt->listpool); BLI_memarena_free(cdt->arena); } -static bool locate_point_final(const double p[2], - SymEdge *tri_se, - bool try_neighbors, - const double epsilon, - LocateResult *r_lr) -{ - /* 'p' should be in or on our just outside of 'cur_tri'. */ - double dist_inside[3]; - int i; - SymEdge *se; - const double *a, *b; - double lambda, close[2]; - bool done = false; -#ifdef DEBUG_CDT - int dbg_level = 0; - - if (dbg_level > 0) { - fprintf(stderr, "locate_point_final %d\n", try_neighbors); - dump_se(tri_se, "tri_se"); - fprintf(stderr, "\n"); - } -#endif - se = tri_se; - i = 0; - do { -#ifdef DEBUG_CDT - if (dbg_level > 1) { - fprintf(stderr, "%d: ", i); - dump_se(se, "search se"); - } -#endif - a = se->vert->co; - b = se->next->vert->co; - lambda = closest_to_line_v2_db(close, p, a, b); - double len_close_p = len_v2v2_db(close, p); - if (len_close_p < epsilon) { - if (len_v2v2_db(p, a) < epsilon) { -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "OnVert case a (%.2f,%.2f)\n", F2(a)); - } -#endif - r_lr->loc_kind = OnVert; - r_lr->se = se; - r_lr->edge_lambda = 0.0; - done = true; - } - else if (len_v2v2_db(p, b) < epsilon) { -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "OnVert case b (%.2f,%.2f)\n", F2(b)); - } -#endif - r_lr->loc_kind = OnVert; - r_lr->se = se->next; - r_lr->edge_lambda = 0.0; - done = true; - } - else if (lambda > 0.0 && lambda < 1.0) { -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "OnEdge case, lambda=%f\n", lambda); - dump_se(se, "se"); - } -#endif - r_lr->loc_kind = OnEdge; - r_lr->se = se; - r_lr->edge_lambda = lambda; - done = true; - } - } - else { - dist_inside[i] = len_close_p; - dist_inside[i] = CCW_test(a, b, p, epsilon) >= 0 ? len_close_p : -len_close_p; - } - i++; - se = se->next; - } while (se != tri_se && !done); - if (!done) { -#ifdef DEBUG_CDT - if (dbg_level > 1) { - fprintf(stderr, - "not done, dist_inside=%f %f %f\n", - dist_inside[0], - dist_inside[1], - dist_inside[2]); - } -#endif - if (dist_inside[0] >= 0.0 && dist_inside[1] >= 0.0 && dist_inside[2] >= 0.0) { -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "InFace case\n"); - dump_se_cycle(tri_se, "tri", 10); - } -#endif - r_lr->loc_kind = InFace; - r_lr->se = tri_se; - r_lr->edge_lambda = 0.0; - done = true; - } - else if (try_neighbors) { - for (se = tri_se->next; se != tri_se; se = se->next) { - if (locate_point_final(p, se, false, epsilon, r_lr)) { - done = true; - break; - } - } - if (!done) { - /* Shouldn't happen desperation mode: pick something. */ - se = NULL; - if (dist_inside[0] > 0) { - se = tri_se; - } - if (dist_inside[1] > 0 && (se == NULL || dist_inside[1] < dist_inside[i])) { - se = tri_se->next; - } - if (se == NULL) { - se = tri_se->next->next; - } - a = se->vert->co; - b = se->next->vert->co; - lambda = closest_to_line_v2_db(close, p, a, b); - if (lambda <= 0.0) { - r_lr->loc_kind = OnVert; - r_lr->se = se; - r_lr->edge_lambda = 0.0; - } - else if (lambda >= 1.0) { - r_lr->loc_kind = OnVert; - r_lr->se = se->next; - r_lr->edge_lambda = 0.0; - } - else { - r_lr->loc_kind = OnEdge; - r_lr->se = se->next; - r_lr->edge_lambda = lambda; - } -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf( - stderr, "desperation case kind=%u lambda=%f\n", r_lr->loc_kind, r_lr->edge_lambda); - dump_se(r_lr->se, "se"); - BLI_assert(0); /* While developing, catch these "should not happens" */ - } -#endif - fprintf(stderr, "desperation! point=(%g,%g)\n", p[0], p[1]); // TODO: remove - return true; - } - } - } - return done; -} +typedef struct SiteInfo { + CDTVert *v; + int orig_index; +} SiteInfo; -static LocateResult locate_point(CDT_state *cdt, const double p[2]) +static int site_lexicographic_cmp(const void *a, const void *b) { - LocateResult lr; - SymEdge *cur_se, *next_se, *next_se_sym; - CDTFace *cur_tri; - bool done; - int sample_n, i, k; - CDTVert *v, *best_start_vert; - double dist_squared, best_dist_squared; - double *a, *b, *c; - const double epsilon = cdt->epsilon; - int visit = ++cdt->visit_count; - int loop_count = 0; -#ifdef DEBUG_CDT - int dbg_level = 0; + const SiteInfo *s1 = a; + const SiteInfo *s2 = b; + const double *co1 = s1->v->co; + const double *co2 = s2->v->co; - if (dbg_level > 0) { - fprintf(stderr, "locate_point (%.2f,%.2f), visit_index=%d\n", F2(p), visit); - } -#endif - /* Starting point determined by closest to p in an n ** (1/3) sized sample of current points. */ - BLI_assert(cdt->vert_array_len > 0); - sample_n = (int)round(pow((double)cdt->vert_array_len, 0.33333)); - if (sample_n < 1) { - sample_n = 1; + if (co1[0] < co2[0]) { + return -1; } - best_start_vert = NULL; - best_dist_squared = DBL_MAX; - for (k = 0; k < sample_n; k++) { - /* Yes, this may try some i's more than once, - * but will still get about an n ** (1/3) size sample. */ - i = (int)(BLI_rng_get_uint(cdt->rng) % cdt->vert_array_len); - v = cdt->vert_array[i]; - dist_squared = len_squared_v2v2_db(p, v->co); -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "try start vert %d, dist_squared=%f\n", i, dist_squared); - dump_v(v, "v"); - } -#endif - if (dist_squared < best_dist_squared) { - best_dist_squared = dist_squared; - best_start_vert = v; - } + else if (co1[0] > co2[0]) { + return 1; } - cur_se = &best_start_vert->symedge[0]; - if (cur_se->face == cdt->outer_face) { - cur_se = cur_se->rot; - BLI_assert(cur_se->face != cdt->outer_face); + else if (co1[1] < co2[1]) { + return -1; } -#ifdef DEBUG_CDT - if (dbg_level > 0) { - dump_se(cur_se, "start vert edge"); + else if (co1[1] > co2[1]) { + return 1; } -#endif - done = false; - while (!done) { - /* Find edge of cur_tri that separates p and t's centroid, - * and where other tri over the edge is unvisited. */ -#ifdef DEBUG_CDT - if (dbg_level > 0) { - dump_se_cycle(cur_se, "cur search face", 5); - } -#endif - cur_tri = cur_se->face; - BLI_assert(cur_tri != cdt->outer_face); - cur_tri->visit_index = visit; - /* Is p in or on current triangle? */ - a = cur_se->vert->co; - b = cur_se->next->vert->co; - c = cur_se->next->next->vert->co; - if (CCW_test(a, b, p, 0.0) >= 0 && CCW_test(b, c, p, 0.0) >= 0 && - CCW_test(c, a, p, 0.0) >= 0) { -#ifdef DEBUG_CDT - if (dbg_level > 1) { - fprintf(stderr, "p in current triangle\n"); - } -#endif - done = locate_point_final(p, cur_se, false, epsilon, &lr); - BLI_assert(done == true); - break; - } - bool found_next = false; - next_se = cur_se; - do { - a = next_se->vert->co; - b = next_se->next->vert->co; - c = next_se->next->next->vert->co; -#ifdef DEBUG_CDT - if (dbg_level > 1) { - dump_se(next_se, "search edge"); - fprintf(stderr, "tri centroid=(%.3f,%.3f)\n", F2(cur_tri->centroid)); - validate_face_centroid(next_se); - } -#endif - next_se_sym = sym(next_se); - if (CCW_test(a, b, p, 0.0) <= 0 && next_se->face != cdt->outer_face) { -#ifdef DEBUG_CDT - if (dbg_level > 1) { - fprintf(stderr, "CCW_test(a, b, p) <= 0\n"); - } -#endif -#ifdef DEBUG_CDT - if (dbg_level > 0) { - dump_se(next_se_sym, "next_se_sym"); - fprintf(stderr, "next_se_sym face visit=%d\n", next_se_sym->face->visit_index); - } -#endif - if (next_se_sym->face->visit_index != visit) { -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "found edge to cross\n"); - } -#endif - found_next = true; - cur_se = next_se_sym; - break; - } - } - next_se = next_se->next; - } while (next_se != cur_se); - if (!found_next) { - done = locate_point_final(p, cur_se, true, epsilon, &lr); - BLI_assert(done = true); - done = true; - } - if (++loop_count > 1000000) { - fprintf(stderr, "infinite search loop?\n"); - done = locate_point_final(p, cur_se, true, epsilon, &lr); - } + else if (s1->orig_index < s2->orig_index) { + return -1; } - - return lr; -} - -/** - * Return true if circumcircle(v1, v2, v3) does not contain p. - * To avoid possible infinite flip loops, we will say true even if p is inside the circle - * but less than epsilon from the boundary; or if v1, v2, v3, form a straight line. - */ -static bool delaunay_check(CDTVert *v1, CDTVert *v2, CDTVert *v3, CDTVert *p, const double epsilon) -{ - double x1, y1, x2, y2, den, cenx, ceny, rad, pc, a, b, w, z, q, s; - - /* Find center and radius of circum-circle of v1,v2,v3. - * Transform coords so v3 is at origin to help reduce floating point error - * when coordinates are far from (0,0) but close together. - */ - x1 = v1->co[0] - v3->co[0]; - y1 = v1->co[1] - v3->co[1]; - x2 = v2->co[0] - v3->co[0]; - y2 = v2->co[1] - v3->co[1]; - den = 2.0 * (x1 * y2 - x2 * y1); - if (UNLIKELY(den == 0.0)) { - /* v1, v2, v3 are in a line. */ - return true; + else if (s1->orig_index > s2->orig_index) { + return 1; } - /* cen[0] = det(x1**2 + y1**2, y1, x2**2 + y2**2, y2) / den - * cen[1] = det(x1, x1**2 + y1**2, x2, x2**2 + y2**2) / den - * den = 2 * det(x1, y1, x2, y2) - */ - a = x1 * x1 + y1 * y1; - b = x2 * x2 + y2 * y2; - cenx = (a * y2 - b * y1) / den; - ceny = (x1 * b - x2 * a) / den; - w = x1 - cenx; - z = y1 - ceny; - rad = sqrt(w * w + z * z); - q = p->co[0] - v3->co[0] - cenx; - s = p->co[1] - v3->co[1] - ceny; - pc = sqrt(q * q + s * s); - return (pc >= rad - epsilon); -} - -/* Return true if we can flip edge v1-v3 to edge v2-v4 inside quad v1v2v3v4 (in CCW order). - * We can do this if angles v4-v1-v2 and v2-v3-v4 are both CCW or straight. - */ -static inline bool can_flip(CDTVert *v1, CDTVert *v2, CDTVert *v3, CDTVert *v4) -{ - return CCW_test(v4->co, v1->co, v2->co, 0.0) >= 0 && CCW_test(v2->co, v3->co, v4->co, 0.0) >= 0; + return 0; } -/** Use LinkNode linked list as stack of SymEdges, allocating from cdt->listpool. */ -typedef LinkNode *Stack; - -static inline void push(Stack *stack, SymEdge *se, CDT_state *cdt) +BLI_INLINE bool vert_left_of_symedge(CDTVert *v, SymEdge *se) { - BLI_linklist_prepend_pool(stack, se, cdt->listpool); + return orient2d(v->co, se->vert->co, se->next->vert->co) > 0.0; } -static inline SymEdge *pop(Stack *stack, CDT_state *cdt) +BLI_INLINE bool vert_right_of_symedge(CDTVert *v, SymEdge *se) { - return (SymEdge *)BLI_linklist_pop_pool(stack, cdt->listpool); + return orient2d(v->co, se->next->vert->co, se->vert->co) > 0.0; } -static inline bool is_empty(Stack *stack) +/* Is se above basel? */ +BLI_INLINE bool dc_tri_valid(SymEdge *se, SymEdge *basel, SymEdge *basel_sym) { - return *stack == NULL; + return orient2d(se->next->vert->co, basel_sym->vert->co, basel->vert->co) > 0.0; } -/** - * <pre> - * /\ /\ - * /a|\ / \ - * / | sesym / \ - * / | \ / \ - * . b | d . -> . se______ - * \ se| / \ / - * \ |c/ \ / - * \ |/ \ / - * </pre> +/* Delaunay triangulate sites[start} to sites[end-1]. + * Assume sites are lexicographically sorted by coordinate. + * Return SymEdge of ccw convex hull at left-most point in *r_le + * and that of right-most point of cw convex null in *r_re. */ -static void flip(SymEdge *se, CDT_state *cdt) +static void dc_tri( + CDT_state *cdt, SiteInfo *sites, int start, int end, SymEdge **r_le, SymEdge **r_re) { - SymEdge *a, *b, *c, *d; - SymEdge *sesym, *asym, *bsym, *csym, *dsym; - CDTFace *t1, *t2; - CDTVert *v1, *v2; + int n = end - start; + int n2; + CDTVert *v1, *v2, *v3; + CDTEdge *ea, *eb, *ebasel; + SymEdge *ldo, *ldi, *rdi, *rdo, *basel, *basel_sym, *lcand, *rcand, *t; + double orient; + bool valid_lcand, valid_rcand; #ifdef DEBUG_CDT - const int dbg_level = 0; -#endif + char label_buf[100]; + int dbg_level = 0; - sesym = sym(se); -#ifdef DEBUG_CDT if (dbg_level > 0) { - fprintf(stderr, "flip\n"); - dump_se(se, "se"); - dump_se(sesym, "sesym"); - } -#endif - a = se->next; - b = a->next; - c = sesym->next; - d = c->next; - asym = sym(a); - bsym = sym(b); - csym = sym(c); - dsym = sym(d); -#ifdef DEBUG_CDT - if (dbg_level > 1) { - dump_se(a, "a"); - dump_se(b, "b"); - dump_se(c, "c"); - dump_se(d, "d"); + fprintf(stderr, "DC_TRI start=%d end=%d\n", start, end); } #endif - v1 = se->vert; - v2 = sesym->vert; - t1 = a->face; - t2 = c->face; - - se->vert = b->vert; - sesym->vert = d->vert; - - a->next = se; - se->next = d; - d->next = a; - - sesym->next = b; - b->next = c; - c->next = sesym; - a->rot = dsym; - b->rot = se; - se->rot = asym; - - c->rot = bsym; - d->rot = sesym; - sesym->rot = csym; - - a->face = se->face = d->face = t1; - sesym->face = b->face = c->face = t2; - - if (v1->symedge == se) { - v1->symedge = c; + BLI_assert(r_le != NULL && r_re != NULL); + if (n <= 1) { + *r_le = NULL; + *r_re = NULL; + return; } - if (v2->symedge == sesym) { - v2->symedge = a; + if (n <= 3) { + v1 = sites[start].v; + v2 = sites[start + 1].v; + ea = add_cdtedge(cdt, v1, v2, cdt->outer_face, cdt->outer_face); + ea->symedges[0].next = &ea->symedges[1]; + ea->symedges[1].next = &ea->symedges[0]; + ea->symedges[0].rot = &ea->symedges[0]; + ea->symedges[1].rot = &ea->symedges[1]; + if (n == 2) { + *r_le = &ea->symedges[0]; + *r_re = &ea->symedges[1]; + return; + } + v3 = sites[start + 2].v; + eb = add_vert_to_symedge_edge(cdt, v3, &ea->symedges[1]); + orient = orient2d(v1->co, v2->co, v3->co); + if (orient > 0.0) { + add_diagonal(cdt, &eb->symedges[0], &ea->symedges[0]); + *r_le = &ea->symedges[0]; + *r_re = &eb->symedges[0]; + } + else if (orient < 0.0) { + add_diagonal(cdt, &ea->symedges[0], &eb->symedges[0]); + *r_le = ea->symedges[0].rot; + *r_re = eb->symedges[0].rot; + } + else { + /* Collinear points. Just return a line. */ + *r_le = &ea->symedges[0]; + *r_re = &eb->symedges[0]; + } + return; } + /* Here: n >= 4. Divide and conquer. */ + n2 = n / 2; + BLI_assert(n2 >= 2 && end - (start + n2) >= 2); - calc_face_centroid(a); - calc_face_centroid(sesym); - + /* Delaunay triangulate two halves, L and R. */ + dc_tri(cdt, sites, start, start + n2, &ldo, &ldi); + dc_tri(cdt, sites, start + n2, end, &rdi, &rdo); #ifdef DEBUG_CDT if (dbg_level > 0) { - fprintf(stderr, "after flip\n"); - dump_se_cycle(a, "a cycle", 5); - dump_se_cycle(sesym, "sesym cycle", 5); + fprintf(stderr, "\nDC_TRI merge step for start=%d, end=%d\n", start, end); + dump_se(ldo, "ldo"); + dump_se(ldi, "ldi"); + dump_se(rdi, "rdi"); + dump_se(rdo, "rdo"); + if (dbg_level > 1) { + sprintf(label_buf, "dc_tri(%d,%d)(%d,%d)", start, start + n2, start + n2, end); + /* dump_cdt(cdt, label_buf); */ + cdt_draw(cdt, label_buf); + } } #endif - if (cdt) { - /* Pass. */ - } -} -static void flip_edges(CDTVert *v, Stack *stack, CDT_state *cdt) -{ - SymEdge *se, *sesym; - CDTVert *a, *b, *c, *d; - SymEdge *tri_without_p; - bool is_delaunay; - const double epsilon = cdt->epsilon; - int count = 3; + /* Find lower common tangent of L and R. */ + for (;;) { + if (vert_left_of_symedge(rdi->vert, ldi)) { + ldi = ldi->next; + } + else if (vert_right_of_symedge(ldi->vert, rdi)) { + rdi = sym(rdi)->rot; /* Previous edge to rdi with same right face. */ + } + else { + break; + } + } #ifdef DEBUG_CDT - const int dbg_level = 0; if (dbg_level > 0) { - fprintf(stderr, "flip_edges, v=(%.2f,%.2f)\n", F2(v->co)); + fprintf(stderr, "common lower tangent is between\n"); + dump_se(rdi, "rdi"); + dump_se(ldi, "ldi"); } #endif - while (!is_empty(stack)) { - if (++count > 10000) { - fprintf(stderr, "infinite flip loop?\n"); - return; - } - se = pop(stack, cdt); + ebasel = connect_separate_parts(cdt, sym(rdi)->next, ldi); + basel = &ebasel->symedges[0]; + basel_sym = &ebasel->symedges[1]; #ifdef DEBUG_CDT - if (dbg_level > 0) { - dump_se(se, "flip_edges popped"); - } + if (dbg_level > 1) { + dump_se(basel, "basel"); + cdt_draw(cdt, "after basel made"); + } #endif - if (!is_constrained_edge(se->edge)) { - /* Edge is not constrained; is it Delaunay? */ + if (ldi->vert == ldo->vert) { + ldo = basel_sym; + } + if (rdi->vert == rdo->vert) { + rdo = basel; + } + + /* Merge loop. */ + for (;;) { + /* Locate the first point lcand->next->vert encountered by rising bubble, + * and delete L edges out of basel->next->vert that fail the circle test. */ + lcand = basel_sym->rot; + rcand = basel_sym->next; #ifdef DEBUG_CDT - if (dbg_level > 1) { - dump_se_cycle(se, "unconstrained edge", 5); - } - else if (dbg_level > 0) { - fprintf(stderr, "unconstrained edge\n"); - } + if (dbg_level > 1) { + fprintf(stderr, "\ntop of merge loop\n"); + dump_se(lcand, "lcand"); + dump_se(rcand, "rcand"); + dump_se(basel, "basel"); + } #endif - a = se->vert; - b = se->next->vert; - c = se->next->next->vert; - sesym = sym(se); - d = sesym->next->next->vert; + if (dc_tri_valid(lcand, basel, basel_sym)) { #ifdef DEBUG_CDT if (dbg_level > 1) { - fprintf(stderr, "a=(%.3f,%.3f) b=(%.3f,%.3f)\n", F2(a->co), F2(b->co)); - fprintf(stderr, "c=(%.3f,%.3f) d=(%.3f,%.3f)\n", F2(c->co), F2(d->co)); + fprintf(stderr, "found valid lcand\n"); + dump_se(lcand, " lcand"); } #endif - if (v == c) { - tri_without_p = sesym; - is_delaunay = delaunay_check(a, b, c, d, epsilon); + while (incircle(basel_sym->vert->co, + basel->vert->co, + lcand->next->vert->co, + lcand->rot->next->vert->co) > 0.0) { #ifdef DEBUG_CDT if (dbg_level > 1) { - fprintf(stderr, "v==c, delaunay(a,b,c,d)=%d\n", is_delaunay); + fprintf(stderr, "incircle says to remove lcand\n"); + dump_se(lcand, " lcand"); } #endif + t = lcand->rot; + delete_edge(cdt, sym(lcand)); + lcand = t; } - else { - tri_without_p = se; - BLI_assert(d == v); - is_delaunay = delaunay_check(b, a, d, c, epsilon); + } + /* Symmetrically, locate first R point to be hit and delete R edges. */ + if (dc_tri_valid(rcand, basel, basel_sym)) { #ifdef DEBUG_CDT - if (dbg_level > 1) { - fprintf(stderr, "v!=c, delaunay(b,a,d,c)=%d\n", is_delaunay); - } -#endif + if (dbg_level > 1) { + fprintf(stderr, "found valid rcand\n"); + dump_se(rcand, " rcand"); } - if (!is_delaunay && can_flip(a, d, b, c)) { - /* Push two edges of tri without p that aren't se. */ +#endif + while (incircle(basel_sym->vert->co, + basel->vert->co, + rcand->next->vert->co, + sym(rcand)->next->next->vert->co) > 0.0) { #ifdef DEBUG_CDT if (dbg_level > 0) { - fprintf(stderr, "maybe pushing more edges\n"); + fprintf(stderr, "incircle says to remove rcand\n"); + dump_se(lcand, " rcand"); } #endif - if (!is_border_edge(tri_without_p->next->edge, cdt)) { + t = sym(rcand)->next; + delete_edge(cdt, rcand); + rcand = t; + } + } + /* If both lcand and rcand are invalid, then basel is the common upper tangent. */ + valid_lcand = dc_tri_valid(lcand, basel, basel_sym); + valid_rcand = dc_tri_valid(rcand, basel, basel_sym); #ifdef DEBUG_CDT - if (dbg_level > 0) { - dump_se(tri_without_p->next, "push1"); - } + if (dbg_level > 0) { + fprintf( + stderr, "after bubbling up, valid_lcand=%d, valid_rcand=%d\n", valid_lcand, valid_rcand); + dump_se(lcand, "lcand"); + dump_se(rcand, "rcand"); + } #endif - push(stack, tri_without_p->next, cdt); - } - if (!is_border_edge(tri_without_p->next->next->edge, cdt)) { + if (!valid_lcand && !valid_rcand) { + break; + } + /* The next cross edge to be connected is to either lcand->next->vert or rcand->next->vert; + * if both are valid, choose the appropriate one using the incircle test. + */ + if (!valid_lcand || + (valid_rcand && + incircle(lcand->next->vert->co, lcand->vert->co, rcand->vert->co, rcand->next->vert->co) > + 0.0)) { #ifdef DEBUG_CDT - if (dbg_level > 0) { - dump_se(tri_without_p->next->next, "\npush2"); - } + if (dbg_level > 0) { + fprintf(stderr, "connecting rcand\n"); + dump_se(basel_sym, " se1=basel_sym"); + dump_se(rcand->next, " se2=rcand->next"); + } #endif - push(stack, tri_without_p->next->next, cdt); - } - flip(se, cdt); + ebasel = add_diagonal(cdt, rcand->next, basel_sym); + } + else { #ifdef DEBUG_CDT - if (dbg_level > 2) { - dump_cdt(cdt, "after flip"); - cdt_draw(cdt, "afer flip"); - validate_cdt(cdt, true); - } -#endif + if (dbg_level > 0) { + fprintf(stderr, "connecting lcand\n"); + dump_se(sym(lcand), " se1=sym(lcand)"); + dump_se(basel_sym->next, " se2=basel_sym->next"); } +#endif + ebasel = add_diagonal(cdt, basel_sym->next, sym(lcand)); } + basel = &ebasel->symedges[0]; + basel_sym = &ebasel->symedges[1]; + BLI_assert(basel_sym->face == cdt->outer_face); +#ifdef DEBUG_CDT + if (dbg_level > 2) { + cdt_draw(cdt, "after adding new crossedge"); + // dump_cdt(cdt, "after adding new crossedge"); + } +#endif } + *r_le = ldo; + *r_re = rdo; + BLI_assert(sym(ldo)->face == cdt->outer_face && rdo->face == cdt->outer_face); } -/** - * Splits e at lambda and returns a #SymEdge with new vert as its vert. - * The two opposite triangle vertices to e are connect to new point. - * <pre> - * /\ /\ - * /f|\ / |\ - * / |j\ / | \ - * / | i\ / k| \ - * . | . -> . l_ p m_. - * \g | / \ | / - * \ |h/ \ | / - * \e|/ \ e|/ - * - * t1 = {e, f, g}; t2 = {h, i, j}; - * t1' = {e, l.sym, g}; t2' = {h, m.sym, e'.sym} - * t3 = {k, f, l}; t4 = {m, i, j} - * </pre> - */ -static CDTVert *insert_point_in_edge(CDT_state *cdt, SymEdge *e, double lambda) +/* Guibas-Stolfi Divide-and_Conquer algorithm. */ +static void dc_triangulate(CDT_state *cdt, SiteInfo *sites, int nsites) { - SymEdge *f, *g, *h, *i, *j, *k; - CDTEdge *ke; - CDTVert *p; - Stack stack; - /* Split e at lambda. */ - - f = e->next; - g = f->next; - BLI_assert(g->next == e); - j = sym(e); - h = j->next; - i = h->next; - BLI_assert(i->next == j); - - ke = split_edge(cdt, e, lambda); - k = &ke->symedges[0]; - p = k->vert; + int i, j, n; + SymEdge *le, *re; - add_diagonal(cdt, g, k); - add_diagonal(cdt, sym(e), i); - - stack = NULL; - if (!is_border_edge(f->edge, cdt)) { - push(&stack, f, cdt); - } - if (!is_border_edge(g->edge, cdt)) { - push(&stack, g, cdt); - } - if (!is_border_edge(h->edge, cdt)) { - push(&stack, h, cdt); + /* Compress sites in place to eliminated verts that merge to others. */ + i = 0; + j = 0; + while (j < nsites) { + /* Invariante: sites[0..i-1] have non-merged verts from 0..(j-1) in them. */ + sites[i] = sites[j++]; + if (sites[i].v->merge_to_index < 0) { + i++; + } } - if (!is_border_edge(i->edge, cdt)) { - push(&stack, i, cdt); + n = i; + if (n == 0) { + return; } - flip_edges(k->vert, &stack, cdt); - return p; + dc_tri(cdt, sites, 0, n, &le, &re); } /** - * Inserts p inside e's triangle and connects the three cornders - * of the triangle to the new point. Returns a SymEdge that has - * new point as its point. - * <pre> - * * * - * *g * * .j* - * * * * . * - * * p * -> * 1. p . 3* - * * * * . . * - * * e f* * . h 2 i . * - * * * * * * * * * * * * * * * * * * * * * * * * * * * - * </pre> + * Do a Delaunay Triangulation of the points in cdt->vert_array. + * This is only a first step in the Constrained Delaunay triangulation, + * because it doesn't yet deal with the segment constraints. + * The algorithm used is the Divide & Conquer algorithm from the + * Guibas-Stolfi "Primitives for the Manipulation of General Subdivision + * and the Computation of Voronoi Diagrams" paper. + * The data structure here is similar to but not exactly the same as + * the quad-edge structure described in that paper. + * The incircle and ccw tests are done using Shewchuk's exact + * primitives (see below), so that this routine is robust. + * + * As a preprocessing step, we want to merge all vertices that are + * within cdt->epsilon of each other. This is accomplished by lexicographically + * sorting the coordinates first (which is needed anyway for the D&C algorithm). + * The CDTVerts with merge_to_index not equal to -1 are after this regarded + * as having been merged into the vertex with the corresponding index. */ -static CDTVert *insert_point_in_face(CDT_state *cdt, SymEdge *e, const double p[2]) +static void initial_triangulation(CDT_state *cdt) { - SymEdge *f, *g, *h, *i, *j; - SymEdge *esym, *fsym, *gsym, *hsym, *isym, *jsym; - CDTVert *v; - CDTEdge *he, *ie, *je; - CDTFace *t1, *t2, *t3; - Stack stack; + int i, j, n; + SiteInfo *sites; + double *ico, *jco; + double xend, yend, xcur; + double epsilon = cdt->epsilon; + double epsilon_squared = cdt->epsilon_squared; +#ifdef SJF_WAY + CDTEdge *e; + CDTVert *va, *vb; +#endif #ifdef DEBUG_CDT int dbg_level = 0; if (dbg_level > 0) { - fprintf(stderr, "insert point in face, p=(%.3f,%.3f)\n", F2(p)); - dump_se_cycle(e, "insert face", 20); + fprintf(stderr, "\nINITIAL TRIANGULATION\n\n"); } #endif - f = e->next; - g = f->next; - esym = sym(e); - fsym = sym(f); - gsym = sym(g); - t1 = e->face; - t2 = add_cdtface(cdt); - t3 = add_cdtface(cdt); - - v = add_cdtvert(cdt, p[0], p[1]); - he = add_cdtedge(cdt, e->vert, v, t1, t2); - h = &he->symedges[0]; - hsym = &he->symedges[1]; - ie = add_cdtedge(cdt, f->vert, v, t2, t3); - i = &ie->symedges[0]; - isym = &ie->symedges[1]; - je = add_cdtedge(cdt, g->vert, v, t3, t1); - j = &je->symedges[0]; - jsym = &je->symedges[1]; - - e->next = i; - i->next = hsym; - hsym->next = e; - e->face = t2; - - f->next = j; - j->next = isym; - isym->next = f; - f->face = t3; - - g->next = h; - h->next = jsym; - jsym->next = g; - g->face = t1; - - e->rot = h; - i->rot = esym; - hsym->rot = isym; - - f->rot = i; - j->rot = fsym; - isym->rot = jsym; - - g->rot = j; - h->rot = gsym; - jsym->rot = hsym; - - calc_face_centroid(e); - calc_face_centroid(f); - calc_face_centroid(g); - + /* First sort the vertices by lexicographic order of their + * coordinates, breaking ties by putting earlier original-index + * vertices first. + */ + n = cdt->vert_array_len; + if (n <= 1) { + return; + } + sites = MEM_malloc_arrayN(n, sizeof(SiteInfo), __func__); + for (i = 0; i < n; i++) { + sites[i].v = cdt->vert_array[i]; + sites[i].orig_index = i; + } + qsort(sites, n, sizeof(SiteInfo), site_lexicographic_cmp); #ifdef DEBUG_CDT - if (dbg_level > 1) { - fprintf(stderr, "after initial insert:\n"); - dump_se_cycle(e, "e", 20); - dump_se_cycle(f, "f", 20); - dump_se_cycle(g, "g", 20); - if (dbg_level > 2) { - dump_cdt(cdt, "after initial insert, before flip"); - cdt_draw(cdt, "after initial insert, before flip"); - validate_cdt(cdt, true); + if (dbg_level > 0) { + fprintf(stderr, "after sorting\n"); + for (i = 0; i < n; i++) { + fprintf(stderr, "%d: orig index: %d, (%f,%f)\n", i, sites[i].orig_index, F2(sites[i].v->co)); } } #endif - stack = NULL; - if (!is_border_edge(e->edge, cdt)) { - push(&stack, e, cdt); - } - if (!is_border_edge(f->edge, cdt)) { - push(&stack, f, cdt); - } - if (!is_border_edge(g->edge, cdt)) { - push(&stack, g, cdt); + /* Now dedup according to user-defined epsilon. + * We will merge a vertex into an earlier-indexed vertex + * that is within epsilon (Euclidean distance). + * Merges may cascade. So we may end up merging two things + * that are farther than epsilon by transitive merging. Oh well. + * Assume that merges are rare, so use simple searches in the + * lexicographic ordering - likely we will soon hit y's with + * the same x that are farther away than epsilon, and then + * skipping ahead to the next biggest x, are likely to soon + * find one of those farther away than epsilon. + */ + for (i = 0; i < n - 1; i++) { + ico = sites[i].v->co; + /* Start j at next place that has both x and y coords within epsilon. */ + xend = ico[0] + epsilon; + yend = ico[1] + epsilon; + j = i + 1; + while (j < n) { + jco = sites[j].v->co; + if (jco[0] > xend) { + break; /* No more j's to process. */ + } + else if (jco[1] > yend) { + /* Get past any string of v's with the same x and too-big y. */ + xcur = jco[0]; + while (++j < n) { + if (sites[j].v->co[0] > xcur) { + break; + } + } + BLI_assert(j == n || sites[j].v->co[0] > xcur); + if (j == n) { + break; + } + jco = sites[j].v->co; + if (jco[0] > xend || jco[1] > yend) { + break; + } + } + /* When here, vertex i and j are within epsilon by box test. + * The Euclidean distance test is stricter, so need to do it too, now. + */ + BLI_assert(j < n && jco[0] <= xend && jco[1] <= yend); + if (len_squared_v2v2_db(ico, jco) <= epsilon_squared) { + sites[j].v->merge_to_index = (sites[i].v->merge_to_index == -1) ? + sites[i].orig_index : + sites[i].v->merge_to_index; +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, + "merged orig vert %d to %d\n", + sites[j].orig_index, + sites[j].v->merge_to_index); + } +#endif + } + j++; + } } - flip_edges(v, &stack, cdt); - return v; + /* Now add non-dup vertices into triangulation in lexicographic order. */ + + dc_triangulate(cdt, sites, n); + MEM_freeN(sites); +} + +/** Use LinkNode linked list as stack of SymEdges, allocating from cdt->listpool. */ +typedef LinkNode *Stack; + +BLI_INLINE void push(Stack *stack, SymEdge *se, CDT_state *cdt) +{ + BLI_linklist_prepend_pool(stack, se, cdt->listpool); +} + +BLI_INLINE SymEdge *pop(Stack *stack, CDT_state *cdt) +{ + return (SymEdge *)BLI_linklist_pop_pool(stack, cdt->listpool); +} + +BLI_INLINE bool is_empty(Stack *stack) +{ + return *stack == NULL; } /** @@ -1347,12 +1024,16 @@ static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se) SymEdge *ss, *first, *cse; CDTVert *a, *b, *c, *v; CDTEdge *ebc, *eca; - const double epsilon = cdt->epsilon; int count; #ifdef DEBUG_CDT SymEdge *last; const int dbg_level = 0; +#endif + if (se->face == cdt->outer_face || sym(se)->face == cdt->outer_face) { + return; + } +#ifdef DEBUG_CDT if (dbg_level > 0) { fprintf(stderr, "retriangulate"); dump_se_cycle(se, "poly ", 1000); @@ -1391,7 +1072,7 @@ static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se) #endif for (ss = first->next; ss != se; ss = ss->next) { v = ss->vert; - if (!delaunay_check(a, b, c, v, epsilon)) { + if (incircle(a->co, b->co, c->co, v->co) > 0.0) { c = v; cse = ss; #ifdef DEBUG_CDT @@ -1440,50 +1121,6 @@ static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se) } /** - * Add a constrained point to cdt structure, and return the corresponding CDTVert*. - * May not be at exact coords given, because it can be merged with an existing vertex - * or moved to an existing edge (which could be a triangulation edge, not just a constraint one) - * if the point is within cdt->epsilon of those other elements. - * - * input_id will be added to the list of input_ids for the returned CDTVert (don't use -1 for id). - * - * Assumes cdt has been initialized, with min/max bounds that contain coords. - * Assumes that #BLI_constrained_delaunay_get_output has not been called yet. - */ -static CDTVert *add_point_constraint(CDT_state *cdt, const double coords[2], int input_id) -{ - LocateResult lr; - CDTVert *v; -#ifdef DEBUG_CDT - const int dbg_level = 0; -#endif - - BLI_assert(!cdt->output_prepared); -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "add point constraint (%.3f,%.3f), id=%d\n", F2(coords), input_id); - } -#endif - lr = locate_point(cdt, coords); -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, " locate result has loc_kind %u\n", lr.loc_kind); - } -#endif - if (lr.loc_kind == OnVert) { - v = lr.se->vert; - } - else if (lr.loc_kind == OnEdge) { - v = insert_point_in_edge(cdt, lr.se, lr.edge_lambda); - } - else { - v = insert_point_in_face(cdt, lr.se, coords); - } - add_to_input_ids(&v->input_ids, input_id, cdt); - return v; -} - -/** * Add a constrained edge between v1 and v2 to cdt structure. * This may result in a number of #CDTEdges created, due to intersections * and partial overlaps with existing cdt vertices and edges. @@ -1505,11 +1142,11 @@ static void add_edge_constraint( SymEdge *t, *tstart, *tout, *tnext; SymEdge *se; CDTEdge *edge; - int ccw1, ccw2, isect; - int i, search_count, visit; + int isect; + double orient1, orient2; + int i, search_count; double curco[2]; double lambda; - const double epsilon = cdt->epsilon; bool done, state_through_vert; LinkNodePair edge_list = {NULL, NULL}; typedef struct CrossData { @@ -1523,7 +1160,7 @@ static void add_edge_constraint( CrossData *cd; BLI_array_staticdeclare(crossings, 128); #ifdef DEBUG_CDT - const int dbg_level = 0; + int dbg_level = 0; #endif /* Find path through structure from v1 to v2 and record how we got there in crossings. @@ -1564,6 +1201,10 @@ static void add_edge_constraint( #ifdef DEBUG_CDT if (dbg_level > 0) { vse2 = v2->symedge; + if (dbg_level > 2) { + // dump_cdt(cdt, "before insert_segment"); + cdt_draw(cdt, "before insert segment"); + } fprintf(stderr, "\ninsert_segment %d\n", input_id); dump_v(v1, " 1"); dump_v(v2, " 2"); @@ -1571,9 +1212,6 @@ static void add_edge_constraint( dump_se(vse1, " se1"); dump_se(vse2, " se2"); } - if (dbg_level > 2) { - dump_cdt(cdt, "before insert_segment"); - } } #endif if (v1 == v2) { @@ -1600,7 +1238,7 @@ static void add_edge_constraint( cdata.vert = v2; BLI_array_append(crossings, cdata); #ifdef DEBUG_CDT - if (dbg_level > 1) { + if (dbg_level > 0) { fprintf(stderr, "special one segment case\n"); dump_se(t, " "); } @@ -1611,10 +1249,6 @@ static void add_edge_constraint( t = t->rot; } while (t != tstart); if (!done) { - /* To prevent infinite loop in the face of epsilon tests that might lead us back to - * an already-visited (vertex, face) pair, use visit indices. - */ - visit = ++cdt->visit_count; state_through_vert = true; done = false; t = vse1; @@ -1636,9 +1270,6 @@ static void add_edge_constraint( dump_se_cycle(t, "current t ", 4); } #endif - BLI_assert(t->vert->visit_index != visit || t->face->visit_index != visit); - t->vert->visit_index = visit; - t->face->visit_index = visit; if (state_through_vert) { /* Invariant: ray vcur--v2 contains t->vert. */ cdata.in = (BLI_array_len(crossings) == 0) ? NULL : t; @@ -1648,7 +1279,7 @@ static void add_edge_constraint( BLI_array_append(crossings, cdata); if (t->vert == v2) { #ifdef DEBUG_CDT - if (dbg_level > 0) { + if (dbg_level > 1) { fprintf(stderr, "found v2, so done\n"); } #endif @@ -1661,20 +1292,18 @@ static void add_edge_constraint( do { va = t->next->vert; vb = t->next->next->vert; - ccw1 = CCW_test(t->vert->co, va->co, v2->co, epsilon); - ccw2 = CCW_test(t->vert->co, vb->co, v2->co, epsilon); + orient1 = orient2d(t->vert->co, va->co, v2->co); #ifdef DEBUG_CDT if (dbg_level > 1) { fprintf(stderr, "non-final through vert case\n"); dump_v(va, " va"); dump_v(vb, " vb"); - fprintf(stderr, "ccw1=%d, ccw2=%d\n", ccw1, ccw2); + fprintf(stderr, "orient1=%g\n", orient1); } #endif - if (ccw1 == 0 && in_line(t->vert->co, va->co, v2->co, epsilon) && - va->visit_index != visit) { + if (orient1 == 0.0 && in_line(t->vert->co, va->co, v2->co)) { #ifdef DEBUG_CDT - if (dbg_level > 0) { + if (dbg_level > 1) { fprintf(stderr, "ray goes through va\n"); } #endif @@ -1683,30 +1312,35 @@ static void add_edge_constraint( t = t->next; break; } - else if (ccw2 == 0 && in_line(t->vert->co, vb->co, v2->co, epsilon) && - vb->visit_index != visit) { + else if (t->face != cdt->outer_face) { + orient2 = orient2d(t->vert->co, vb->co, v2->co); #ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "ray goes through vb\n"); + if (dbg_level > 1) { + fprintf(stderr, "orient2=%g\n", orient2); } #endif - state_through_vert = true; - t = t->next->next; - tout = sym(t); - break; - } - else if (ccw1 > 0 && ccw2 < 0 && - (t->next->vert->visit_index != visit || - t->next->face->visit_index != visit)) { + if (orient2 == 0.0 && in_line(t->vert->co, vb->co, v2->co)) { #ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "segment intersects\n"); + if (dbg_level > 1) { + fprintf(stderr, "ray goes through vb\n"); + } +#endif + state_through_vert = true; + t = t->next->next; + tout = sym(t); + break; } + else if (orient1 > 0.0 && orient2 < 0.0) { +#ifdef DEBUG_CDT + if (dbg_level > 1) { + fprintf(stderr, "segment intersects\n"); + } #endif - state_through_vert = false; - tout = t; - t = t->next; - break; + state_through_vert = false; + tout = t; + t = t->next; + break; + } } t = t->rot; #ifdef DEBUG_CDT @@ -1715,57 +1349,13 @@ static void add_edge_constraint( } #endif } while (t != tstart); - if (tout == NULL) { - /* With exact arithmetic this shouldn't happen, but maybe the epsilon tests made it so - * that we want to go back to a previous vertex. - * As desperation measure, pick unvisited vertex that is closest in line with - * destination. - */ -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "add_edge_constraint desperation search\n"); - } -#endif - SymEdge *bestt = NULL; - double dot, bestdot = -2.0; - double dir_tv_v2[2], dir_tvnext_v2[2]; - sub_v2_v2v2_db(dir_tv_v2, v2->co, t->vert->co); - do { - if (t->next->vert->visit_index != visit) { - sub_v2_v2v2_db(dir_tvnext_v2, v2->co, t->next->vert->co); - dot = dot_v2v2_db(dir_tv_v2, dir_tvnext_v2); - if (dot > bestdot) { - bestdot = dot; - bestt = t->next; - } - } - t = t->rot; - } while (t != tstart); - if (bestt == NULL) { - /* No unvisited place to go! Give up on adding this edge constraint. */ -#ifdef DEBUG_CDT - fprintf(stderr, "could not add edge constraint\n"); -#endif - return; - } - else { -#ifdef DEBUG_CDT - if (dbg_level > 0) { - fprintf(stderr, "add_edge_constraint desperation search chose to go through\n"); - dump_v(bestt->vert, "desperation vert"); - } -#endif - tout = bestt; - t = t->next; - } - } + BLI_assert(tout != NULL); crossings[BLI_array_len(crossings) - 1].out = tout; } } else { /* State is "through edge", not "through vert" */ /* Invariant: ray v1--v2 intersects segment t->edge, not at either end. * and t->face is the face we have just passed through. - * Whatever we make t next should not have both vert and face visited. */ va = t->vert; vb = t->next->vert; @@ -1784,19 +1374,41 @@ static void add_edge_constraint( } #endif isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, curco, v2->co, &lambda, NULL); - if (isect != ISECT_LINE_LINE_CROSS) { - /* Shouldn't happen. Just pick something. */ + if (isect == ISECT_LINE_LINE_NONE || isect == ISECT_LINE_LINE_EXACT) { + /* The orient tests say that there is an intersection between + * va and vb, but the inexect isect routine has either put the + * intersection exactly on one of the endpoints or just outside + * one of them. + * Or this is an exact intersection at one of the curco / v2 ends. + * If lambda is outside of range, move the intersection to somewhere + * just inside the segment. + * Could also snap to an endpoint and redo this as a "through vert" + * case, but the short edge will be cleaned up later and this seems + * less risky to get into "impossible" cases. + */ + if (lambda <= 0.0) { + lambda = 4.0 * (double)FLT_EPSILON; + } + else if (lambda >= 1.0) { + lambda = 1.0 - 4.0 * (double)FLT_EPSILON; + } + } + if (isect == ISECT_LINE_LINE_COLINEAR) { #ifdef DEBUG_CDT if (dbg_level > 1) { - fprintf(stderr, "add_edge_constraint no intersect found, using lambda = 0.5\n"); + fprintf(stderr, "intersect is collinear, treating as through vert\n"); } + dump_v(va, "va"); #endif - lambda = 0.5; + state_through_vert = true; + continue; } #ifdef DEBUG_CDT + interp_v2_v2v2_db(curco, va->co, vb->co, lambda); if (dbg_level > 0) { - fprintf(stderr, "intersect point at %f along va--vb\n", lambda); - if (dbg_level == 1) { + fprintf(stderr, "intersect point at lambda=%.17g along va--vb\n", lambda); + fprintf(stderr, "which is (%g,%g)\n", F2(curco)); + if (dbg_level > 1) { dump_v(va, " va"); dump_v(vb, " vb"); } @@ -1817,15 +1429,15 @@ static void add_edge_constraint( /* 'tout' is 'symedge' from 'va' to third vertex, 'vc'. */ BLI_assert(tout->vert == va); vc = tout->next->vert; - ccw1 = CCW_test(curco, v2->co, vc->co, epsilon); + orient1 = orient2d(curco, v2->co, vc->co); #ifdef DEBUG_CDT if (dbg_level > 1) { fprintf(stderr, "now searching with third vertex "); dump_v(vc, "vc"); - fprintf(stderr, "ccw(vcur, v2, vc) = %d\n", ccw1); + fprintf(stderr, "orient2d(vcur, v2, vc) = %g\n", orient1); } #endif - if (ccw1 == -1 && (vc->visit_index != visit || tout->next->face->visit_index != visit)) { + if (orient1 < 0.0) { /* vcur--v2 should intersect vb--vc. */ #ifdef DEBUG_CDT if (dbg_level > 1) { @@ -1835,7 +1447,7 @@ static void add_edge_constraint( t = tout->next; state_through_vert = false; } - else if (ccw1 == 1 && tout->face->visit_index != visit) { + else if (orient1 > 0.0) { /* vcur--v2 should intersect va--vc. */ #ifdef DEBUG_CDT if (dbg_level > 1) { @@ -1845,7 +1457,7 @@ static void add_edge_constraint( t = tout; state_through_vert = false; } - else if (ccw1 == 0 && vc->visit_index != visit) { + else if (orient1 == 0.0) { #ifdef DEBUG_CDT if (dbg_level > 1) { fprintf(stderr, "ccw==0 case, so going through or to vc\n"); @@ -1856,16 +1468,11 @@ static void add_edge_constraint( } else { #ifdef DEBUG_CDT - fprintf(stderr, "add_edge_constraint desperation search 2\n"); + fprintf(stderr, "add_edge_constraint desperation search needed\n"); #endif - if (tout->face->visit_index != visit) { - /* Treat as if an intersection of va-vc. */ - t = tout; - state_through_vert = false; - } } } - if (++search_count > 10000) { + if (++search_count > 1000000) { fprintf(stderr, "infinite loop? bailing out\n"); BLI_assert(0); /* Catch these while developing. */ break; @@ -2091,6 +1698,304 @@ static void dissolve_symedge(CDT_state *cdt, SymEdge *se) delete_edge(cdt, se); } +/* Return true if we can merge se's vert into se->next's vert + * without making the area of any new triangle formed by doing + * that into a zero or negative area triangle.*/ +static bool can_collapse(const SymEdge *se) +{ + SymEdge *loop_se; + const double *co = se->next->vert->co; + + for (loop_se = se->rot; loop_se != se && loop_se->rot != se; loop_se = loop_se->rot) { + if (orient2d(co, loop_se->next->vert->co, loop_se->rot->next->vert->co) <= 0.0) { + return false; + } + } + return true; +} + +/* + * Merge one end of e onto the other, fixing up surrounding faces. + * + * General situation looks something like: + * + * c-----e + * / \ / \ + * / \ / \ + * a------b-----f + * \ / \ / + * \ / \ / + * d-----g + * + * where ab is the tiny edge. We want to merge a and b and delete edge ab. + * We don't want to change the coordinates of input vertices [We could revisit this + * in the future, as API def doesn't prohibit this, but callers will appreciate if they + * don't change.] + * Sometimes the collapse shouldn't happen because the triangles formed by the changed + * edges may end up with zero or negative area (see can_collapse, above). + * So don't choose a collapse direction that is not allowed or one that has an original vertex + * as origin and a non-original vertex as destination. + * If both collapse directions are allowed by that rule, picke the one with the lower original + * index. + * + * After merging, the faces abc and adb disappear (if they are not the outer face). + * Suppose we merge b onto a. + * Then edges cb and db are deleted. Face cbe becomes cae and face bdg becomes adg. + * Any other faces attached to b now have a in their place. + * We can do this by rotating edges round b, replacing their vert references with a. + * Similar statements can be made about what happens when a merges into b; + * in code below we'll swap a and b to make above lettering work for a b->a merge. + * Return the vert at the collapsed edge, if a collapse happens. + */ +static CDTVert *collapse_tiny_edge(CDT_state *cdt, CDTEdge *e) +{ + CDTVert *va, *vb; + SymEdge *ab_se, *ba_se, *bd_se, *bc_se, *ad_se, *ac_se; + SymEdge *bg_se, *be_se, *se, *gb_se, *ca_se; + bool can_collapse_a_to_b, can_collapse_b_to_a; +#ifdef DEBUG_CDT + int dbg_level = 0; +#endif + + ab_se = &e->symedges[0]; + ba_se = &e->symedges[1]; + va = ab_se->vert; + vb = ba_se->vert; +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "\ncollapse_tiny_edge\n"); + dump_se(&e->symedges[0], "tiny edge"); + fprintf(stderr, "a = [%d], b = [%d]\n", va->index, vb->index); + validate_cdt(cdt, true, false, true); + } +#endif + can_collapse_a_to_b = can_collapse(ab_se); + can_collapse_b_to_a = can_collapse(ba_se); + /* Now swap a and b if necessary and possible, so that from this point on we are collapsing b to + * a. */ + if (va->index > vb->index || !can_collapse_b_to_a) { + if (can_collapse_a_to_b && !(is_original_vert(va, cdt) && !is_original_vert(vb, cdt))) { + SWAP(CDTVert *, va, vb); + ab_se = &e->symedges[1]; + ba_se = &e->symedges[0]; +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "swapped a and b\n"); + } +#endif + } + else { + /* Neither collapse direction is OK. */ +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "neither collapse direction ok\n"); + } +#endif + return NULL; + } + } + bc_se = ab_se->next; + bd_se = ba_se->rot; + if (bd_se == ba_se) { + /* Shouldn't happen. Wire edge in outer face. */ + fprintf(stderr, "unexpected wire edge\n"); + return NULL; + } + vb->merge_to_index = va->merge_to_index == -1 ? va->index : va->merge_to_index; + vb->symedge = NULL; +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, + "vb = v[%d] merges to va = v[%d], vb->merge_to_index=%d\n", + vb->index, + va->index, + vb->merge_to_index); + } +#endif + /* First fix the vertex of intermediate triangles, like bgf. */ + for (se = bd_se->rot; se != bc_se; se = se->rot) { +#ifdef DEBUG_CDT + if (dbg_level > 0) { + dump_se(se, "intermediate tri edge, setting vert to va"); + } +#endif + se->vert = va; + } + ad_se = sym(sym(bd_se)->rot); + ca_se = bc_se->next; + ac_se = sym(ca_se); + if (bd_se->rot != bc_se) { + bg_se = bd_se->rot; + be_se = sym(bc_se)->next; + gb_se = sym(bg_se); + } + else { + bg_se = NULL; + be_se = NULL; + } +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "delete bd, inputs to ad\n"); + dump_se(bd_se, " bd"); + dump_se(ad_se, " ad"); + fprintf(stderr, "delete bc, inputs to ac\n"); + dump_se(bc_se, " bc"); + dump_se(ac_se, " ac"); + fprintf(stderr, "delete ab\n"); + dump_se(ab_se, " ab"); + if (bg_se != NULL) { + fprintf(stderr, "fix up bg, be\n"); + dump_se(bg_se, " bg"); + dump_se(be_se, " be"); + } + } +#endif + add_list_to_input_ids(&ad_se->edge->input_ids, bd_se->edge->input_ids, cdt); + delete_edge(cdt, bd_se); + add_list_to_input_ids(&ac_se->edge->input_ids, bc_se->edge->input_ids, cdt); + delete_edge(cdt, sym(bc_se)); + /* At this point we have this: + * + * c-----e + * / / \ + * / / \ + * a------b-----f + * \ \ / + * \ \ / + * d-----g + * + * Or, if there is not bg_se and be_se, like this: + * + * c + * / + * / + * a------b + * \ + * \ + * d + * + * (But we've already changed the vert field for bg, bf, ..., be to be va.) + */ + if (bg_se != NULL) { + gb_se->next = ad_se; + ad_se->rot = bg_se; + ca_se->next = be_se; + be_se->rot = ac_se; + bg_se->vert = va; + be_se->vert = va; + } + else { + ca_se->next = ad_se; + ad_se->rot = ac_se; + } + /* Don't use delete_edge as it changes too much. */ + ab_se->next = ab_se->rot = NULL; + ba_se->next = ba_se->rot = NULL; + if (va->symedge == ab_se) { + va->symedge = ac_se; + } + return va; +} + +/* + * Check to see if e is tiny (length <= epsilon) and queue it if so. + */ +static void maybe_enqueue_small_feature(CDT_state *cdt, CDTEdge *e, LinkNodePair *tiny_edge_queue) +{ + SymEdge *se, *sesym; +#ifdef DEBUG_CDT + int dbg_level = 0; + + if (dbg_level > 0) { + fprintf(stderr, "\nmaybe_enqueue_small_features\n"); + dump_se(&e->symedges[0], " se0"); + } +#endif + + if (is_deleted_edge(e) || e->in_queue) { +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "returning because of e conditions\n"); + } +#endif + return; + } + se = &e->symedges[0]; + sesym = &e->symedges[1]; + if (len_squared_v2v2_db(se->vert->co, sesym->vert->co) <= cdt->epsilon_squared) { + BLI_linklist_append_pool(tiny_edge_queue, e, cdt->listpool); + e->in_queue = true; +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "Queue tiny edge\n"); + } +#endif + } +} + +/* Consider all edges in rot ring around v for possible enqueing as small features .*/ +static void maybe_enqueue_small_features(CDT_state *cdt, CDTVert *v, LinkNodePair *tiny_edge_queue) +{ + SymEdge *se, *se_start; + + se = se_start = v->symedge; + if (!se_start) { + return; + } + do { + maybe_enqueue_small_feature(cdt, se->edge, tiny_edge_queue); + } while ((se = se->rot) != se_start); +} + +/* Collapse small edges (length <= epsilon) until no more exist. + */ +static void remove_small_features(CDT_state *cdt) +{ + double epsilon = cdt->epsilon; + LinkNodePair tiny_edge_queue = {NULL, NULL}; + BLI_mempool *pool = cdt->listpool; + LinkNode *ln; + CDTEdge *e; + CDTVert *v_change; +#ifdef DEBUG_CDT + int dbg_level = 0; + + if (dbg_level > 0) { + fprintf(stderr, "\nREMOVE_SMALL_FEATURES, epsilon=%g\n", epsilon); + } +#endif + + if (epsilon == 0.0) { + return; + } + + for (ln = cdt->edges; ln; ln = ln->next) { + e = (CDTEdge *)ln->link; + maybe_enqueue_small_feature(cdt, e, &tiny_edge_queue); + } + + while (tiny_edge_queue.list != NULL) { + e = (CDTEdge *)BLI_linklist_pop_pool(&tiny_edge_queue.list, pool); + if (tiny_edge_queue.list == NULL) { + tiny_edge_queue.last_node = NULL; + } + e->in_queue = false; + if (is_deleted_edge(e)) { + continue; + } +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "collapse tiny edge\n"); + dump_se(&e->symedges[0], ""); + } +#endif + v_change = collapse_tiny_edge(cdt, e); + if (v_change) { + maybe_enqueue_small_features(cdt, v_change, &tiny_edge_queue); + } + } +} + /* Remove all non-constraint edges. */ static void remove_non_constraint_edges(CDT_state *cdt) { @@ -2176,7 +2081,7 @@ static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt) e = sorted_edges[i].e; se = &e->symedges[0]; dissolve = true; - if (!edge_touches_frame(e)) { + if (true /*!edge_touches_frame(e)*/) { fleft = se->face; fright = sym(se)->face; if (fleft != cdt->outer_face && fright != cdt->outer_face && @@ -2197,7 +2102,7 @@ static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt) } } -static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constraints) +static void remove_outer_edges_until_constraints(CDT_state *cdt) { LinkNode *fstack = NULL; SymEdge *se, *se_start; @@ -2207,27 +2112,28 @@ static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constrain int dbg_level = 0; if (dbg_level > 0) { - fprintf(stderr, "remove_outer_edges, until_constraints=%d\n", remove_until_constraints); + fprintf(stderr, "remove_outer_edges_until_constraints\n"); } #endif cdt->outer_face->visit_index = visit; - - /* Find an f, not outer face, but touching outer face. */ - f = NULL; - se_start = se = cdt->vert_array[0]->symedge; + /* Walk around outer face, adding faces on other side of dissolvable edges to stack. */ + se_start = se = cdt->outer_face->symedge; do { - if (se->face != cdt->outer_face) { - f = se->face; - break; + if (!is_constrained_edge(se->edge)) { + fsym = sym(se)->face; + if (fsym->visit_index != visit) { +#ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, "pushing f=%p from symedge ", fsym); + dump_se(se, "an outer edge"); + } +#endif + BLI_linklist_prepend_pool(&fstack, fsym, cdt->listpool); + } } - se = se->rot; - } while (se != se_start); - BLI_assert(f != NULL && f->symedge != NULL); - if (f == NULL) { - return; - } - BLI_linklist_prepend_pool(&fstack, f, cdt->listpool); + } while ((se = se->next) != se_start); + while (fstack != NULL) { LinkNode *to_dissolve = NULL; bool dissolvable; @@ -2245,18 +2151,16 @@ static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constrain if (dbg_level > 0) { fprintf(stderr, "top of loop, f=%p\n", f); dump_se_cycle(f->symedge, "visit", 10000); - dump_cdt(cdt, "cdt at top of loop"); + if (dbg_level > 1) { + dump_cdt(cdt, "cdt at top of loop"); + cdt_draw(cdt, "top of dissolve loop"); + } } #endif f->visit_index = visit; se_start = se = f->symedge; do { - if (remove_until_constraints) { - dissolvable = !is_constrained_edge(se->edge); - } - else { - dissolvable = edge_touches_frame(se->edge); - } + dissolvable = !is_constrained_edge(se->edge); #ifdef DEBUG_CDT if (dbg_level > 1) { dump_se(se, "edge in f"); @@ -2306,15 +2210,20 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_ LinkNode *ln; cdt->output_prepared = true; + if (cdt->edges == NULL) { + return; + } /* Make sure all non-deleted faces have a symedge. */ for (ln = cdt->edges; ln; ln = ln->next) { e = (CDTEdge *)ln->link; - if (e->symedges[0].face->symedge == NULL) { - e->symedges[0].face->symedge = &e->symedges[0]; - } - if (e->symedges[1].face->symedge == NULL) { - e->symedges[1].face->symedge = &e->symedges[1]; + if (!is_deleted_edge(e)) { + if (e->symedges[0].face->symedge == NULL) { + e->symedges[0].face->symedge = &e->symedges[0]; + } + if (e->symedges[1].face->symedge == NULL) { + e->symedges[1].face->symedge = &e->symedges[1]; + } } } #ifdef DEBUG_CDT @@ -2335,19 +2244,20 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_ else if (output_type == CDT_CONSTRAINTS_VALID_BMESH) { remove_non_constraint_edges_leave_valid_bmesh(cdt); } - else if (output_type == CDT_FULL || output_type == CDT_INSIDE) { - remove_outer_edges(cdt, output_type == CDT_INSIDE); + else if (output_type == CDT_INSIDE) { + remove_outer_edges_until_constraints(cdt); } } -#define NUM_BOUND_VERTS 4 -#define VERT_OUT_INDEX(v) ((v)->index - NUM_BOUND_VERTS) - -static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_type) +static CDT_result *cdt_get_output(CDT_state *cdt, + const CDT_input *input, + const CDT_output_type output_type) { int i, j, nv, ne, nf, faces_len_total; int orig_map_size, orig_map_index; + int *vert_to_output_map; CDT_result *result; + CDTVert *v; LinkNode *lne, *lnf, *ln; SymEdge *se, *se_start; CDTEdge *e; @@ -2356,35 +2266,70 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t prepare_cdt_for_output(cdt, output_type); result = (CDT_result *)MEM_callocN(sizeof(*result), __func__); + if (cdt->vert_array_len == 0) { + return result; + } - /* All verts except first NUM_BOUND_VERTS will be output. */ - nv = cdt->vert_array_len - NUM_BOUND_VERTS; + /* All verts without a merge_to_index will be output. + * vert_to_output_map[i] will hold the output vertex index + * corresponding to the vert in position i in cdt->vert_array. + * Since merging picked the leftmost-lowermost representative, + * that is not necessarily the same as the vertex with the lowest original + * index (i.e., index in cdt->vert_array), so we need two passes: + * one to get the non-merged-to vertices in vert_to_output_map, + * and a second to put in the merge targets for merged-to vertices. + */ + vert_to_output_map = BLI_memarena_alloc(cdt->arena, (size_t)cdt->vert_array_len * sizeof(int *)); + nv = 0; + for (i = 0; i < cdt->vert_array_len; i++) { + v = cdt->vert_array[i]; + if (v->merge_to_index == -1) { + vert_to_output_map[i] = nv; + nv++; + } + } if (nv <= 0) { return result; } + if (nv < cdt->vert_array_len) { + for (i = 0; i < input->verts_len; i++) { + v = cdt->vert_array[i]; + if (v->merge_to_index != -1) { + add_to_input_ids(&cdt->vert_array[v->merge_to_index]->input_ids, i, cdt); + vert_to_output_map[i] = vert_to_output_map[v->merge_to_index]; + } + } + } result->verts_len = nv; result->vert_coords = MEM_malloc_arrayN(nv, sizeof(result->vert_coords[0]), __func__); /* Make the vertex "orig" map arrays, mapping output verts to lists of input ones. */ orig_map_size = 0; - for (i = 0; i < nv; i++) { - orig_map_size += BLI_linklist_count(cdt->vert_array[i + 4]->input_ids); + for (i = 0; i < cdt->vert_array_len; i++) { + if (cdt->vert_array[i]->merge_to_index == -1) { + orig_map_size += 1 + BLI_linklist_count(cdt->vert_array[i]->input_ids); + } } result->verts_orig_len_table = MEM_malloc_arrayN(nv, sizeof(int), __func__); result->verts_orig_start_table = MEM_malloc_arrayN(nv, sizeof(int), __func__); result->verts_orig = MEM_malloc_arrayN(orig_map_size, sizeof(int), __func__); orig_map_index = 0; - for (i = 0; i < nv; i++) { - j = i + NUM_BOUND_VERTS; - result->vert_coords[i][0] = (float)cdt->vert_array[j]->co[0]; - result->vert_coords[i][1] = (float)cdt->vert_array[j]->co[1]; - result->verts_orig_start_table[i] = orig_map_index; - for (ln = cdt->vert_array[j]->input_ids; ln; ln = ln->next) { - result->verts_orig[orig_map_index++] = POINTER_AS_INT(ln->link); + i = 0; + for (j = 0; j < cdt->vert_array_len; j++) { + v = cdt->vert_array[j]; + if (v->merge_to_index == -1) { + result->vert_coords[i][0] = (float)v->co[0]; + result->vert_coords[i][1] = (float)v->co[1]; + result->verts_orig_start_table[i] = orig_map_index; + result->verts_orig[orig_map_index++] = j; + for (ln = v->input_ids; ln; ln = ln->next) { + result->verts_orig[orig_map_index++] = POINTER_AS_INT(ln->link); + } + result->verts_orig_len_table[i] = orig_map_index - result->verts_orig_start_table[i]; + i++; } - result->verts_orig_len_table[i] = orig_map_index - result->verts_orig_start_table[i]; } ne = 0; @@ -2412,8 +2357,8 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t for (lne = cdt->edges; lne; lne = lne->next) { e = (CDTEdge *)lne->link; if (!is_deleted_edge(e)) { - result->edges[i][0] = VERT_OUT_INDEX(e->symedges[0].vert); - result->edges[i][1] = VERT_OUT_INDEX(e->symedges[1].vert); + result->edges[i][0] = vert_to_output_map[e->symedges[0].vert->index]; + result->edges[i][1] = vert_to_output_map[e->symedges[1].vert->index]; result->edges_orig_start_table[i] = orig_map_index; for (ln = e->input_ids; ln; ln = ln->next) { result->edges_orig[orig_map_index++] = POINTER_AS_INT(ln->link); @@ -2462,7 +2407,7 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t result->faces_start_table[i] = j; se = se_start = f->symedge; do { - result->faces[j++] = VERT_OUT_INDEX(se->vert); + result->faces[j++] = se->vert->index; se = se->next; } while (se != se_start); result->faces_len_table[i] = j - result->faces_start_table[i]; @@ -2478,28 +2423,72 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t return result; } +/** + * Calculate the Constrained Delaunay Triangulation of the 2d elements given in \a input. + * + * A Delaunay triangulation of a set of vertices is a triangulation where no triangle in the + * triangulation has a circumcircle that strictly contains another vertex. Delaunay triangulations + * are avoid long skinny triangles: they maximize the minimum angle of all triangles in the + * triangulation. + * + * A Constrained Delaunay Triangulation adds the requirement that user-provided line segments must + * appear as edges in the output (perhaps divided into several sub-segments). It is not required + * that the input edges be non-intersecting: this routine will calculate the intersections. This + * means that besides triangulating, this routine is also useful for general and robust 2d edge and + * face intersection. + * + * This routine also takes an epsilon parameter in the \a input. Input vertices closer than epsilon + * will be merged, and we collapse tiny edges (less than epsilon length) and skinny triangles + * (having an altitude of less than epsilon). + * + * The current initial Deluanay triangulation algorithm is the Guibas-Stolfi Divide and Conquer + * algorithm (see "Primitives for the Manipulation of General Subdivisions and the Computation of + * Voronoi Diagrams"). and uses Shewchuk's exact predicates to issues where numeric errors cause + * inconsistent geometric judgements. This is followed by inserting edge constraints (including the + * edges implied by faces) using the algorithms discussed in "Fully Dynamic Constrained Delaunay + * Triangulations" by Kallmann, Bieri, and Thalmann. + * + * \param input: points to a CDT_input struct which contains the vertices, edges, and faces to be + * triangulated. \param output_type: specifies which edges to remove after doing the triangulation. + * \return A pointer to an allocated CDT_result struct, which describes the triangulation in terms + * of vertices, edges, and faces, and also has tables to map output elements back to input + * elements. The caller must use BLI_delaunay_2d_cdt_free() on the result when done with it. + * + * See the header file BLI_delaunay_2d.h for details of the CDT_input and CDT_result structs and + * the CDT_output_type enum. + */ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_type output_type) { int nv = input->verts_len; int ne = input->edges_len; int nf = input->faces_len; - double epsilon = (double)input->epsilon; - int i, f, v1, v2; - int fedge_start, fedge_end; - double minx, maxx, miny, maxy; - float *xy; - double vert_co[2]; + int i, iv1, iv2, f, fedge_start, fedge_end; CDT_state *cdt; - CDT_result *result; - CDTVert **verts; - LinkNode *edge_list; + CDTVert *v1, *v2; CDTEdge *face_edge; SymEdge *face_symedge; + LinkNode *edge_list; + CDT_result *result; + static bool called_exactinit = false; #ifdef DEBUG_CDT int dbg_level = 0; #endif + /* The exact orientation and incircle primitives need a one-time initialization of certain + * constants. */ + if (!called_exactinit) { + exactinit(); + called_exactinit = true; + } #ifdef DEBUG_CDT + if (dbg_level > 0) { + fprintf(stderr, + "\n\nCDT CALC, nv=%d, ne=%d, nf=%d, eps=%g\n", + input->verts_len, + input->edges_len, + input->faces_len, + input->epsilon); + } if (dbg_level == -1) { write_cdt_input_to_file(input); } @@ -2514,77 +2503,43 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty return NULL; } - if (nv > 0) { - minx = miny = DBL_MAX; - maxx = maxy = -DBL_MAX; - for (i = 0; i < nv; i++) { - xy = input->vert_coords[i]; - if (xy[0] < minx) { - minx = xy[0]; - } - if (xy[0] > maxx) { - maxx = xy[0]; - } - if (xy[1] < miny) { - miny = xy[1]; - } - if (xy[1] > maxy) { - maxy = xy[1]; - } - } - verts = (CDTVert **)MEM_mallocN(nv * sizeof(CDTVert *), "constrained delaunay"); - } - else { - minx = miny = maxx = maxy = 0; - verts = NULL; - } - - if (epsilon == 0.0) { - epsilon = 1e-8; - } - cdt = cdt_init(minx, maxx, miny, maxy, epsilon); - /* TODO: use a random permutation for order of adding the vertices. */ - for (i = 0; i < nv; i++) { - vert_co[0] = (double)input->vert_coords[i][0]; - vert_co[1] = (double)input->vert_coords[i][1]; - verts[i] = add_point_constraint(cdt, vert_co, i); + cdt = new_cdt_init(input); + initial_triangulation(cdt); #ifdef DEBUG_CDT - if (dbg_level > 3) { - char namebuf[60]; - sprintf(namebuf, "after point %d = (%f,%f)\n", i, vert_co[0], vert_co[1]); - cdt_draw(cdt, namebuf); - dump_cdt(cdt, namebuf); - validate_cdt(cdt, true); - } -#endif + if (dbg_level > 0) { + validate_cdt(cdt, true, false, false); } +#endif + for (i = 0; i < ne; i++) { - v1 = input->edges[i][0]; - v2 = input->edges[i][1]; - if (v1 < 0 || v1 >= nv || v2 < 0 || v2 >= nv) { + iv1 = input->edges[i][0]; + iv2 = input->edges[i][1]; + if (iv1 < 0 || iv1 >= nv || iv2 < 0 || iv2 >= nv) { #ifdef DEBUG_CDT - fprintf(stderr, "edge indices not valid: v1=%d, v2=%d, nv=%d\n", v1, v2, nv); + fprintf(stderr, "edge indices for e%d not valid: v1=%d, v2=%d, nv=%d\n", i, iv1, iv2, nv); #endif continue; } - add_edge_constraint(cdt, verts[v1], verts[v2], i, NULL); + v1 = cdt->vert_array[iv1]; + v2 = cdt->vert_array[iv2]; + if (v1->merge_to_index != -1) { + v1 = cdt->vert_array[v1->merge_to_index]; + } + if (v2->merge_to_index != -1) { + v2 = cdt->vert_array[v2->merge_to_index]; + } + add_edge_constraint(cdt, v1, v2, i, NULL); #ifdef DEBUG_CDT if (dbg_level > 3) { char namebuf[60]; - sprintf(namebuf, "after edge constraint %d = (%d,%d)\n", i, v1, v2); + sprintf(namebuf, "after edge constraint %d = (%d,%d)\n", i, iv1, iv2); cdt_draw(cdt, namebuf); - dump_cdt(cdt, namebuf); - validate_cdt(cdt, true); + // dump_cdt(cdt, namebuf); + validate_cdt(cdt, true, true, false); } #endif } -#ifdef DEBUG_CDT - if (dbg_level > 2) { - cdt_draw(cdt, "after edge constraints"); - dump_cdt(cdt, "after edge constraints"); - validate_cdt(cdt, true); - } -#endif + cdt->face_edge_offset = ne; for (f = 0; f < nf; f++) { int flen = input->faces_len_table[f]; @@ -2597,17 +2552,25 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty } for (i = 0; i < flen; i++) { int face_edge_id = cdt->face_edge_offset + fstart + i; - v1 = input->faces[fstart + i]; - v2 = input->faces[fstart + ((i + 1) % flen)]; - if (v1 < 0 || v1 >= nv || v2 < 0 || v2 >= nv) { + iv1 = input->faces[fstart + i]; + iv2 = input->faces[fstart + ((i + 1) % flen)]; + if (iv1 < 0 || iv1 >= nv || iv2 < 0 || iv2 >= nv) { #ifdef DEBUG_CDT - fprintf(stderr, "face indices not valid: f=%d, v1=%d, v2=%d, nv=%d\n", f, v1, v2, nv); + fprintf(stderr, "face indices not valid: f=%d, iv1=%d, iv2=%d, nv=%d\n", f, iv1, iv2, nv); #endif continue; } - add_edge_constraint(cdt, verts[v1], verts[v2], face_edge_id, &edge_list); + v1 = cdt->vert_array[iv1]; + v2 = cdt->vert_array[iv2]; + if (v1->merge_to_index != -1) { + v1 = cdt->vert_array[v1->merge_to_index]; + } + if (v2->merge_to_index != -1) { + v2 = cdt->vert_array[v2->merge_to_index]; + } + add_edge_constraint(cdt, v1, v2, face_edge_id, &edge_list); #ifdef DEBUG_CDT - if (dbg_level > 1) { + if (dbg_level > 2) { fprintf(stderr, "edges for edge %d:\n", i); for (LinkNode *ln = edge_list; ln; ln = ln->next) { CDTEdge *cdt_e = (CDTEdge *)ln->link; @@ -2619,16 +2582,18 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty } if (dbg_level > 2) { cdt_draw(cdt, "after a face edge"); - dump_cdt(cdt, "after a face edge"); - validate_cdt(cdt, true); + if (dbg_level > 3) { + dump_cdt(cdt, "after a face edge"); + } + validate_cdt(cdt, true, true, false); } #endif if (i == 0) { face_edge = (CDTEdge *)edge_list->link; face_symedge = &face_edge->symedges[0]; - if (face_symedge->vert != verts[v1]) { + if (face_symedge->vert != v1) { face_symedge = &face_edge->symedges[1]; - BLI_assert(face_symedge->vert == verts[v1]); + BLI_assert(face_symedge->vert == v1); } } BLI_linklist_free_pool(edge_list, NULL, cdt->listpool); @@ -2639,22 +2604,36 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty } #ifdef DEBUG_CDT if (dbg_level > 0) { - validate_cdt(cdt, true); + validate_cdt(cdt, true, true, false); } if (dbg_level > 1) { - cdt_draw(cdt, "before cdt_get_output"); + cdt_draw(cdt, "after adding edges and faces"); + if (dbg_level > 2) { + dump_cdt(cdt, "after adding edges and faces"); + } } #endif - result = cdt_get_output(cdt, output_type); + + if (cdt->epsilon > 0.0) { + remove_small_features(cdt); +#ifdef DEBUG_CDT + if (dbg_level > 2) { + cdt_draw(cdt, "after collapse skinny triangles\n"); + if (dbg_level > 3) { + dump_cdt(cdt, "after collapse skinny triangles\n"); + } + } +#endif + } + + result = cdt_get_output(cdt, input, output_type); #ifdef DEBUG_CDT if (dbg_level > 0) { cdt_draw(cdt, "final"); } #endif - if (verts) { - MEM_freeN(verts); - } - cdt_free(cdt); + + new_cdt_free(cdt); return result; } @@ -2710,19 +2689,22 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result) #ifdef DEBUG_CDT -static const char *vertname(const CDTVert *v) +ATTU static const char *vertname(const CDTVert *v) { static char vertnamebuf[20]; - if (v->index < 4) { - sprintf(vertnamebuf, "[%c]", "ABCD"[v->index]); - } - else { - sprintf(vertnamebuf, "[%d]", v->index - 4); - } + sprintf(vertnamebuf, "[%d]", v->index); return vertnamebuf; } +ATTU static const char *sename(const SymEdge *se) +{ + static char senamebuf[20]; + + sprintf(senamebuf, "{%x}", (POINTER_AS_UINT(se)) & 0xFFFF); + return senamebuf; +} + static void dump_v(const CDTVert *v, const char *lab) { fprintf(stderr, "%s%s(%.3f,%.3f)\n", lab, vertname(v), F2(v->co)); @@ -2732,11 +2714,12 @@ static void dump_se(const SymEdge *se, const char *lab) { if (se->next) { fprintf(stderr, - "%s%s((%.3f,%.3f)->(%.3f,%.3f))\n", + "%s%s((%.3f,%.3f)->(%.3f,%.3f))", lab, vertname(se->vert), F2(se->vert->co), F2(se->next->vert->co)); + fprintf(stderr, "%s\n", vertname(se->next->vert)); } else { fprintf(stderr, "%s%s((%.3f,%.3f)->NULL)\n", lab, vertname(se->vert), F2(se->vert->co)); @@ -2791,13 +2774,28 @@ static void dump_cdt_filtered(const CDT_state *cdt, continue; } v = cdt->vert_array[i]; - fprintf(stderr, "%s %x: (%f,%f) symedge=%x\n", vertname(v), PL(v), F2(v->co), PL(v->symedge)); + fprintf(stderr, "%s %x: (%f,%f) symedge=%x", vertname(v), PL(v), F2(v->co), PL(v->symedge)); + if (v->merge_to_index == -1) { + fprintf(stderr, "\n"); + } + else { + fprintf(stderr, " merge to %s\n", vertname(cdt->vert_array[v->merge_to_index])); + continue; + } dump_id_list(v->input_ids, " "); se = v->symedge; cnt = 0; if (se) { fprintf(stderr, " edges out:\n"); do { + if (se->next == NULL) { + fprintf(stderr, " [NULL next/rot symedge, se=%x\n", PL(se)); + break; + } + if (se->next->next == NULL) { + fprintf(stderr, " [NULL next-next/rot symedge, se=%x\n", PL(se)); + break; + } vother = sym(se)->vert; fprintf(stderr, " %s (e=%x, se=%x)\n", vertname(vother), PL(se->edge), PL(se)); se = se->rot; @@ -2839,15 +2837,13 @@ static void dump_cdt_filtered(const CDT_state *cdt, continue; } if (f == cdt->outer_face) { - fprintf(stderr, "outer"); - } - else { - fprintf(stderr, "%x: centroid (%f,%f)", PL(f), F2(f->centroid)); + fprintf(stderr, "%x: outer", PL(f)); } fprintf(stderr, " symedge=%x\n", PL(f->symedge)); dump_id_list(f->input_ids, " "); } fprintf(stderr, "\nOTHER\n"); + fprintf(stderr, "outer_face=%x\n", PL(cdt->outer_face)); fprintf( stderr, "minx=%f, maxx=%f, miny=%f, maxy=%f\n", cdt->minx, cdt->maxx, cdt->miny, cdt->maxy); fprintf(stderr, "margin=%f\n", cdt->margin); @@ -2895,6 +2891,37 @@ static bool reachable_filter(const CDT_state *cdt, int v_index, void *filter_dat return false; } +static void set_min_max(CDT_state *cdt) +{ + int i; + double minx, maxx, miny, maxy; + double *co; + + minx = miny = DBL_MAX; + maxx = maxy = -DBL_MAX; + for (i = 0; i < cdt->vert_array_len; i++) { + co = cdt->vert_array[i]->co; + if (co[0] < minx) { + minx = co[0]; + } + if (co[0] > maxx) { + maxx = co[0]; + } + if (co[1] < miny) { + miny = co[1]; + } + if (co[1] > maxy) { + maxy = co[1]; + } + } + if (minx != DBL_MAX) { + cdt->minx = minx; + cdt->miny = miny; + cdt->maxx = maxx; + cdt->maxy = maxy; + } +} + static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab) { ReachableFilterData rfd; @@ -2903,7 +2930,7 @@ static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const dump_cdt_filtered(cdt, reachable_filter, &rfd, lab); } -/** +/* * Make an html file with svg in it to display the argument cdt. * Mouse-overs will reveal the coordinates of vertices and edges. * Constraint edges are drawn thicker than non-constraint edges. @@ -2916,24 +2943,20 @@ static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const # define THICK_LINE 3 # define VERT_RADIUS 3 # define DRAW_VERT_LABELS 1 -static void cdt_draw(CDT_state *cdt, const char *lab) +# define DRAW_EDGE_LABELS 0 + +static void cdt_draw_region( + CDT_state *cdt, const char *lab, double minx, double miny, double maxx, double maxy) { static bool append = false; FILE *f = fopen(DRAWFILE, append ? "a" : "w"); - double draw_margin = (cdt->maxx - cdt->minx + cdt->maxy - cdt->miny + 1) * 0.05; - double minx = cdt->minx - draw_margin; - double maxx = cdt->maxx + draw_margin; - double miny = cdt->miny - draw_margin; - double maxy = cdt->maxy + draw_margin; - double width, height, aspect; int view_width, view_height; - double scale; + double width, height, aspect, scale; LinkNode *ln; CDTVert *v, *u; CDTEdge *e; int i, strokew; - /* Note: to debug a small area: assign custom min's/max's here. */ width = maxx - minx; height = maxy - miny; aspect = height / width; @@ -2979,10 +3002,23 @@ static void cdt_draw(CDT_state *cdt, const char *lab) fprintf(f, " <title>%s", vertname(u)); fprintf(f, "%s</title>\n", vertname(v)); fprintf(f, "</line>\n"); +# if DRAW_EDGE_LABELS + fprintf(f, + "<text x=\"%f\" y=\"%f\" font-size=\"small\">", + SX(0.5 * (u->co[0] + v->co[0])), + SY(0.5 * (u->co[1] + v->co[1]))); + fprintf(f, "%s", vertname(u)); + fprintf(f, "%s", vertname(v)); + fprintf(f, "%s", sename(&e->symedges[0])); + fprintf(f, "%s</text>\n", sename(&e->symedges[1])); +# endif } - i = cdt->output_prepared ? NUM_BOUND_VERTS : 0; + i = 0; for (; i < cdt->vert_array_len; i++) { v = cdt->vert_array[i]; + if (v->merge_to_index != -1) { + continue; + } fprintf(f, "<circle fill=\"black\" cx=\"%f\" cy=\"%f\" r=\"%d\">\n", SX(v->co[0]), @@ -3006,6 +3042,25 @@ static void cdt_draw(CDT_state *cdt, const char *lab) # undef SY } +static void cdt_draw(CDT_state *cdt, const char *lab) +{ + double draw_margin, minx, maxx, miny, maxy; + + set_min_max(cdt); + draw_margin = (cdt->maxx - cdt->minx + cdt->maxy - cdt->miny + 1) * 0.05; + minx = cdt->minx - draw_margin; + maxx = cdt->maxx + draw_margin; + miny = cdt->miny - draw_margin; + maxy = cdt->maxy + draw_margin; + cdt_draw_region(cdt, lab, minx, miny, maxx, maxy); +} + +static void cdt_draw_vertex_region(CDT_state *cdt, int v, double dist, const char *lab) +{ + const double *co = cdt->vert_array[v]->co; + cdt_draw_region(cdt, lab, co[0] - dist, co[1] - dist, co[0] + dist, co[1] + dist); +} + # define CDTFILE "/tmp/cdtinput.txt" static void write_cdt_input_to_file(const CDT_input *inp) { @@ -3029,16 +3084,18 @@ static void write_cdt_input_to_file(const CDT_input *inp) } # ifndef NDEBUG /* Only used in assert. */ -/** +/* * Is a visible from b: i.e., ab crosses no edge of cdt? * If constrained is true, consider only constrained edges as possible crossers. * In any case, don't count an edge ab itself. + * Note: this is an expensive test if there are a lot of edges. */ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, const CDT_state *cdt) { const LinkNode *ln; const CDTEdge *e; const SymEdge *se, *senext; + double lambda, mu; int ikind; for (ln = cdt->edges; ln; ln = ln->next) { @@ -3055,13 +3112,17 @@ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, con continue; } ikind = isect_seg_seg_v2_lambda_mu_db( - a->co, b->co, se->vert->co, senext->vert->co, NULL, NULL); + a->co, b->co, se->vert->co, senext->vert->co, &lambda, &mu); if (ikind != ISECT_LINE_LINE_NONE) { if (ikind == ISECT_LINE_LINE_COLINEAR) { /* TODO: special test here for overlap. */ continue; } - return false; + /* Allow an intersection very near or at ends, to allow for numerical error. */ + if (lambda > FLT_EPSILON && (1.0 - lambda) > FLT_EPSILON && mu > FLT_EPSILON && + (1.0 - mu) > FLT_EPSILON) { + return false; + } } } return true; @@ -3069,7 +3130,7 @@ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, con # endif # ifndef NDEBUG /* Only used in assert. */ -/** +/* * Check that edge ab satisfies constrained delaunay condition: * That is, for all non-constraint, non-border edges ab, * (1) ab is visible in the constraint graph; and @@ -3078,7 +3139,7 @@ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, con * The argument 'se' specifies ab by: a is se's vert and b is se->next's vert. * Return true if check is OK. */ -static bool is_delaunay_edge(const SymEdge *se, const double epsilon) +static bool is_delaunay_edge(const SymEdge *se) { int i; CDTVert *a, *b, *c; @@ -3099,7 +3160,7 @@ static bool is_delaunay_edge(const SymEdge *se, const double epsilon) b = curse->next->vert; c = curse->next->next->vert; for (ss = curse->rot; ss != curse; ss = ss->rot) { - ok[i] |= delaunay_check(a, b, c, ss->next->vert, epsilon); + ok[i] |= incircle(a->co, b->co, c->co, ss->next->vert->co) <= 0.0; } } return ok[0] || ok[1]; @@ -3113,48 +3174,29 @@ static bool plausible_non_null_ptr(void *p) } # endif -static void validate_face_centroid(SymEdge *se) -{ - SymEdge *senext; -# ifndef NDEBUG - double *centroidp = se->face->centroid; -# endif - double c[2]; - int count; - copy_v2_v2_db(c, se->vert->co); - BLI_assert(reachable(se->next, se, 100)); - count = 1; - for (senext = se->next; senext != se; senext = senext->next) { - add_v2_v2_db(c, senext->vert->co); - count++; - } - c[0] /= count; - c[1] /= count; - BLI_assert(fabs(c[0] - centroidp[0]) < 1e-8 && fabs(c[1] - centroidp[1]) < 1e-8); -} - -static void validate_cdt(CDT_state *cdt, bool check_all_tris) +static void validate_cdt(CDT_state *cdt, + bool check_all_tris, + bool check_delaunay, + bool check_visibility) { - LinkNode *ln, *lne; - int totedges, totfaces, totverts, totborderedges; + LinkNode *ln; + int totedges, totfaces, totverts; CDTEdge *e; SymEdge *se, *sesym, *s; CDTVert *v, *v1, *v2, *v3; CDTFace *f; - double *p; - double margin; int i, limit; bool isborder; if (cdt->output_prepared) { return; } + if (cdt->edges == NULL || cdt->edges->next == NULL) { + return; + } BLI_assert(cdt != NULL); - BLI_assert(cdt->maxx >= cdt->minx); - BLI_assert(cdt->maxy >= cdt->miny); totedges = 0; - totborderedges = 0; for (ln = cdt->edges; ln; ln = ln->next) { e = (CDTEdge *)ln->link; se = &e->symedges[0]; @@ -3165,13 +3207,6 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris) } totedges++; isborder = is_border_edge(e, cdt); - if (isborder) { - totborderedges++; - BLI_assert((se->face == cdt->outer_face && sesym->face != cdt->outer_face) || - (se->face != cdt->outer_face && sesym->face == cdt->outer_face)); - } - /* BLI_assert(se->face != sesym->face); - * Not required because faces can have intruding wire edges. */ BLI_assert(se->vert != sesym->vert); BLI_assert(se->edge == sesym->edge && se->edge == e); BLI_assert(sym(se) == sesym && sym(sesym) == se); @@ -3179,8 +3214,6 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris) se = &e->symedges[i]; v = se->vert; f = se->face; - p = v->co; - UNUSED_VARS_NDEBUG(p); BLI_assert(plausible_non_null_ptr(v)); if (f != NULL) { BLI_assert(plausible_non_null_ptr(f)); @@ -3198,9 +3231,9 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris) v1 = se->vert; v2 = se->next->vert; v3 = se->next->next->vert; - BLI_assert(CCW_test(v1->co, v2->co, v3->co, 0.0)); - BLI_assert(CCW_test(v2->co, v3->co, v1->co, 0.0)); - BLI_assert(CCW_test(v3->co, v1->co, v2->co, 0.0)); + BLI_assert(orient2d(v1->co, v2->co, v3->co) >= 0.0); + BLI_assert(orient2d(v2->co, v3->co, v1->co) >= 0.0); + BLI_assert(orient2d(v3->co, v1->co, v2->co) >= 0.0); } UNUSED_VARS_NDEBUG(limit); BLI_assert(se->next->next != se); @@ -3211,19 +3244,23 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris) s = s->next; } while (s != se); } - BLI_assert(isborder || is_visible(se->vert, se->next->vert, false, cdt)); - BLI_assert(isborder || is_delaunay_edge(se, cdt->epsilon)); + if (check_visibility) { + BLI_assert(isborder || is_visible(se->vert, se->next->vert, false, cdt)); + } + if (!isborder && check_delaunay) { + BLI_assert(is_delaunay_edge(se)); + } } totverts = 0; - margin = cdt->margin; for (i = 0; i < cdt->vert_array_len; i++) { - totverts++; v = cdt->vert_array[i]; BLI_assert(plausible_non_null_ptr(v)); - p = v->co; - BLI_assert(p[0] >= cdt->minx - margin && p[0] <= cdt->maxx + margin); - UNUSED_VARS_NDEBUG(margin); - BLI_assert(v->symedge->vert == v); + if (v->merge_to_index != -1) { + BLI_assert(v->merge_to_index >= 0 && v->merge_to_index < cdt->vert_array_len); + continue; + } + totverts++; + BLI_assert(cdt->vert_array_len <= 1 || v->symedge->vert == v); } totfaces = 0; for (ln = cdt->faces; ln; ln = ln->next) { @@ -3236,23 +3273,1111 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris) if (f == cdt->outer_face) { continue; } - for (lne = cdt->edges; lne; lne = lne->next) { - e = (CDTEdge *)lne->link; - if (!is_deleted_edge(e)) { - for (i = 0; i < 2; i++) { - if (e->symedges[i].face == f) { - validate_face_centroid(&e->symedges[i]); - } - } - } - } - p = f->centroid; - BLI_assert(p[0] >= cdt->minx - margin && p[0] <= cdt->maxx + margin); - BLI_assert(p[1] >= cdt->miny - margin && p[1] <= cdt->maxy + margin); } /* Euler's formula for planar graphs. */ - if (check_all_tris) { + if (check_all_tris && totfaces > 1) { BLI_assert(totverts - totedges + totfaces == 2); } } #endif + +/* Jonathan Shewchuk's adaptive predicates, trimmed to those needed here. + * Permission obtained by private communication from Jonathan to include this code in Blender. + */ + +/* + * Routines for Arbitrary Precision Floating-point Arithmetic + * and Fast Robust Geometric Predicates + * (predicates.c) + * + * May 18, 1996 + * + * Placed in the public domain by + * Jonathan Richard Shewchuk + * School of Computer Science + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, Pennsylvania 15213-3891 + * jrs@cs.cmu.edu + * + * This file contains C implementation of algorithms for exact addition + * and multiplication of floating-point numbers, and predicates for + * robustly performing the orientation and incircle tests used in + * computational geometry. The algorithms and underlying theory are + * described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- + * Point Arithmetic and Fast Robust Geometric Predicates." Technical + * Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon + * University, Pittsburgh, Pennsylvania, May 1996. (Submitted to + * Discrete & Computational Geometry.) + * + * This file, the paper listed above, and other information are available + * from the Web page http://www.cs.cmu.edu/~quake/robust.html . + * + * Using this code: + * + * First, read the short or long version of the paper (from the Web page + * above). + * + * Be sure to call exactinit() once, before calling any of the arithmetic + * functions or geometric predicates. Also be sure to turn on the + * optimizer when compiling this file. + * + * On some machines, the exact arithmetic routines might be defeated by the + * use of internal extended precision floating-point registers. Sometimes + * this problem can be fixed by defining certain values to be volatile, + * thus forcing them to be stored to memory and rounded off. This isn't + * a great solution, though, as it slows the arithmetic down. + * + * To try this out, write "#define INEXACT volatile" below. Normally, + * however, INEXACT should be defined to be nothing. ("#define INEXACT".) + */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +/* Which of the following two methods of finding the absolute values is + * fastest is compiler-dependent. A few compilers can inline and optimize + * the fabs() call; but most will incur the overhead of a function call, + * which is disastrously slow. A faster way on IEEE machines might be to + * mask the appropriate bit, but that's difficult to do in C. + */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that + * performs an approximate operation, and a "tail" that computes the + * roundoff error of that operation. + * + * The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), + * Split(), and Two_Product() are all implemented as described in the + * reference. Each of these macros requires certain variables to be + * defined in the calling routine. The variables `bvirt', `c', `abig', + * `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because + * they store the result of an operation that may incur roundoff error. + * The input parameter `x' (or the highest numbered `x_' parameter) must + * also be declared `INEXACT'. + */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (double)(a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Fast_Two_Diff_Tail(a, b, x, y) \ + bvirt = a - x; \ + y = bvirt - b + +#define Fast_Two_Diff(a, b, x, y) \ + x = (double)(a - b); \ + Fast_Two_Diff_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (double)(x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (double)(a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (double)(a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (double)(a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (double)(splitter * a); \ + abig = (double)(c - a); \ + ahi = c - abig; \ + alo = a - ahi + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (double)(a * b); \ + Two_Product_Tail(a, b, x, y) + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (double)(a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (double)(a * a); \ + Square_Tail(a, x, y) + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b, _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b, _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +static double splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */ +static double m_epsilon; /* = 2^(-p). Used to estimate roundoff errors. */ +/* A set of coefficients used to calculate maximum roundoff errors. */ +static double resulterrbound; +static double ccwerrboundA, ccwerrboundB, ccwerrboundC; +static double o3derrboundA, o3derrboundB, o3derrboundC; +static double iccerrboundA, iccerrboundB, iccerrboundC; +static double isperrboundA, isperrboundB, isperrboundC; + +/* exactinit() Initialize the variables used for exact arithmetic. + * + * `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in + * floating-point arithmetic. `epsilon' bounds the relative roundoff + * error. It is used for floating-point error analysis. + * + * `splitter' is used to split floating-point numbers into two half- + * length significands for exact multiplication. + * + * I imagine that a highly optimizing compiler might be too smart for its + * own good, and somehow cause this routine to fail, if it pretends that + * floating-point arithmetic is too much like real arithmetic. + * + * Don't change this routine unless you fully understand it. + */ + +static void exactinit(void) +{ + double half; + double check, lastcheck; + int every_other; + + every_other = 1; + half = 0.5; + m_epsilon = 1.0; + splitter = 1.0; + check = 1.0; + /* Repeatedly divide `epsilon' by two until it is too small to add to + * one without causing roundoff. (Also check if the sum is equal to + * the previous sum, for machines that round up instead of using exact + * rounding. Not that this library will work on such machines anyway. + */ + do { + lastcheck = check; + m_epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = 1.0 + m_epsilon; + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (3.0 + 8.0 * m_epsilon) * m_epsilon; + ccwerrboundA = (3.0 + 16.0 * m_epsilon) * m_epsilon; + ccwerrboundB = (2.0 + 12.0 * m_epsilon) * m_epsilon; + ccwerrboundC = (9.0 + 64.0 * m_epsilon) * m_epsilon * m_epsilon; + o3derrboundA = (7.0 + 56.0 * m_epsilon) * m_epsilon; + o3derrboundB = (3.0 + 28.0 * m_epsilon) * m_epsilon; + o3derrboundC = (26.0 + 288.0 * m_epsilon) * m_epsilon * m_epsilon; + iccerrboundA = (10.0 + 96.0 * m_epsilon) * m_epsilon; + iccerrboundB = (4.0 + 48.0 * m_epsilon) * m_epsilon; + iccerrboundC = (44.0 + 576.0 * m_epsilon) * m_epsilon * m_epsilon; + isperrboundA = (16.0 + 224.0 * m_epsilon) * m_epsilon; + isperrboundB = (5.0 + 72.0 * m_epsilon) * m_epsilon; + isperrboundC = (71.0 + 1408.0 * m_epsilon) * m_epsilon * m_epsilon; +} + +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero + * components from the output expansion. + * + * Sets h = e + f. See the long version of my paper for details. + * + * If round-to-even is used (as with IEEE 754), maintains the strongly + * nonoverlapping property. (That is, if e is strongly nonoverlapping, h + * will be also.) Does NOT maintain the nonoverlapping or nonadjacent + * properties. + */ + +static int fast_expansion_sum_zeroelim( + int elen, double *e, int flen, double *f, double *h) /* h cannot be e or f. */ +{ + double Q; + INEXACT double Qnew; + INEXACT double hh; + INEXACT double bvirt; + double avirt, bround, around; + int eindex, findex, hindex; + double enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } + else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } + else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } + else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, + * eliminating zero components from the + * output expansion. + * + * Sets h = be. See either version of my paper for details. + * + * Maintains the nonoverlapping property. If round-to-even is used (as + * with IEEE 754), maintains the strongly nonoverlapping and nonadjacent + * properties as well. (That is, if e has one of these properties, so + * will h.) + */ + +static int scale_expansion_zeroelim(int elen, + double *e, + double b, + double *h) /* e and h cannot be the same. */ +{ + INEXACT double Q, sum; + double hh; + INEXACT double product1; + double product0; + int eindex, hindex; + double enow; + INEXACT double bvirt; + double avirt, bround, around; + INEXACT double c; + INEXACT double abig; + double ahi, alo, bhi, blo; + double err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/* estimate() Produce a one-word estimate of an expansion's value. + * + * See either version of my paper for details. + */ + +static double estimate(int elen, double *e) +{ + double Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/* orient2d() Adaptive exact 2D orientation test. Robust. + * + * Return a positive value if the points pa, pb, and pc occur + * in counterclockwise order; a negative value if they occur + * in clockwise order; and zero if they are collinear. The + * result is also a rough approximation of twice the signed + * area of the triangle defined by the three points. + * + * This uses exact arithmetic to ensure a correct answer. The + * result returned is the determinant of a matrix. + * This determinant is computed adaptively, in the sense that exact + * arithmetic is used only to the degree it is needed to ensure that the + * returned value has the correct sign. Hence, orient2d() is usually quite + * fast, but will run more slowly when the input points are collinear or + * nearly so. + */ + +static double orient2dadapt(const double *pa, const double *pb, const double *pc, double detsum) +{ + INEXACT double acx, acy, bcx, bcy; + double acxtail, acytail, bcxtail, bcytail; + INEXACT double detleft, detright; + double detlefttail, detrighttail; + double det, errbound; + double B[4], C1[8], C2[12], D[16]; + INEXACT double B3; + int C1length, C2length, Dlength; + double u[4]; + INEXACT double u3; + INEXACT double s1, t1; + double s0, t0; + + INEXACT double bvirt; + double avirt, bround, around; + INEXACT double c; + INEXACT double abig; + double ahi, alo, bhi, blo; + double err1, err2, err3; + INEXACT double _i, _j; + double _0; + + acx = (double)(pa[0] - pc[0]); + bcx = (double)(pb[0] - pc[0]); + acy = (double)(pa[1] - pc[1]); + bcy = (double)(pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = ccwerrboundB * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); + det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return (D[Dlength - 1]); +} + +static double orient2d(const double *pa, const double *pb, const double *pc) +{ + double detleft, detright, det; + double detsum, errbound; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (detleft > 0.0) { + if (detright <= 0.0) { + return det; + } + else { + detsum = detleft + detright; + } + } + else if (detleft < 0.0) { + if (detright >= 0.0) { + return det; + } + else { + detsum = -detleft - detright; + } + } + else { + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return orient2dadapt(pa, pb, pc, detsum); +} + +/* incircle() Adaptive exact 2D incircle test. Robust. + * + * Return a positive value if the point pd lies inside the + * circle passing through pa, pb, and pc; a negative value if + * it lies outside; and zero if the four points are cocircular. + * The points pa, pb, and pc must be in counterclockwise + * order, or the sign of the result will be reversed. + * + * This uses exact arithmetic to ensure a correct answer. + * The result returned is the determinant of a matrix. + * This determinant is computed adaptively, in the sense that exact + * arithmetic is used only to the degree it is needed to ensure that the + * returned value has the correct sign. Hence, incircle() is usually quite + * fast, but will run more slowly when the input points are cocircular or + * nearly so. + */ + +static double incircleadapt( + const double *pa, const double *pb, const double *pc, const double *pd, double permanent) +{ + INEXACT double adx, bdx, cdx, ady, bdy, cdy; + double det, errbound; + + INEXACT double bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + double bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + double bc[4], ca[4], ab[4]; + INEXACT double bc3, ca3, ab3; + double axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + double bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + double cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + double abdet[64]; + int ablen; + double fin1[1152], fin2[1152]; + double *finnow, *finother, *finswap; + int finlength; + + double adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT double adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + double adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + double aa[4], bb[4], cc[4]; + INEXACT double aa3, bb3, cc3; + INEXACT double ti1, tj1; + double ti0, tj0; + double u[4], v[4]; + INEXACT double u3, v3; + double temp8[8], temp16a[16], temp16b[16], temp16c[16]; + double temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + double axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + double bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + double cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + double axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + double axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + double axtbctt[8], aytbctt[8], bxtcatt[8]; + double bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + double abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + double abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT double abtt3, bctt3, catt3; + double negate; + + INEXACT double bvirt; + double avirt, bround, around; + INEXACT double c; + INEXACT double abig; + double ahi, alo, bhi, blo; + double err1, err2, err3; + INEXACT double _i, _j; + double _0; + + adx = (double)(pa[0] - pd[0]); + bdx = (double)(pb[0] - pd[0]); + cdx = (double)(pc[0] - pd[0]); + ady = (double)(pa[1] - pd[1]); + bdy = (double)(pb[1] - pd[1]); + cdy = (double)(pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = iccerrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0) && + (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); + det += ((adx * adx + ady * ady) * + ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * + ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * + ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } + else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } + else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } + else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); + finswap = finnow; + finnow = finother; + finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +static double incircle(const double *pa, const double *pb, const double *pc, const double *pd) +{ + double adx, bdx, cdx, ady, bdy, cdy; + double bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + double alift, blift, clift; + double det; + double permanent, errbound; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady); + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return incircleadapt(pa, pb, pc, pd, permanent); +} diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index 1712738e859..2ed7d7d7345 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -439,42 +439,66 @@ void BLI_rcti_union(rcti *rct1, const rcti *rct2) void BLI_rctf_init(rctf *rect, float xmin, float xmax, float ymin, float ymax) { - if (xmin <= xmax) { - rect->xmin = xmin; - rect->xmax = xmax; - } - else { - rect->xmax = xmin; - rect->xmin = xmax; - } - if (ymin <= ymax) { - rect->ymin = ymin; - rect->ymax = ymax; - } - else { - rect->ymax = ymin; - rect->ymin = ymax; - } + rect->xmin = xmin; + rect->xmax = xmax; + rect->ymin = ymin; + rect->ymax = ymax; + + BLI_rctf_sanitize(rect); } void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax) { - if (xmin <= xmax) { - rect->xmin = xmin; - rect->xmax = xmax; + rect->xmin = xmin; + rect->xmax = xmax; + rect->ymin = ymin; + rect->ymax = ymax; + + BLI_rcti_sanitize(rect); +} + +/** + * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively. + * If this returns false, #BLI_rctf_sanitize() can be called to address this. + * + * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to + * have max < min. Usually this is what you'd want though. + */ +bool BLI_rctf_is_valid(const rctf *rect) +{ + return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax); +} + +bool BLI_rcti_is_valid(const rcti *rect) +{ + return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax); +} + +/** + * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively. + */ +void BLI_rctf_sanitize(rctf *rect) +{ + if (rect->xmin > rect->xmax) { + SWAP(float, rect->xmin, rect->xmax); } - else { - rect->xmax = xmin; - rect->xmin = xmax; + if (rect->ymin > rect->ymax) { + SWAP(float, rect->ymin, rect->ymax); } - if (ymin <= ymax) { - rect->ymin = ymin; - rect->ymax = ymax; + + BLI_assert(BLI_rctf_is_valid(rect)); +} + +void BLI_rcti_sanitize(rcti *rect) +{ + if (rect->xmin > rect->xmax) { + SWAP(int, rect->xmin, rect->xmax); } - else { - rect->ymax = ymin; - rect->ymin = ymax; + if (rect->ymin > rect->ymax) { + SWAP(int, rect->ymin, rect->ymax); } + + BLI_assert(BLI_rcti_is_valid(rect)); } void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f6cf68f7daf..5a834f31528 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3371,6 +3371,11 @@ static void lib_link_workspaces(FileData *fd, Main *bmain) } } } + else { + /* If we're reading a layout without screen stored, it's useless and we shouldn't keep it + * around. */ + BKE_workspace_layout_remove(bmain, workspace, layout); + } } id->tag &= ~LIB_TAG_NEED_LINK; @@ -3869,7 +3874,7 @@ static void direct_link_bones(FileData *fd, Bone *bone) bone->bbone_next = newdataadr(fd, bone->bbone_next); bone->bbone_prev = newdataadr(fd, bone->bbone_prev); - bone->flag &= ~BONE_DRAW_ACTIVE; + bone->flag &= ~(BONE_DRAW_ACTIVE | BONE_DRAW_LOCKED_WEIGHT); link_list(fd, &bone->childbase); @@ -6215,8 +6220,6 @@ static void direct_link_object(FileData *fd, Object *ob) BKE_object_empty_draw_type_set(ob, ob->empty_drawtype); } - ob->derivedDeform = NULL; - ob->derivedFinal = NULL; BKE_object_runtime_reset(ob); link_list(fd, &ob->pc_ids); diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index afe0d728934..e92ae6e73cc 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -636,6 +636,29 @@ static ARegion *do_versions_add_region(int regiontype, const char *name) return ar; } +static void do_versions_area_ensure_tool_region(Main *bmain, + const short space_type, + const short region_flag) +{ + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == space_type) { + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); + if (!ar) { + ARegion *header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + ar = do_versions_add_region(RGN_TYPE_TOOLS, "tools region"); + BLI_insertlinkafter(regionbase, header, ar); + ar->alignment = RGN_ALIGN_LEFT; + ar->flag = region_flag; + } + } + } + } + } +} + static void do_version_bones_split_bbone_scale(ListBase *lb) { for (Bone *bone = lb->first; bone; bone = bone->next) { @@ -2828,6 +2851,35 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Files stored pre 2.5 (possibly re-saved with newer versions) may have non-visible + * spaces without a header (visible/active ones are properly versioned). + * Multiple version patches below assume there's always a header though. So inserting this + * patch in-between older ones to add a header when needed. + * + * From here on it should be fine to assume there always is a header. + */ + if (!MAIN_VERSION_ATLEAST(bmain, 283, 1)) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion *ar_header = do_versions_find_region_or_null(regionbase, RGN_TYPE_HEADER); + + if (!ar_header) { + /* Headers should always be first in the region list, except if there's also a + * tool-header. These were only introduced in later versions though, so should be + * fine to always insert headers first. */ + BLI_assert(!do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)); + + ARegion *ar = do_versions_add_region(RGN_TYPE_HEADER, "header 2.83.1 versioning"); + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + BLI_addhead(regionbase, ar); + } + } + } + } + } + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { @@ -3709,7 +3761,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; /* All spaces that use tools must be eventually added. */ ARegion *ar = NULL; - if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && + if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ) && ((ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)) == NULL)) { /* Add tool header. */ ar = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header"); @@ -4309,6 +4361,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Keep this block, even when empty. */ + /* Sequencer Tool region */ + do_versions_area_ensure_tool_region(bmain, SPACE_SEQ, RGN_FLAG_HIDDEN); + /* Cloth internal springs */ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { for (ModifierData *md = ob->modifiers.first; md; md = md->next) { diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index bc43d9605e2..8c7a0c4f7b2 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -207,13 +207,20 @@ static void blo_update_defaults_screen(bScreen *screen, } } - /* Show top-bar by default. */ + /* Show tool-header by default (for most cases at least, hide for others). */ + const bool hide_image_tool_header = STREQ(workspace_name, "Rendering"); for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = regionbase->first; ar; ar = ar->next) { if (ar->regiontype == RGN_TYPE_TOOL_HEADER) { - ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER); + if ((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) { + ar->flag |= RGN_FLAG_HIDDEN; + } + else { + ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER); + } } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index b1f70848bdc..94ee8d46675 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -164,6 +164,17 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_view3d.face_front); } + if (!USER_VERSION_ATLEAST(283, 1)) { + FROM_DEFAULT_V4_UCHAR(space_view3d.bone_locked_weight); + } + + if (!USER_VERSION_ATLEAST(283, 2)) { + FROM_DEFAULT_V4_UCHAR(space_info.info_property); + FROM_DEFAULT_V4_UCHAR(space_info.info_property_text); + FROM_DEFAULT_V4_UCHAR(space_info.info_operator); + FROM_DEFAULT_V4_UCHAR(space_info.info_operator_text); + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 30e7cf476fb..401f0ef6a85 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2066,9 +2066,7 @@ static void write_customdata(WriteData *wd, int count, CustomData *data, CustomDataLayer *layers, - CustomDataMask cddata_mask, - int partial_type, - int partial_count) + CustomDataMask cddata_mask) { int i; @@ -2105,16 +2103,7 @@ static void write_customdata(WriteData *wd, else { CustomData_file_write_info(layer->type, &structname, &structnum); if (structnum) { - /* when using partial visibility, the MEdge and MFace layers - * are smaller than the original, so their type and count is - * passed to make this work */ - if (layer->type != partial_type) { - datasize = structnum * count; - } - else { - datasize = structnum * partial_count; - } - + datasize = structnum * count; writestruct_id(wd, DATA, structname, datasize, layer->data); } else { @@ -2133,85 +2122,70 @@ static void write_customdata(WriteData *wd, static void write_mesh(WriteData *wd, Mesh *mesh) { - CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - if (mesh->id.us > 0 || wd->use_memfile) { - /* write LibData */ - { - /* write a copy of the mesh, don't modify in place because it is - * not thread safe for threaded renders that are reading this */ - Mesh *old_mesh = mesh; - Mesh copy_mesh = *mesh; - mesh = ©_mesh; - - /* cache only - don't write */ - mesh->mface = NULL; - mesh->totface = 0; - memset(&mesh->fdata, 0, sizeof(mesh->fdata)); - - /** - * Those calls: - * - Reduce mesh->xdata.totlayer to number of layers to write. - * - Fill xlayers with those layers to be written. - * Note that mesh->xdata is from now on invalid for Blender, - * but this is why the whole mesh is a temp local copy! - */ - CustomData_file_write_prepare( - &mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); - CustomData_file_write_prepare( - &mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); - flayers = flayers_buff; - CustomData_file_write_prepare( - &mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); - CustomData_file_write_prepare( - &mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - - writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh); - write_iddata(wd, &mesh->id); - - /* direct data */ - if (mesh->adt) { - write_animdata(wd, mesh->adt); - } + /* Write a copy of the mesh with possibly reduced number of data layers. + * Don't edit the original since other threads might be reading it. */ + Mesh *old_mesh = mesh; + Mesh copy_mesh = *mesh; + mesh = ©_mesh; + + /* cache only - don't write */ + mesh->mface = NULL; + mesh->totface = 0; + memset(&mesh->fdata, 0, sizeof(mesh->fdata)); + + /* Reduce xdata layers, fill xlayers with layers to be written. + * This makes xdata invalid for Blender, which is why we made a + * temporary local copy. */ + CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; + + CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); + CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); + flayers = flayers_buff; + CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); + CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); + + writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh); + write_iddata(wd, &mesh->id); - writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); - writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); + /* direct data */ + if (mesh->adt) { + write_animdata(wd, mesh->adt); + } - write_customdata( - wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, CD_MASK_MESH.vmask, -1, 0); - write_customdata( - wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, CD_MASK_MESH.emask, -1, 0); - /* fdata is really a dummy - written so slots align */ - write_customdata( - wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, CD_MASK_MESH.fmask, -1, 0); - write_customdata( - wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, CD_MASK_MESH.lmask, -1, 0); - write_customdata( - wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, CD_MASK_MESH.pmask, -1, 0); + writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); + writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); - /* restore pointer */ - mesh = old_mesh; - } - } + write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, CD_MASK_MESH.vmask); + write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, CD_MASK_MESH.emask); + /* fdata is really a dummy - written so slots align */ + write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, CD_MASK_MESH.fmask); + write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, CD_MASK_MESH.lmask); + write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, CD_MASK_MESH.pmask); - if (vlayers && vlayers != vlayers_buff) { - MEM_freeN(vlayers); - } - if (elayers && elayers != elayers_buff) { - MEM_freeN(elayers); - } - if (flayers && flayers != flayers_buff) { - MEM_freeN(flayers); - } - if (llayers && llayers != llayers_buff) { - MEM_freeN(llayers); - } - if (players && players != players_buff) { - MEM_freeN(players); + /* restore pointer */ + mesh = old_mesh; + + /* free temporary data */ + if (vlayers && vlayers != vlayers_buff) { + MEM_freeN(vlayers); + } + if (elayers && elayers != elayers_buff) { + MEM_freeN(elayers); + } + if (flayers && flayers != flayers_buff) { + MEM_freeN(flayers); + } + if (llayers && llayers != llayers_buff) { + MEM_freeN(llayers); + } + if (players && players != players_buff) { + MEM_freeN(players); + } } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 07e159b3241..d3b3541a539 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -60,16 +60,7 @@ #define BEVEL_MATCH_SPEC_WEIGHT 0.2 //#define DEBUG_CUSTOM_PROFILE_CUTOFF -//#define DEBUG_CUSTOM_PROFILE_SAMPLE - -#if defined(DEBUG_PROFILE_ORIENTATION_DRAW) || defined(DEBUG_CUSTOM_PROFILE_PIPE) -static float debug_color_red[4] = {1.0f, 0.0f, 0.0f, 1.0f}; -static float debug_color_blue[4] = {0.0f, 0.0f, 1.0f, 1.0f}; -extern void DRW_debug_sphere(const float center[3], const float radius, const float color[4]); -extern void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]); -#endif - -/* happens far too often, uncomment for development */ +/* Happens far too often, uncomment for development. */ // #define BEVEL_ASSERT_PROJECT /* for testing */ @@ -155,6 +146,8 @@ typedef struct Profile { float *prof_co; /** Like prof_co, but for seg power of 2 >= seg */ float *prof_co_2; + /** Mark a special case so the these parameters aren't reset with others. */ + bool special_params; } Profile; #define PRO_SQUARE_R 1e4f #define PRO_CIRCLE_R 2.0f @@ -266,7 +259,7 @@ typedef struct BevVert { VMesh *vmesh; } BevVert; -/* face classification: note depend on F_RECON > F_EDGE > F_VERT */ +/* Face classification. Note: depends on F_RECON > F_EDGE > F_VERT */ typedef enum { /** Used when there is no face at all */ F_NONE, @@ -290,10 +283,6 @@ enum { ANGLE_LARGER = 1, }; -#if 0 -static const char* fkind_names[] = {"F_NONE", "F_ORIG", "F_VERT", "F_EDGE", "F_RECON"}; /* DEBUG */ -#endif - /** Bevel parameters and state */ typedef struct BevelParams { /** Records BevVerts made: key BMVert*, value BevVert* */ @@ -359,12 +348,8 @@ typedef struct BevelParams { // #pragma GCC diagnostic ignored "-Wpadded" -/* Some flags to re-enable old behavior for a while, - * in case fixes broke things not caught by regression tests. */ -static int bev_debug_flags = 0; -#define DEBUG_OLD_PLANE_SPECIAL (bev_debug_flags & 1) -#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2) -#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4) +/* Only for debugging, shouldn't be in blender repo. */ +// #include "bevdebug.c" /* use the unused _BM_ELEM_TAG_ALT flag to flag the 'long' loops (parallel to beveled edge) * of edge-polygons. */ @@ -1314,7 +1299,10 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, flo } /* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco. */ -static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3]) +static void project_to_edge(const BMEdge *e, + const float co_a[3], + const float co_b[3], + float projco[3]) { float otherco[3]; @@ -1330,16 +1318,13 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], * It is the closest point on the beveled edge to the line segment between bndv and bndv->next. */ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) { - EdgeHalf *e; - Profile *pro; float start[3], end[3], co3[3], d1[3], d2[3]; - bool do_linear_interp; + bool do_linear_interp = true; + EdgeHalf *e = bndv->ebev; + Profile *pro = &bndv->profile; copy_v3_v3(start, bndv->nv.co); copy_v3_v3(end, bndv->next->nv.co); - pro = &bndv->profile; - e = bndv->ebev; - do_linear_interp = true; if (e) { do_linear_interp = false; pro->super_r = bp->pro_super_r; @@ -1350,23 +1335,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } normalize_v3(pro->proj_dir); project_to_edge(e->e, start, end, pro->middle); - if (DEBUG_OLD_PROJ_TO_PERP_PLANE) { - /* Put arc endpoints on plane with normal proj_dir, containing middle. */ - add_v3_v3v3(co3, start, pro->proj_dir); - if (!isect_line_plane_v3(pro->start, start, co3, pro->middle, pro->proj_dir)) { - /* Shouldn't happen. */ - copy_v3_v3(pro->start, start); - } - add_v3_v3v3(co3, end, pro->proj_dir); - if (!isect_line_plane_v3(pro->end, end, co3, pro->middle, pro->proj_dir)) { - /* Shouldn't happen. */ - copy_v3_v3(pro->end, end); - } - } - else { - copy_v3_v3(pro->start, start); - copy_v3_v3(pro->end, end); - } + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->end, end); /* Default plane to project onto is the one with triangle start - middle - end in it. */ sub_v3_v3v3(d1, pro->middle, start); sub_v3_v3v3(d2, pro->middle, end); @@ -1384,69 +1354,55 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) * If the profile is going to lead into unbeveled edges on each side * (that is, both BoundVerts are "on-edge" points on non-beveled edges) */ - if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) { - do_linear_interp = true; - } - else { - if (DEBUG_OLD_PROJ_TO_PERP_PLANE) { - copy_v3_v3(pro->start, start); - copy_v3_v3(pro->end, end); - } - if (DEBUG_OLD_FLAT_MID) { - copy_v3_v3(pro->middle, bv->v->co); - } - else { - copy_v3_v3(pro->middle, bv->v->co); - if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) { - /* Want mid at the meet point of next and prev offset edges. */ - float d3[3], d4[3], co4[3], meetco[3], isect2[3]; - int isect_kind; - - sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co); - sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co); - normalize_v3(d3); - normalize_v3(d4); - if (nearly_parallel(d3, d4)) { - /* Offset lines are collinear - want linear interpolation. */ - mid_v3_v3v3(pro->middle, start, end); - do_linear_interp = true; - } - else { - add_v3_v3v3(co3, start, d3); - add_v3_v3v3(co4, end, d4); - isect_kind = isect_line_line_v3(start, co3, end, co4, meetco, isect2); - if (isect_kind != 0) { - copy_v3_v3(pro->middle, meetco); - } - else { - /* Offset lines don't intersect - want linear interpolation. */ - mid_v3_v3v3(pro->middle, start, end); - do_linear_interp = true; - } - } - } - } - copy_v3_v3(pro->end, end); - sub_v3_v3v3(d1, pro->middle, start); - normalize_v3(d1); - sub_v3_v3v3(d2, pro->middle, end); - normalize_v3(d2); - cross_v3_v3v3(pro->plane_no, d1, d2); - normalize_v3(pro->plane_no); - if (nearly_parallel(d1, d2)) { - /* Whole profile is collinear with edge: just interpolate. */ + copy_v3_v3(pro->middle, bv->v->co); + if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) { + /* Want mid at the meet point of next and prev offset edges. */ + float d3[3], d4[3], co4[3], meetco[3], isect2[3]; + int isect_kind; + + sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co); + sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co); + normalize_v3(d3); + normalize_v3(d4); + if (nearly_parallel(d3, d4)) { + /* Offset lines are collinear - want linear interpolation. */ + mid_v3_v3v3(pro->middle, start, end); do_linear_interp = true; } else { - copy_v3_v3(pro->plane_co, bv->v->co); - copy_v3_v3(pro->proj_dir, pro->plane_no); + add_v3_v3v3(co3, start, d3); + add_v3_v3v3(co4, end, d4); + isect_kind = isect_line_line_v3(start, co3, end, co4, meetco, isect2); + if (isect_kind != 0) { + copy_v3_v3(pro->middle, meetco); + } + else { + /* Offset lines don't intersect - want linear interpolation. */ + mid_v3_v3v3(pro->middle, start, end); + do_linear_interp = true; + } } } + copy_v3_v3(pro->end, end); + sub_v3_v3v3(d1, pro->middle, start); + normalize_v3(d1); + sub_v3_v3v3(d2, pro->middle, end); + normalize_v3(d2); + cross_v3_v3v3(pro->plane_no, d1, d2); + normalize_v3(pro->plane_no); + if (nearly_parallel(d1, d2)) { + /* Whole profile is collinear with edge: just interpolate. */ + do_linear_interp = true; + } + else { + copy_v3_v3(pro->plane_co, bv->v->co); + copy_v3_v3(pro->proj_dir, pro->plane_no); + } } copy_v3_v3(pro->plane_co, start); } else if (bndv->is_arc_start) { - /* Assume pro->middle was alredy set. */ + /* Assume pro->middle was already set. */ copy_v3_v3(pro->start, start); copy_v3_v3(pro->end, end); pro->super_r = PRO_CIRCLE_R; @@ -1455,6 +1411,17 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) zero_v3(pro->proj_dir); do_linear_interp = false; } + else if (bp->vertex_only) { + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->middle, bv->v->co); + copy_v3_v3(pro->end, end); + pro->super_r = bp->pro_super_r; + zero_v3(pro->plane_co); + zero_v3(pro->plane_no); + zero_v3(pro->proj_dir); + do_linear_interp = false; + } + if (do_linear_interp) { pro->super_r = PRO_LINE_R; copy_v3_v3(pro->start, start); @@ -1467,11 +1434,11 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } } -/* Maybe move the profile plane for bndv->ebev to the plane its profile's start, and the +/* Maybe move the profile plane for bndv->ebev to the plane its profile's start, and the * original beveled vert, bmv. This will usually be the plane containing its adjacent * non-beveled edges, but sometimes the start and the end are not on those edges. * - * Currently just used in build boundary terminal edge */ + * Currently just used in #build_boundary_terminal_edge */ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert) { float d1[3], d2[3], no[3], no2[3], no3[3], dot2, dot3; @@ -1496,6 +1463,9 @@ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert) copy_v3_v3(bndv->profile.plane_no, no); } } + + /* We've changed the parameters from their defaults, so don't recalculate them later. */ + pro->special_params = true; } /* Move the profile plane for the two BoundVerts involved in a weld. @@ -1531,6 +1501,10 @@ static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *b copy_v3_v3(bndv2->profile.plane_no, no); } } + + /* We've changed the parameters from their defaults, so don't recalculate them later. */ + bndv1->profile.special_params = true; + bndv2->profile.special_params = true; } /* return 1 if a and b are in CCW order on the normal side of f, @@ -1748,6 +1722,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b else { map_ok = make_unit_square_map(pro->start, pro->middle, pro->end, map); } + if (bp->vmesh_method == BEVEL_VMESH_CUTOFF && map_ok) { /* Calculate the "height" of the profile by putting the (0,0) and (1,1) corners of the * un-transformed profile throughout the 2D->3D map and calculating the distance between them. @@ -1759,6 +1734,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b mul_v3_m4v3(top_corner, map, p); pro->height = len_v3v3(bottom_corner, top_corner); } + /* The first iteration is the nseg case, the second is the seg_2 case (if it's needed) */ for (i = 0; i < 2; i++) { if (i == 0) { @@ -2321,15 +2297,20 @@ static bool eh_on_plane(EdgeHalf *e) /* Calculate the profiles for all the BoundVerts of VMesh vm */ static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm) { - BoundVert *bndv; - - bndv = vm->boundstart; + BoundVert *bndv = vm->boundstart; do { - set_profile_params(bp, bv, bndv); - /* Use the miter profile spacing struct if the default is filled with the custom profile. */ - bool miter_profile = bp->use_custom_profile && (bndv->is_arc_start || bndv->is_patch_start); - /* Don't bother reversing the profile if it's a miter profile */ - bool reverse_profile = !bndv->is_profile_start && !miter_profile; + /* In special cases the params will have already been set. */ + if (!bndv->profile.special_params) { + set_profile_params(bp, bv, bndv); + } + bool miter_profile = false; + bool reverse_profile = false; + if (bp->use_custom_profile) { + /* Use the miter profile spacing struct if the default is filled with the custom profile. */ + miter_profile = (bndv->is_arc_start || bndv->is_patch_start); + /* Don't bother reversing the profile if it's a miter profile */ + reverse_profile = !bndv->is_profile_start && !miter_profile; + } calculate_profile(bp, bndv, reverse_profile, miter_profile); } while ((bndv = bndv->next) != vm->boundstart); } @@ -2357,8 +2338,6 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr } } while ((e = e->next) != efirst); - calculate_vm_profiles(bp, bv, vm); - if (construct) { set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp); if (vm->count == 2) { @@ -2471,15 +2450,13 @@ static void build_boundary_terminal_edge(BevelParams *bp, } } } - calculate_vm_profiles(bp, bv, vm); if (bv->edgecount >= 3) { /* Special case: snap profile to plane of adjacent two edges. */ bndv = vm->boundstart; BLI_assert(bndv->ebev != NULL); + set_profile_params(bp, bv, bndv); move_profile_plane(bndv, bv->v); - /* This step happens before the profile orientation pass so don't reverse the profile. */ - calculate_profile(bp, bndv, false, false); } if (construct) { @@ -2506,17 +2483,6 @@ static void build_boundary_terminal_edge(BevelParams *bp, vm->mesh_kind = M_POLY; } } -#ifdef DEBUG_CUSTOM_PROFILE_WELD - if (bp->seg > 1) { - printf("Terminal Edge Profile Coordinates:\n"); - for (int k = 0; k < bp->seg; k++) { - printf("%0.4f, %0.4f, %0.4f\n", - (double)vm->boundstart->profile.prof_co[3 * k], - (double)vm->boundstart->profile.prof_co[3 * k + 1], - (double)vm->boundstart->profile.prof_co[3 * k + 2]); - } - } -#endif } /* Helper for build_boundary to handle special miters */ @@ -2831,8 +2797,6 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) adjust_miter_coords(bp, bv, emiter); } - calculate_vm_profiles(bp, bv, vm); - if (construct) { set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp); @@ -3185,53 +3149,6 @@ static void regularize_profile_orientation(BevelParams *bp, BMEdge *bme) } } -#ifdef DEBUG_PROFILE_ORIENTATION_DRAW -/** - * Draws markers on beveled edges showing the side that the profile starts on. A sphere shows - * the start side of the profile where it starts, and the lines connected to the sphere show which - * edge the orientation corresponds to. - * \note Only drawn while bevel is calculating, the debug geometry is not persistent. - */ -static void debug_draw_profile_orientation(BevelParams *bp, BMesh *bm) -{ - BMIter iter; - BMEdge *bmedge; - float middle[3]; - - BM_ITER_MESH (bmedge, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(bmedge, BM_ELEM_TAG)) { - mid_v3_v3v3(middle, bmedge->v1->co, bmedge->v2->co); - - /* Draw the orientation for the first side of the edge. */ - EdgeHalf *edge_half = find_edge_half(find_bevvert(bp, bmedge->v1), bmedge); - if (edge_half->leftv->is_profile_start) { /* The left boundvert defines the profiles. */ - DRW_debug_sphere(edge_half->leftv->nv.co, 0.04f, debug_color_red); - DRW_debug_line_v3v3(middle, edge_half->leftv->nv.co, debug_color_red); - DRW_debug_line_v3v3(bmedge->v1->co, edge_half->leftv->nv.co, debug_color_red); - } - else { - DRW_debug_sphere(edge_half->rightv->nv.co, 0.04f, debug_color_red); - DRW_debug_line_v3v3(middle, edge_half->rightv->nv.co, debug_color_red); - DRW_debug_line_v3v3(bmedge->v1->co, edge_half->rightv->nv.co, debug_color_red); - } - - /* Draw the orientation for the second side of the edge. */ - edge_half = find_edge_half(find_bevvert(bp, bmedge->v2), bmedge); - if (edge_half->leftv->is_profile_start) { - DRW_debug_sphere(edge_half->leftv->nv.co, 0.05f, debug_color_blue); - DRW_debug_line_v3v3(middle, edge_half->leftv->nv.co, debug_color_blue); - DRW_debug_line_v3v3(bmedge->v2->co, edge_half->leftv->nv.co, debug_color_blue); - } - else { - DRW_debug_sphere(edge_half->rightv->nv.co, 0.05f, debug_color_blue); - DRW_debug_line_v3v3(middle, edge_half->rightv->nv.co, debug_color_blue); - DRW_debug_line_v3v3(bmedge->v2->co, edge_half->rightv->nv.co, debug_color_blue); - } - } - } -} -#endif - /* Adjust the offsets for a single cycle or chain. * For chains and some cycles, a fast solution exists. * Otherwise, we set up and solve a linear least squares problem @@ -3643,9 +3560,6 @@ static void vmesh_copy_equiv_verts(VMesh *vm) /* Calculate and return in r_cent the centroid of the center poly */ static void vmesh_center(VMesh *vm, float r_cent[3]) { -#ifdef DEBUG_CUSTOM_PROFILE_ADJ - printf("VMESH CENTER\n"); -#endif int n, ns2, i; n = vm->count; @@ -4157,9 +4071,8 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) copy_v3_v3(bndv->profile.plane_co, bndv->profile.start); cross_v3_v3v3(bndv->profile.plane_no, bndv->profile.start, bndv->profile.end); copy_v3_v3(bndv->profile.proj_dir, bndv->profile.plane_no); - /* No need to reverse the profile or use the miter profile spacing struct because this case - * isn't used with custom profiles. */ - calculate_profile(bp, bndv, false, false); + /* Calculate profiles again because we started over with new boundverts. */ + calculate_profile(bp, bndv, false, false); /* No custom profiles in this case. */ /* Just building the boundaries here, so sample the profile halfway through */ get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co); @@ -4359,6 +4272,10 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3]) copy_v3_v3(va, pro->start); copy_v3_v3(vb, pro->end); + if (compare_v3v3(va, vb, BEVEL_EPSILON_D)) { + copy_v3_v3(co, va); + return; + } /* Get a plane with the normal pointing along the beveled edge */ sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co); @@ -4367,13 +4284,8 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3]) closest_to_plane_v3(va0, plane, va); closest_to_plane_v3(vb0, plane, vb); closest_to_plane_v3(vmid0, plane, pro->middle); - if (make_unit_square_map(va0, vmid0, vb0, m)) { + if (make_unit_square_map(va0, vmid0, vb0, m) && invert_m4_m4(minv, m)) { /* Transform co and project it onto superellipse */ - if (!invert_m4_m4(minv, m)) { - /* shouldn't happen */ - BLI_assert(!"failed inverse during pipe profile snap"); - return; - } mul_v3_m4v3(p, minv, co); snap_to_superellipsoid(p, pro->super_r, midline); @@ -4394,14 +4306,6 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3]) */ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) { -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - printf("PIPE ADJ VMESH\n"); - float green[4] = {0.0f, 1.0f, 0.0f, 1.0f}; - float blue[4] = {0.0f, 0.0f, 1.0f, 1.0f}; - float red[4] = {1.0f, 0.0f, 0.0f, 1.0f}; - float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - float *color; -#endif int i, j, k, n_bndv, ns, half_ns, ipipe1, ipipe2, ring; VMesh *vm; bool even, midline; @@ -4418,11 +4322,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) ipipe1 = vpipe->index; ipipe2 = vpipe->next->next->index; -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - printf("ipipe1: %d\n", ipipe1); - printf("ipipe2: %d\n", ipipe2); -#endif - for (i = 0; i < n_bndv; i++) { for (j = 1; j <= half_ns; j++) { for (k = 0; k <= half_ns; k++) { @@ -4456,18 +4355,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) /* Place the vertex by interpolatin between the two profile points using the factor. */ interp_v3_v3v3(mesh_vert(vm, i, j, k)->co, profile_point_pipe1, profile_point_pipe2, f); -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - printf("(%d, %d, %d)\n", i, j, k); - printf("f: %.3f\n", f); - printf("point 1: (%.3f, %.3f, %.3f)\n", - profile_point_pipe1[0], - profile_point_pipe1[1], - profile_point_pipe1[2]); - printf("point 2: (%.3f, %.3f, %.3f)\n", - profile_point_pipe2[0], - profile_point_pipe2[1], - profile_point_pipe2[2]); -#endif } else { /* A tricky case is for the 'square' profiles and an even nseg: we want certain @@ -4479,33 +4366,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) } } } -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - /* Draw the locations of all the vertices after the "snapping" process */ - for (i = 0; i < n_bndv; i++) { - for (j = 1; j <= half_ns; j++) { - for (k = 1; k <= ns; k++) { - if (!is_canon(vm, i, j, k)) { - continue; - } - switch (i) { - case 0: - color = red; - break; - case 1: - color = green; - break; - case 2: - color = blue; - break; - case 3: - color = white; - break; - } - DRW_debug_sphere(mesh_vert(vm, i, j, k)->co, 0.01f, color); - } - } - } -#endif return vm; } @@ -4922,20 +4782,6 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert odd = ns % 2; BLI_assert(n_bndv >= 3 && ns > 1); - /* Add support for profiles in vertex only in-plane bevels. */ - if (bp->vertex_only) { - bndv = bv->vmesh->boundstart; - do { - Profile *pro = &bndv->profile; - copy_v3_v3(pro->middle, bv->v->co); - pro->super_r = bp->pro_super_r; - bool miter_profile = bp->use_custom_profile && (bndv->is_arc_start || bndv->is_patch_start); - /* Orientation doesn't matter when only beveling vertices */ - calculate_profile(bp, bndv, false, miter_profile); - bndv = bndv->next; - } while (bndv != bv->vmesh->boundstart); - } - if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd && !bp->use_custom_profile) { vm1 = square_out_adj_vmesh(bp, bv); } @@ -5105,6 +4951,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) { #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("BEVEL BUILD CUTOFF\n"); +# define F3(v) (v)[0], (v)[1], (v)[2] int j; #endif int i; @@ -5143,10 +4990,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("Corner vertices:\n"); for (j = 0; j < n_bndv; j++) { - printf(" (%.3f, %.3f, %.3f)\n", - (double)mesh_vert(bv->vmesh, j, 1, 0)->co[0], - (double)mesh_vert(bv->vmesh, j, 1, 0)->co[1], - (double)mesh_vert(bv->vmesh, j, 1, 0)->co[2]); + printf(" (%.3f, %.3f, %.3f)\n", F3(mesh_vert(bv->vmesh, j, 1, 0)->co)); } #endif @@ -5204,21 +5048,14 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) if (bndv->is_patch_start || bndv->is_arc_start) { printf(" Miter profile\n"); } - printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n", - (double)mesh_vert(bv->vmesh, i, 1, 0)->co[0], - (double)mesh_vert(bv->vmesh, i, 1, 0)->co[1], - (double)mesh_vert(bv->vmesh, i, 1, 0)->co[2]); + printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 0)->co)); #endif /* Add profile point vertices to the face, including the last one. */ for (int k = 0; k < bp->seg + 1; k++) { face_bmverts[k + 1] = mesh_vert(bv->vmesh, i, 0, k)->v; /* Leave room for first vert. */ #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF - printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n", - k, - (double)mesh_vert(bv->vmesh, i, 0, k)->co[0], - (double)mesh_vert(bv->vmesh, i, 0, k)->co[1], - (double)mesh_vert(bv->vmesh, i, 0, k)->co[2]); + printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n", k, F3(mesh_vert(bv->vmesh, i, 0, k)->co)); #endif } @@ -5226,10 +5063,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) if (build_center_face) { face_bmverts[bp->seg + 2] = mesh_vert(bv->vmesh, i, 1, 1)->v; #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF - printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n", - (double)mesh_vert(bv->vmesh, i, 1, 1)->co[0], - (double)mesh_vert(bv->vmesh, i, 1, 1)->co[1], - (double)mesh_vert(bv->vmesh, i, 1, 1)->co[2]); + printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 1)->co)); #endif } @@ -5428,7 +5262,6 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv) * we have to make it here. */ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) { - VMesh *vm = bv->vmesh; BMVert *v1, *v2; BMEdge *e_eg, *bme; @@ -5455,8 +5288,6 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) zero_v3(pro->plane_co); zero_v3(pro->plane_no); zero_v3(pro->proj_dir); - /* there's no orientation chain to continue so the orientation of the bevel doesn't matter. */ - calculate_profile(bp, bndv, false, false); for (k = 1; k < ns; k++) { get_profile_point(bp, pro, k, ns, co); @@ -5519,15 +5350,17 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) } else { /* Get the last of the two BoundVerts. */ weld2 = bndv; + set_profile_params(bp, bv, weld1); + set_profile_params(bp, bv, weld2); move_weld_profile_planes(bv, weld1, weld2); - if (!bp->use_custom_profile) { /* Else profile recalculated in next loop. */ - calculate_profile(bp, weld1, !weld1->is_profile_start, false); - calculate_profile(bp, weld2, !weld2->is_profile_start, false); - } } } } while ((bndv = bndv->next) != vm->boundstart); + /* It's simpler to calculate all profiles only once at a single moment, so keep just a single + * profile calculation here, the last point before actual mesh verts are created. */ + calculate_vm_profiles(bp, bv, vm); + /* Create new vertices and place them based on the profiles. */ /* Copy other ends to (i, 0, ns) for all i, and fill in profiles for edges. */ bndv = vm->boundstart; @@ -5536,10 +5369,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) /* bndv's last vert along the boundary arc is the first of the next BoundVert's arc. */ copy_mesh_vert(vm, i, 0, ns, bndv->next->index, 0, 0); - /* Fix the profile orientations if it's not a miter profile. */ - if (bp->use_custom_profile && !bndv->is_arc_start && !bndv->is_patch_start) { - calculate_profile(bp, bndv, !bndv->is_profile_start, false); - } if (vm->mesh_kind != M_ADJ) { for (k = 1; k < ns; k++) { if (bndv->ebev) { @@ -5589,24 +5418,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) copy_mesh_vert(bv->vmesh, weld2->index, 0, ns - k, weld1->index, 0, k); } } -#ifdef DEBUG_CUSTOM_PROFILE_WELD - if (weld && ns > 1) { - printf("Weld1 profile coordinates:\n"); - for (k = 0; k < ns; k++) { - printf("%0.4f, %0.4f, %0.4f\n", - (double)weld1->profile.prof_co[3 * k], - (double)weld1->profile.prof_co[3 * k + 1], - (double)weld1->profile.prof_co[3 * k + 2]); - } - printf("Weld2 profile coordinates\n"); - for (k = 0; k < ns; k++) { - printf("%0.4f, %0.4f, %0.4f\n", - (double)weld2->profile.prof_co[3 * k], - (double)weld2->profile.prof_co[3 * k + 1], - (double)weld2->profile.prof_co[3 * k + 2]); - } - } -#endif /* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff options. */ vpipe = NULL; @@ -7423,7 +7234,7 @@ void BM_mesh_bevel(BMesh *bm, adjust_offsets(&bp, bm); } - /* Maintain consistent orientations for the unsymmetrical custom profiles. */ + /* Maintain consistent orientations for the asymmetrical custom profiles. */ if (bp.use_custom_profile) { BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { @@ -7431,11 +7242,6 @@ void BM_mesh_bevel(BMesh *bm, } } } -#ifdef DEBUG_PROFILE_ORIENTATION_DRAW - if (bp.use_custom_profile) { - debug_draw_profile_orientation(&bp, bm); - } -#endif /* Build the meshes around vertices, now that positions are final */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -7511,22 +7317,6 @@ void BM_mesh_bevel(BMesh *bm, BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { BM_elem_flag_disable(l, BM_ELEM_LONG_TAG); } - -#ifdef DEBUG_CUSTOM_PROFILE_SAMPLE - printf("Profile spacing:\n"); - printf("Seg values:\n"); - if (bp.pro_spacing.xvals != NULL) { - for (int i = 0; i < bp.seg; i++) { - printf("(%.3f, %.3f)\n", bp.pro_spacing.xvals[i], bp.pro_spacing.yvals[i]); - } - } - if (bp.pro_spacing.seg_2 != bp.seg && bp.pro_spacing.seg_2 != 0) { - printf("Seg_2 values:\n"); - for (int i = 0; i < bp.pro_spacing.seg_2; i++) { - printf("(%0.2f, %0.2f)\n", bp.pro_spacing.xvals_2[i], bp.pro_spacing.yvals_2[i]); - } - } -#endif } /* primary free */ diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c index c3687c5d477..ce40256221e 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.c +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c @@ -57,7 +57,7 @@ struct EDBMSplitBestFaceData { * Track the range of vertices in edgenet along the faces normal, * find the lowest since it's most likely to be most co-planar with the face. */ - float best_face_range_on_normal_axis; + float best_edgenet_range_on_face_normal; BMFace *r_best_face; }; @@ -76,11 +76,14 @@ static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f, SWAP(float, min, max); } - BMVert *v_test = l_b->v; BMEdge **e_iter = &data->edgenet[0]; + BMEdge *e_next = data->edgenet[1]; + BMVert *v_test = ELEM((*e_iter)->v1, e_next->v1, e_next->v2) ? (*e_iter)->v2 : (*e_iter)->v1; + int verts_len = data->edgenet_len - 1; for (int i = verts_len; i--; e_iter++) { v_test = BM_edge_other_vert(*e_iter, v_test); + BLI_assert(v_test != NULL); if (!BM_face_point_inside_test(f, v_test->co)) { return false; } @@ -93,9 +96,9 @@ static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f, } } - const float test_face_range_on_normal_axis = max - min; - if (test_face_range_on_normal_axis < data->best_face_range_on_normal_axis) { - data->best_face_range_on_normal_axis = test_face_range_on_normal_axis; + const float test_edgenet_range_on_face_normal = max - min; + if (test_edgenet_range_on_face_normal < data->best_edgenet_range_on_face_normal) { + data->best_edgenet_range_on_face_normal = test_edgenet_range_on_face_normal; data->r_best_face = f; } @@ -111,114 +114,79 @@ static bool bm_vert_pair_share_splittable_face_cb(BMFace *UNUSED(f), float(*data)[3] = userdata; float *v_a_co = data[0]; float *v_a_b_dir = data[1]; + const float range_min = -FLT_EPSILON; + const float range_max = 1.0f + FLT_EPSILON; + + float co[3]; + float dir[3]; + float lambda_b; - float lambda; - if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_a->prev->v->co, l_a->next->v->co, &lambda)) { - if (IN_RANGE(lambda, 0.0f, 1.0f)) { + copy_v3_v3(co, l_a->prev->v->co); + sub_v3_v3v3(dir, l_a->next->v->co, co); + if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, NULL, &lambda_b)) { + if (IN_RANGE(lambda_b, range_min, range_max)) { return true; } - else if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_b->prev->v->co, l_b->next->v->co, &lambda)) { - return IN_RANGE(lambda, 0.0f, 1.0f); + else { + copy_v3_v3(co, l_b->prev->v->co); + sub_v3_v3v3(dir, l_b->next->v->co, co); + if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, NULL, &lambda_b)) { + return IN_RANGE(lambda_b, range_min, range_max); + } } } return false; } -void BM_vert_weld_linked_wire_edges_into_linked_faces( - BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len) +static BMFace *bm_vert_pair_best_face_get( + BMVert *v_a, BMVert *v_b, BMEdge **edgenet, const int edgenet_len, const float epsilon) { - BMEdge **edgenet = *r_edgenet; - int edgenet_alloc_len = *r_edgenet_alloc_len; - - BMIter iter; - BMEdge *e; - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - int edgenet_len = 0; - BMVert *v_other = v; - while (BM_edge_is_wire(e)) { - if (edgenet_alloc_len == edgenet_len) { - edgenet_alloc_len = (edgenet_alloc_len + 1) * 2; - edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)); - } - edgenet[edgenet_len++] = e; - v_other = BM_edge_other_vert(e, v_other); - if (v_other == v) { - /* Endless loop. */ - break; - } - - BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other); - if (e_next == e) { - /* Vert is wire_endpoint. */ - edgenet_len = 0; - break; - } - - BMEdge *e_test = e_next; - while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != e) { - if (e_test->l) { - /* Vert is linked to a face. */ - goto l_break; - } - } - - e = e_next; - } + BMFace *r_best_face = NULL; - BMLoop *dummy; - BMFace *best_face; + BLI_assert(v_a != v_b); - l_break: - if (edgenet_len == 0) { - /* Nothing to do. */ - continue; - } - if (edgenet_len == 1) { - float data[2][3]; - copy_v3_v3(data[0], v_other->co); - sub_v3_v3v3(data[1], v->co, data[0]); - best_face = BM_vert_pair_shared_face_cb( - v_other, v, true, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy); - } - else { - struct EDBMSplitBestFaceData data = { - .edgenet = edgenet, - .edgenet_len = edgenet_len, - .best_face_range_on_normal_axis = FLT_MAX, - .r_best_face = NULL, - }; - BM_vert_pair_shared_face_cb( - v_other, v, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy); - - if (data.r_best_face) { - float no[3], min = FLT_MAX, max = -FLT_MAX; - copy_v3_v3(no, data.r_best_face->no); - BMVert *v_test; - BMIter f_iter; - BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) { - float dot = dot_v3v3(v_test->co, no); - if (dot < min) { - min = dot; - } - if (dot > max) { - max = dot; - } + BMLoop *dummy; + if (edgenet_len == 1) { + float data[2][3]; + copy_v3_v3(data[0], v_b->co); + sub_v3_v3v3(data[1], v_a->co, data[0]); + r_best_face = BM_vert_pair_shared_face_cb( + v_a, v_b, false, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy); + } + else { + struct EDBMSplitBestFaceData data = { + .edgenet = edgenet, + .edgenet_len = edgenet_len, + .best_edgenet_range_on_face_normal = FLT_MAX, + .r_best_face = NULL, + }; + BM_vert_pair_shared_face_cb( + v_a, v_b, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy); + + if (data.r_best_face) { + /* Check if the edgenet's range is smaller than the face's range. */ + float no[3], min = FLT_MAX, max = -FLT_MAX; + copy_v3_v3(no, data.r_best_face->no); + BMVert *v_test; + BMIter f_iter; + BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) { + float dot = dot_v3v3(v_test->co, no); + if (dot < min) { + min = dot; } - float range = max - min + 2 * epsilon; - if (range < data.best_face_range_on_normal_axis) { - data.r_best_face = NULL; + if (dot > max) { + max = dot; } } - best_face = data.r_best_face; - } - - if (best_face) { - BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL); + float face_range_on_normal = max - min + 2 * epsilon; + if (face_range_on_normal < data.best_edgenet_range_on_face_normal) { + data.r_best_face = NULL; + } } + r_best_face = data.r_best_face; } - *r_edgenet = edgenet; - *r_edgenet_alloc_len = edgenet_alloc_len; + return r_best_face; } /** \} */ @@ -517,7 +485,8 @@ static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, voi #define INTERSECT_EDGES -bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap) +bool BM_mesh_intersect_edges( + BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap) { bool ok = false; @@ -560,6 +529,9 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas verts_remain_len++; } } + + /* The index will indicate which cut in pair_array this vertex belongs to. */ + BM_elem_index_set(v, -1); } bm->elem_index_dirty |= BM_VERT; @@ -621,6 +593,10 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas /* Don't test hidden edges or smaller than the minimum distance. * These have already been handled in the vertices overlap. */ BM_elem_index_set(e, 0); + if (split_faces) { + /* Tag to be ignored. */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + } continue; } @@ -631,6 +607,10 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas else { BM_elem_index_set(e, EDGE_REMAIN_TO_TEST); edges_remain_len++; + if (split_faces) { + /* Tag to be ignored. */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + } } } @@ -656,7 +636,7 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas BLI_bvhtree_insert(tree_edges_act, i, co[0], 2); } else if (edge_test == EDGE_REMAIN_TO_TEST) { - BLI_assert(tree_edges_act); + BLI_assert(tree_edges_remain); e->head.index = 0; copy_v3_v3(co[0], e->v1->co); copy_v3_v3(co[1], e->v2->co); @@ -823,6 +803,11 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev); lambda_prev = pair_elem->lambda; e = pair_elem->edge; + if (split_faces) { + /* Tagged edges are ignored when split faces. + * Un-tag these. */ + BM_elem_flag_disable(e, BM_ELEM_TAG); + } BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda); pair_elem->vert = v_new; @@ -856,10 +841,148 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT); BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT); BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem); - - BLI_ghash_insert(r_targetmap, (*pair_iter)[0].vert, (*pair_iter)[1].vert); + BMVert *v_key, *v_val; + v_key = (*pair_iter)[0].vert; + v_val = (*pair_iter)[1].vert; + BLI_ghash_insert(r_targetmap, v_key, v_val); + if (split_faces) { + BM_elem_index_set(v_key, i * 2); + BM_elem_index_set(v_val, i * 2 + 1); + } } + if (split_faces) { + BMEdge **edgenet = NULL; + int edgenet_alloc_len = 0; + + struct EDBMSplitElem *pair_flat = (struct EDBMSplitElem *)&pair_array[0]; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + continue; + } + + BMVert *va, *vb, *va_dest = NULL; + va = e->v1; + vb = e->v2; + + int v_cut = BM_elem_index_get(va); + int v_cut_other = BM_elem_index_get(vb); + if (v_cut == -1 && v_cut_other == -1) { + if (!BM_elem_flag_test(va, BM_ELEM_TAG) && !BM_elem_flag_test(vb, BM_ELEM_TAG)) { + /* Ignore edges out of context. */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + continue; + } + + /* Tag to avoid testing again. */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + + if (v_cut == -1) { + SWAP(BMVert *, va, vb); + v_cut = v_cut_other; + v_cut_other = -1; + } + + v_cut += v_cut % 2 ? -1 : 1; + va_dest = pair_flat[v_cut].vert; + + BMFace *best_face = NULL; + int edgenet_len = 0; + BMVert *v_other_dest, *v_other = vb; + BMEdge *e_net = e; + while (true) { + if (edgenet_alloc_len == edgenet_len) { + edgenet_alloc_len = (edgenet_alloc_len + 1) * 2; + edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)); + } + edgenet[edgenet_len++] = e_net; + + if (v_cut_other != -1) { + v_cut_other += v_cut_other % 2 ? -1 : 1; + v_other_dest = pair_flat[v_cut_other].vert; + } + else { + v_other_dest = v_other; + } + + if (BM_edge_exists(va_dest, v_other_dest)) { + /* No need to detect face. (Optimization). */ + break; + } + + best_face = bm_vert_pair_best_face_get( + va_dest, v_other_dest, edgenet, edgenet_len, dist); + + if (best_face) { + if (va_dest != va) { + e_net = edgenet[0]; + if (edgenet_len > 1) { + vb = BM_edge_other_vert(e_net, va); + } + else { + vb = v_other_dest; + } + edgenet[0] = BM_edge_create(bm, va_dest, vb, e_net, BM_CREATE_NOP); + } + if ((edgenet_len > 1) && (v_other_dest != v_other)) { + e_net = edgenet[edgenet_len - 1]; + edgenet[edgenet_len - 1] = BM_edge_create( + bm, v_other_dest, BM_edge_other_vert(e_net, v_other), e_net, BM_CREATE_NOP); + } + break; + } + + BMEdge *e_test = e_net, *e_next = NULL; + while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != (e_net)) { + if (!BM_edge_is_wire(e_test)) { + if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) { + continue; + } + if (!BM_elem_flag_test(e_test->v1, BM_ELEM_TAG) && + !BM_elem_flag_test(e_test->v2, BM_ELEM_TAG)) { + continue; + } + } + else if (!BM_edge_is_wire(e_net)) { + continue; + } + e_next = e_test; + break; + } + + if (e_next == NULL) { + break; + } + + e_net = e_next; + v_other = BM_edge_other_vert(e_net, v_other); + if (v_other == va) { + /* Endless loop. */ + break; + } + v_cut_other = BM_elem_index_get(v_other); + } + + if (best_face) { + BMFace **face_arr = NULL; + int face_arr_len = 0; + BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, &face_arr, &face_arr_len); + if (face_arr) { + /* Update the new faces normal. + * Normal is necessary to obtain the best face for edgenet */ + while (face_arr_len--) { + BM_face_normal_update(face_arr[face_arr_len]); + } + MEM_freeN(face_arr); + } + } + } + + if (edgenet) { + MEM_freeN(edgenet); + } + } ok = true; } } diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h index a22a1ca1e1d..7e2252250d6 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.h +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.h @@ -21,9 +21,7 @@ #ifndef __BMESH_INTERSECT_EDGES_H__ #define __BMESH_INTERSECT_EDGES_H__ -void BM_vert_weld_linked_wire_edges_into_linked_faces( - BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len); - -bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap); +bool BM_mesh_intersect_edges( + BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap); #endif /* __BMESH_INTERSECT_EDGES_H__ */ diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h index 4651290ea0f..7b523ac53ca 100644 --- a/source/blender/collada/BCAnimationCurve.h +++ b/source/blender/collada/BCAnimationCurve.h @@ -23,8 +23,9 @@ #include "collada_utils.h" #include "BCSampleData.h" -extern "C" { #include "MEM_guardedalloc.h" + +extern "C" { #include "BKE_fcurve.h" #include "BKE_armature.h" #include "BKE_material.h" diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 0ebcd6d0919..24a960ab287 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -56,6 +56,8 @@ #include "COLLADASWInstanceNode.h" #include "COLLADASWBaseInputElement.h" +#include "MEM_guardedalloc.h" + extern "C" { #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -99,8 +101,6 @@ extern char build_commit_time[]; extern char build_hash[]; #endif -#include "MEM_guardedalloc.h" - #include "RNA_access.h" } diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 30e41a8d720..f2c52b125a4 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -43,6 +43,8 @@ #include "COLLADASaxFWLLoader.h" #include "COLLADASaxFWLIExtraDataCallbackHandler.h" +#include "MEM_guardedalloc.h" + extern "C" { #include "BLI_listbase.h" #include "BLI_math.h" @@ -68,8 +70,6 @@ extern "C" { #include "RNA_access.h" -#include "MEM_guardedalloc.h" - #include "WM_api.h" #include "WM_types.h" } diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 80f84738f6e..2d69fae035f 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -112,26 +112,22 @@ void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *m void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma) { - // get diffuse color COLLADASW::ColorOrTexture cot = bc_get_base_color(ma); ep.setDiffuse(cot, false, "diffuse"); } void EffectsExporter::set_ambient(COLLADASW::EffectProfile &ep, Material *ma) { - // get diffuse color COLLADASW::ColorOrTexture cot = bc_get_ambient(ma); ep.setAmbient(cot, false, "ambient"); } void EffectsExporter::set_specular(COLLADASW::EffectProfile &ep, Material *ma) { - // get diffuse color COLLADASW::ColorOrTexture cot = bc_get_specular(ma); ep.setSpecular(cot, false, "specular"); } void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma) { - // get diffuse color COLLADASW::ColorOrTexture cot = bc_get_reflective(ma); ep.setReflective(cot, false, "reflective"); } diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp index 3b2c68ef95e..06f54884668 100644 --- a/source/blender/collada/Materials.cpp +++ b/source/blender/collada/Materials.cpp @@ -202,6 +202,7 @@ void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode, bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha"); ((bNodeSocketValueFloat *)socket->default_value)->value = alpha; + material->a = alpha; } else if (cot.isTexture()) { int locy = -300 * (node_map.size() - 2); diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index e02a7a014f1..8ed30a0dc81 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -31,6 +31,8 @@ #include "COLLADAFWMeshVertexData.h" #include "COLLADAFWPolygons.h" +#include "MEM_guardedalloc.h" + extern "C" { #include "BKE_customdata.h" #include "BKE_displist.h" @@ -44,8 +46,6 @@ extern "C" { #include "BLI_math.h" #include "BLI_string.h" #include "BLI_edgehash.h" - -#include "MEM_guardedalloc.h" } #include "ArmatureImporter.h" diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index b688840cb09..63dad6b7ac0 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -27,6 +27,9 @@ #include <set> #include <string> + +#include "MEM_guardedalloc.h" + extern "C" { #include "DNA_modifier_types.h" #include "DNA_customdata_types.h" @@ -62,8 +65,6 @@ extern "C" { #include "ED_node.h" #include "ED_object.h" -#include "MEM_guardedalloc.h" - #include "WM_api.h" /* XXX hrm, see if we can do without this */ #include "WM_types.h" @@ -1321,10 +1322,11 @@ void bc_add_default_shader(bContext *C, Material *ma) COLLADASW::ColorOrTexture bc_get_base_color(Material *ma) { - Color default_color = {0.8, 0.8, 0.8, 1.0}; + /* for alpha see bc_get_alpha() */ + Color default_color = {ma->r, ma->g, ma->b, 1.0}; bNode *shader = bc_get_master_shader(ma); if (ma->use_nodes && shader) { - return bc_get_cot_from_shader(shader, "Base Color", default_color); + return bc_get_cot_from_shader(shader, "Base Color", default_color, false); } else { return bc_get_cot(default_color); @@ -1414,16 +1416,17 @@ double bc_get_float_from_shader(bNode *shader, double &val, std::string nodeid) COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader, std::string nodeid, - Color &default_color) + Color &default_color, + bool with_alpha) { bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, nodeid.c_str()); if (socket) { bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value; float *col = dcol->value; - return bc_get_cot(col); + return bc_get_cot(col, with_alpha); } else { - return bc_get_cot(default_color); /* default black */ + return bc_get_cot(default_color, with_alpha); } } @@ -1447,9 +1450,9 @@ COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a) return cot; } -COLLADASW::ColorOrTexture bc_get_cot(Color col) +COLLADASW::ColorOrTexture bc_get_cot(Color col, bool with_alpha) { - COLLADASW::Color color(col[0], col[1], col[2], col[3]); + COLLADASW::Color color(col[0], col[1], col[2], (with_alpha) ? col[3] : 1.0); COLLADASW::ColorOrTexture cot(color); return cot; } diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index c0425e59d1a..b313fcd6e66 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -397,9 +397,10 @@ double bc_get_shininess(Material *ma); double bc_get_float_from_shader(bNode *shader, double &ior, std::string nodeid); COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader, std::string nodeid, - Color &default_color); + Color &default_color, + bool with_alpha = true); COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a); -COLLADASW::ColorOrTexture bc_get_cot(Color col); +COLLADASW::ColorOrTexture bc_get_cot(Color col, bool with_alpha = true); #endif diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp index 5bd466658c0..ff9fc7dbcbc 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp @@ -17,6 +17,7 @@ */ #include "COM_CompositorOperation.h" +#include "MEM_guardedalloc.h" #include "BLI_listbase.h" #include "BKE_global.h" #include "BKE_image.h" @@ -26,7 +27,6 @@ extern "C" { #include "RE_pipeline.h" #include "RE_shader_ext.h" #include "RE_render_ext.h" -#include "MEM_guardedalloc.h" #include "render_types.h" } #include "PIL_time.h" diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h index e03173dca8d..6237d336c74 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.h +++ b/source/blender/compositor/operations/COM_ImageOperation.h @@ -20,13 +20,13 @@ #define __COM_IMAGEOPERATION_H__ #include "COM_NodeOperation.h" +#include "MEM_guardedalloc.h" #include "BLI_listbase.h" #include "BKE_image.h" extern "C" { #include "RE_pipeline.h" #include "RE_shader_ext.h" #include "RE_render_ext.h" -#include "MEM_guardedalloc.h" } /** diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index c06994d7cdb..334eab6ef95 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -30,9 +30,9 @@ #include "BKE_scene.h" #include "DNA_color_types.h" +#include "MEM_guardedalloc.h" extern "C" { -#include "MEM_guardedalloc.h" #include "IMB_imbuf.h" #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cpp index cd2bb3b2928..b91c3324f87 100644 --- a/source/blender/compositor/operations/COM_PreviewOperation.cpp +++ b/source/blender/compositor/operations/COM_PreviewOperation.cpp @@ -26,8 +26,8 @@ #include "BLI_math_color.h" #include "COM_defines.h" #include "BLI_math.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_colormanagement.h" diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index 5aa7e879760..ca7c18a0586 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -20,12 +20,12 @@ #define __COM_RENDERLAYERSPROG_H__ #include "COM_NodeOperation.h" +#include "MEM_guardedalloc.h" #include "DNA_scene_types.h" #include "BLI_listbase.h" #include "BKE_image.h" extern "C" { #include "RE_pipeline.h" -#include "MEM_guardedalloc.h" } /** diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cpp index 24978acc8f3..437b20d14d4 100644 --- a/source/blender/compositor/operations/COM_SplitOperation.cpp +++ b/source/blender/compositor/operations/COM_SplitOperation.cpp @@ -22,9 +22,9 @@ #include "BLI_utildefines.h" #include "BLI_math_color.h" #include "BLI_math_vector.h" +#include "MEM_guardedalloc.h" extern "C" { -#include "MEM_guardedalloc.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" } diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h index 934b6f8683f..6b44c11f423 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.h +++ b/source/blender/compositor/operations/COM_TextureOperation.h @@ -22,11 +22,11 @@ #include "COM_NodeOperation.h" #include "DNA_texture_types.h" #include "BLI_listbase.h" +#include "MEM_guardedalloc.h" extern "C" { #include "RE_pipeline.h" #include "RE_shader_ext.h" #include "RE_render_ext.h" -#include "MEM_guardedalloc.h" } /** diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp index b6caf52a9f7..50b508dafb1 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cpp +++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp @@ -26,9 +26,9 @@ #include "BLI_utildefines.h" #include "BLI_math_color.h" #include "BLI_math_vector.h" +#include "MEM_guardedalloc.h" extern "C" { -#include "MEM_guardedalloc.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_colormanagement.h" diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 4abeec19645..fad8bc22e08 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -59,6 +59,7 @@ set(SRC intern/eval/deg_eval_copy_on_write.cc intern/eval/deg_eval_flush.cc intern/eval/deg_eval_runtime_backup.cc + intern/eval/deg_eval_runtime_backup_animation.cc intern/eval/deg_eval_runtime_backup_modifier.cc intern/eval/deg_eval_runtime_backup_movieclip.cc intern/eval/deg_eval_runtime_backup_object.cc @@ -82,6 +83,7 @@ set(SRC intern/depsgraph_query.cc intern/depsgraph_query_foreach.cc intern/depsgraph_query_iter.cc + intern/depsgraph_relation.cc intern/depsgraph_registry.cc intern/depsgraph_tag.cc intern/depsgraph_type.cc @@ -104,10 +106,12 @@ set(SRC intern/builder/deg_builder_rna.h intern/builder/deg_builder_transitive.h intern/debug/deg_debug.h + intern/debug/deg_time_average.h intern/eval/deg_eval.h intern/eval/deg_eval_copy_on_write.h intern/eval/deg_eval_flush.h intern/eval/deg_eval_runtime_backup.h + intern/eval/deg_eval_runtime_backup_animation.h intern/eval/deg_eval_runtime_backup_modifier.h intern/eval/deg_eval_runtime_backup_movieclip.h intern/eval/deg_eval_runtime_backup_object.h @@ -127,6 +131,7 @@ set(SRC intern/depsgraph.h intern/depsgraph_physics.h intern/depsgraph_registry.h + intern/depsgraph_relation.h intern/depsgraph_tag.h intern/depsgraph_type.h intern/depsgraph_update.h diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index fb7104e7556..7eca04112e7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -42,6 +42,7 @@ extern "C" { } #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" #include "intern/depsgraph_tag.h" #include "intern/depsgraph_type.h" #include "intern/builder/deg_builder_cache.h" @@ -58,14 +59,14 @@ namespace DEG { bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig) { IDNode *id_node = graph->find_id_node(id_orig); - return id_node != NULL; + return id_node != nullptr; } bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base) { Object *object_orig = base->base_orig->object; IDNode *id_node = graph->find_id_node(&object_orig->id); - if (id_node == NULL) { + if (id_node == nullptr) { return false; } return id_node->has_base; @@ -113,7 +114,7 @@ bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel *pchan) { BLI_assert(object->type == OB_ARMATURE); - if (pchan == NULL || pchan->bone == NULL) { + if (pchan == nullptr || pchan->bone == nullptr) { return false; } /* We don't really care whether segments are higher than 1 due to static user input (as in, @@ -133,7 +134,7 @@ bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan) { /* Proxies don't have BONE_SEGMENTS */ - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { return false; } return check_pchan_has_bbone(object, pchan); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc index 3cfb4f95e5e..fe1886c67e8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc @@ -37,7 +37,7 @@ namespace DEG { /* Animated property storage. */ -AnimatedPropertyID::AnimatedPropertyID() : data(NULL), property_rna(NULL) +AnimatedPropertyID::AnimatedPropertyID() : data(nullptr), property_rna(nullptr) { } @@ -89,13 +89,13 @@ struct AnimatedPropertyCallbackData { void animated_property_cb(ID * /*id*/, FCurve *fcurve, void *data_v) { - if (fcurve->rna_path == NULL || fcurve->rna_path[0] == '\0') { + if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') { return; } AnimatedPropertyCallbackData *data = static_cast<AnimatedPropertyCallbackData *>(data_v); /* Resolve property. */ PointerRNA pointer_rna; - PropertyRNA *property_rna = NULL; + PropertyRNA *property_rna = nullptr; if (!RNA_path_resolve_property( &data->pointer_rna, fcurve->rna_path, &pointer_rna, &property_rna)) { return; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index bea59eceea2..e0d162a49c5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -35,6 +35,7 @@ #include "intern/node/deg_node_operation.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" namespace DEG { @@ -99,8 +100,8 @@ void schedule_node_to_stack(CyclesSolverState *state, OperationNode *node) { StackEntry entry; entry.node = node; - entry.from = NULL; - entry.via_relation = NULL; + entry.from = nullptr; + entry.via_relation = nullptr; BLI_stack_push(state->traversal_stack, &entry); set_node_visited_state(node, NODE_IN_STACK); } @@ -186,7 +187,7 @@ void solve_cycles(CyclesSolverState *state) node->full_identifier() + " via '" + rel->name + "'\n"; StackEntry *current = entry; while (current->node != to) { - BLI_assert(current != NULL); + BLI_assert(current != nullptr); cycle_str += " " + current->from->node->full_identifier() + " via '" + current->via_relation->name + "'\n"; current = current->from; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index b260df6fa06..6382772c8db 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -122,7 +122,7 @@ namespace { void free_copy_on_write_datablock(void *id_info_v) { DepsgraphNodeBuilder::IDInfo *id_info = (DepsgraphNodeBuilder::IDInfo *)id_info_v; - if (id_info->id_cow != NULL) { + if (id_info->id_cow != nullptr) { deg_free_copy_on_write_datablock(id_info->id_cow); MEM_freeN(id_info->id_cow); } @@ -140,37 +140,37 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache) : DepsgraphBuilder(bmain, graph, cache), - scene_(NULL), - view_layer_(NULL), + scene_(nullptr), + view_layer_(nullptr), view_layer_index_(-1), - collection_(NULL), + collection_(nullptr), is_parent_collection_visible_(true), - id_info_hash_(NULL) + id_info_hash_(nullptr) { } DepsgraphNodeBuilder::~DepsgraphNodeBuilder() { - if (id_info_hash_ != NULL) { - BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock); + if (id_info_hash_ != nullptr) { + BLI_ghash_free(id_info_hash_, nullptr, free_copy_on_write_datablock); } } IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) { - IDNode *id_node = NULL; - ID *id_cow = NULL; + IDNode *id_node = nullptr; + ID *id_cow = nullptr; IDComponentsMask previously_visible_components_mask = 0; uint32_t previous_eval_flags = 0; DEGCustomDataMeshMasks previous_customdata_masks; IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id); - if (id_info != NULL) { + if (id_info != nullptr) { id_cow = id_info->id_cow; previously_visible_components_mask = id_info->previously_visible_components_mask; previous_eval_flags = id_info->previous_eval_flags; previous_customdata_masks = id_info->previous_customdata_masks; /* Tag ID info to not free the CoW ID pointer. */ - id_info->id_cow = NULL; + id_info->id_cow = nullptr; } id_node = graph_->add_id_node(id, id_cow); id_node->previously_visible_components_mask = previously_visible_components_mask; @@ -218,7 +218,7 @@ OperationNode *DepsgraphNodeBuilder::add_operation_node(ComponentNode *comp_node int name_tag) { OperationNode *op_node = comp_node->find_operation(opcode, name, name_tag); - if (op_node == NULL) { + if (op_node == nullptr) { op_node = comp_node->add_operation(op, opcode, name, name_tag); graph_->operations.push_back(op_node); } @@ -263,7 +263,7 @@ OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id, int name_tag) { OperationNode *operation = find_operation_node(id, comp_type, opcode, name, name_tag); - if (operation != NULL) { + if (operation != nullptr) { return operation; } return add_operation_node(id, comp_type, opcode, op, name, name_tag); @@ -276,7 +276,7 @@ bool DepsgraphNodeBuilder::has_operation_node(ID *id, const char *name, int name_tag) { - return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != NULL; + return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != nullptr; } OperationNode *DepsgraphNodeBuilder::find_operation_node(ID *id, @@ -324,13 +324,13 @@ void DepsgraphNodeBuilder::begin_build() id_info->id_cow = id_node->id_cow; } else { - id_info->id_cow = NULL; + id_info->id_cow = nullptr; } id_info->previously_visible_components_mask = id_node->visible_components_mask; id_info->previous_eval_flags = id_node->eval_flags; id_info->previous_customdata_masks = id_node->customdata_masks; BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info); - id_node->id_cow = NULL; + id_node->id_cow = nullptr; } GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) { @@ -350,23 +350,23 @@ void DepsgraphNodeBuilder::begin_build() /* Make sure graph has no nodes left from previous state. */ graph_->clear_all_nodes(); graph_->operations.clear(); - BLI_gset_clear(graph_->entry_tags, NULL); + BLI_gset_clear(graph_->entry_tags, nullptr); } void DepsgraphNodeBuilder::end_build() { for (const SavedEntryTag &entry_tag : saved_entry_tags_) { IDNode *id_node = find_id_node(entry_tag.id_orig); - if (id_node == NULL) { + if (id_node == nullptr) { continue; } ComponentNode *comp_node = id_node->find_component(entry_tag.component_type); - if (comp_node == NULL) { + if (comp_node == nullptr) { continue; } OperationNode *op_node = comp_node->find_operation( entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag); - if (op_node == NULL) { + if (op_node == nullptr) { continue; } /* Since the tag is coming from a saved copy of entry tags, this means @@ -377,7 +377,7 @@ void DepsgraphNodeBuilder::end_build() void DepsgraphNodeBuilder::build_id(ID *id) { - if (id == NULL) { + if (id == nullptr) { return; } switch (GS(id->name)) { @@ -391,7 +391,7 @@ void DepsgraphNodeBuilder::build_id(ID *id) build_camera((Camera *)id); break; case ID_GR: - build_collection(NULL, (Collection *)id); + build_collection(nullptr, (Collection *)id); break; case ID_OB: /* TODO(sergey): Get visibility from a "parent" somehow. @@ -487,7 +487,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti * objects are poked with the new visibility flag, since they * might become visible too. */ } - else if (from_layer_collection == NULL && !id_node->is_collection_fully_expanded) { + else if (from_layer_collection == nullptr && !id_node->is_collection_fully_expanded) { /* Initially collection was built from layer now, and was requested * to not recurs into object. But nw it's asked to recurs into all * objects. */ @@ -501,7 +501,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti id_node = add_id_node(&collection->id); id_node->is_directly_visible = is_collection_visible; } - if (from_layer_collection != NULL) { + if (from_layer_collection != nullptr) { /* If we came from layer collection we don't go deeper, view layer * builder takes care of going deeper. */ return; @@ -518,7 +518,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti } /* Build child collections. */ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, child->collection); + build_collection(nullptr, child->collection); } /* Restore state. */ collection_ = current_state_collection; @@ -531,7 +531,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, eDepsNode_LinkedState_Type linked_state, bool is_visible) { - if (object->proxy != NULL) { + if (object->proxy != nullptr) { object->proxy->proxy_from = object; } const bool has_object = built_map_.checkIsBuiltAndTag(object); @@ -554,10 +554,10 @@ void DepsgraphNodeBuilder::build_object(int base_index, IDNode *id_node = add_id_node(&object->id); Object *object_cow = get_cow_datablock(object); id_node->linked_state = linked_state; - /* NOTE: Scene is NULL when building dependency graph for render pipeline. - * Probably need to assign that to something non-NULL, but then the logic here will still be + /* NOTE: Scene is nullptr when building dependency graph for render pipeline. + * Probably need to assign that to something non-nullptr, but then the logic here will still be * somewhat weird. */ - if (scene_ != NULL && object == scene_->camera) { + if (scene_ != nullptr && object == scene_->camera) { id_node->is_directly_visible = true; } else { @@ -569,32 +569,32 @@ void DepsgraphNodeBuilder::build_object(int base_index, /* Transform. */ build_object_transform(object); /* Parent. */ - if (object->parent != NULL) { + if (object->parent != nullptr) { build_object(-1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible); } /* Modifiers. */ - if (object->modifiers.first != NULL) { + if (object->modifiers.first != nullptr) { BuilderWalkUserData data; data.builder = this; data.is_parent_visible = is_visible; modifiers_foreachIDLink(object, modifier_walk, &data); } /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { + if (object->greasepencil_modifiers.first != nullptr) { BuilderWalkUserData data; data.builder = this; data.is_parent_visible = is_visible; BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); } /* Shader FX. */ - if (object->shader_fx.first != NULL) { + if (object->shader_fx.first != nullptr) { BuilderWalkUserData data; data.builder = this; data.is_parent_visible = is_visible; BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); } /* Constraints. */ - if (object->constraints.first != NULL) { + if (object->constraints.first != nullptr) { BuilderWalkUserData data; data.builder = this; data.is_parent_visible = is_visible; @@ -612,17 +612,17 @@ void DepsgraphNodeBuilder::build_object(int base_index, * pose for proxy. */ build_animdata(&object->id); /* Particle systems. */ - if (object->particlesystem.first != NULL) { + if (object->particlesystem.first != nullptr) { build_particle_systems(object, is_visible); } /* Proxy object to copy from. */ build_object_proxy_from(object, is_visible); build_object_proxy_group(object, is_visible); /* Object dupligroup. */ - if (object->instance_collection != NULL) { + if (object->instance_collection != nullptr) { const bool is_current_parent_collection_visible = is_parent_collection_visible_; is_parent_collection_visible_ = is_visible; - build_collection(NULL, object->instance_collection); + build_collection(nullptr, object->instance_collection); is_parent_collection_visible_ = is_current_parent_collection_visible; add_operation_node(&object->id, NodeType::DUPLI, OperationCode::DUPLI); } @@ -658,7 +658,7 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index, void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visible) { - if (object->proxy_from == NULL) { + if (object->proxy_from == nullptr) { return; } build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); @@ -666,7 +666,7 @@ void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visib void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visible) { - if (object->proxy_group == NULL) { + if (object->proxy_group == nullptr) { return; } build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); @@ -674,7 +674,7 @@ void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visi void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible) { - if (object->data == NULL) { + if (object->data == nullptr) { return; } /* type-specific data. */ @@ -689,7 +689,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi build_object_data_geometry(object, is_object_visible); break; case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { build_proxy_rig(object); } else { @@ -718,7 +718,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi } /* Materials. */ Material ***materials_ptr = give_matarar(object); - if (materials_ptr != NULL) { + if (materials_ptr != nullptr) { short *num_materials_ptr = give_totcolp(object); build_materials(*materials_ptr, *num_materials_ptr); } @@ -763,14 +763,14 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object) OperationCode::TRANSFORM_LOCAL, function_bind(BKE_object_eval_local_transform, _1, ob_cow)); /* Object parent. */ - if (object->parent != NULL) { + if (object->parent != nullptr) { add_operation_node(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_PARENT, function_bind(BKE_object_eval_parent, _1, ob_cow)); } /* Object constraints. */ - if (object->constraints.first != NULL) { + if (object->constraints.first != nullptr) { build_object_constraints(object); } /* Rest of transformation update. */ @@ -840,16 +840,16 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) build_animation_images(id); /* Regular animation. */ AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { + if (adt == nullptr) { return; } - if (adt->action != NULL) { + if (adt->action != nullptr) { build_action(adt->action); } /* Make sure ID node exists. */ (void)add_id_node(id); ID *id_cow = get_cow_id(id); - if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks)) { + if (adt->action != nullptr || !BLI_listbase_is_empty(&adt->nla_tracks)) { OperationNode *operation_node; /* Explicit entry operation. */ operation_node = add_operation_node(id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); @@ -878,10 +878,10 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) { LISTBASE_FOREACH (NlaStrip *, strip, strips) { - if (strip->act != NULL) { + if (strip->act != nullptr) { build_action(strip->act); } - else if (strip->strips.first != NULL) { + else if (strip->strips.first != nullptr) { build_animdata_nlastrip_targets(&strip->strips); } } @@ -938,13 +938,13 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve) build_driver_id_property(id, fcurve->rna_path); LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) { DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - if (dtar->id == NULL) { + if (dtar->id == nullptr) { continue; } build_id(dtar->id); build_driver_id_property(dtar->id, dtar->rna_path); /* Corresponds to dtar_id_ensure_proxy_from(). */ - if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) { + if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != nullptr)) { Object *proxy_from = ((Object *)dtar->id)->proxy_from; build_id(&proxy_from->id); build_driver_id_property(&proxy_from->id, dtar->rna_path); @@ -956,7 +956,7 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve) void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path) { - if (id == NULL || rna_path == NULL) { + if (id == nullptr || rna_path == nullptr) { return; } PointerRNA id_ptr, ptr; @@ -966,7 +966,7 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) { return; } - if (prop == NULL) { + if (prop == nullptr) { return; } if (!RNA_property_is_idprop(prop)) { @@ -974,7 +974,7 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path } const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); ensure_operation_node( - id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, NULL, prop_identifier); + id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, nullptr, prop_identifier); } void DepsgraphNodeBuilder::build_parameters(ID *id) @@ -1053,8 +1053,8 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) sim_node->set_as_exit(); sim_node->owner->entry_operation = sim_node; /* Objects - simulation participants. */ - if (rbw->group != NULL) { - build_collection(NULL, rbw->group); + if (rbw->group != nullptr) { + build_collection(nullptr, rbw->group); FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { if (object->type != OB_MESH) { continue; @@ -1072,11 +1072,11 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* Constraints. */ - if (rbw->constraints != NULL) { + if (rbw->constraints != nullptr) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { - /* When either ob1 or ob2 is NULL, the constraint doesn't work. */ + if (rbc == nullptr || rbc->ob1 == nullptr || rbc->ob2 == nullptr) { + /* When either ob1 or ob2 is nullptr, the constraint doesn't work. */ continue; } /* Make sure indirectly linked objects are fully built. */ @@ -1120,11 +1120,11 @@ void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object * NOTE: The call itself ensures settings are only build once. */ build_particle_settings(part); /* Particle system evaluation. */ - add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, NULL, psys->name); + add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, nullptr, psys->name); /* Keyed particle targets. */ if (part->phystype == PART_PHYS_KEYED) { LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { - if (particle_target->ob == NULL || particle_target->ob == object) { + if (particle_target->ob == nullptr || particle_target->ob == object) { continue; } build_object(-1, particle_target->ob, DEG_ID_LINKED_INDIRECTLY, is_object_visible); @@ -1133,13 +1133,13 @@ void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object /* Visualization of particle system. */ switch (part->ren_as) { case PART_DRAW_OB: - if (part->instance_object != NULL) { + if (part->instance_object != nullptr) { build_object(-1, part->instance_object, DEG_ID_LINKED_INDIRECTLY, is_object_visible); } break; case PART_DRAW_GR: - if (part->instance_collection != NULL) { - build_collection(NULL, part->instance_collection); + if (part->instance_collection != nullptr) { + build_collection(nullptr, part->instance_collection); } break; } @@ -1174,7 +1174,7 @@ void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_se /* Texture slots. */ for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) { MTex *mtex = particle_settings->mtex[mtex_index]; - if (mtex == NULL || mtex->tex == NULL) { + if (mtex == nullptr || mtex->tex == nullptr) { continue; } build_texture(mtex->tex); @@ -1196,7 +1196,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) * drivers evaluation. */ LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { add_operation_node( - &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, key_block->name); + &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, key_block->name); } } @@ -1274,13 +1274,13 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool /* Make sure objects used for bevel.taper are in the graph. * NOTE: This objects might be not linked to the scene. */ Curve *cu = (Curve *)obdata; - if (cu->bevobj != NULL) { + if (cu->bevobj != nullptr) { build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); } - if (cu->taperobj != NULL) { + if (cu->taperobj != nullptr) { build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); } - if (cu->textoncurve != NULL) { + if (cu->textoncurve != nullptr) { build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible); } break; @@ -1338,7 +1338,7 @@ void DepsgraphNodeBuilder::build_camera(Camera *camera) } build_animdata(&camera->id); build_parameters(&camera->id); - if (camera->dof.focus_object != NULL) { + if (camera->dof.focus_object != nullptr) { build_object(-1, camera->dof.focus_object, DEG_ID_LINKED_INDIRECTLY, false); } } @@ -1356,7 +1356,7 @@ void DepsgraphNodeBuilder::build_light(Light *lamp) void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) { - if (ntree == NULL) { + if (ntree == nullptr) { return; } if (built_map_.checkIsBuiltAndTag(ntree)) { @@ -1380,7 +1380,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) /* nodetree's nodes... */ LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; - if (id == NULL) { + if (id == nullptr) { continue; } ID_Type id_type = GS(id->name); @@ -1404,7 +1404,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) * * On the one hand it's annoying to always pull it in, but on another hand it's also annoying * to have hardcoded node-type exception here. */ - if (node_scene->camera != NULL) { + if (node_scene->camera != nullptr) { /* TODO(sergey): Use visibility of owner of the node tree. */ build_object(-1, node_scene->camera, DEG_ID_LINKED_INDIRECTLY, true); } @@ -1454,7 +1454,7 @@ void DepsgraphNodeBuilder::build_material(Material *material) void DepsgraphNodeBuilder::build_materials(Material **materials, int num_materials) { for (int i = 0; i < num_materials; i++) { - if (materials[i] == NULL) { + if (materials[i] == nullptr) { continue; } build_material(materials[i]); @@ -1474,7 +1474,7 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture) build_nodetree(texture->nodetree); /* Special cases for different IDs which texture uses. */ if (texture->type == TEX_IMAGE) { - if (texture->ima != NULL) { + if (texture->ima != nullptr) { build_image(texture->ima); } } @@ -1552,7 +1552,7 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask) for (int i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; MaskParent *parent = &point->parent; - if (parent == NULL || parent->id == NULL) { + if (parent == nullptr || parent->id == nullptr) { continue; } build_id(parent->id); @@ -1615,7 +1615,7 @@ void DepsgraphNodeBuilder::build_speaker(Speaker *speaker) add_operation_node(&speaker->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL); build_animdata(&speaker->id); build_parameters(&speaker->id); - if (speaker->sound != NULL) { + if (speaker->sound != nullptr) { build_sound(speaker->sound); } } @@ -1637,7 +1637,7 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound) void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene) { - if (scene->ed == NULL) { + if (scene->ed == nullptr) { return; } build_scene_audio(scene); @@ -1649,13 +1649,13 @@ void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene) /* Make sure data for sequences is in the graph. */ Sequence *seq; SEQ_BEGIN (scene->ed, seq) { - if (seq->sound != NULL) { + if (seq->sound != nullptr) { build_sound(seq->sound); } - if (seq->scene != NULL) { + if (seq->scene != nullptr) { build_scene_parameters(seq->scene); } - if (seq->type == SEQ_TYPE_SCENE && seq->scene != NULL) { + if (seq->type == SEQ_TYPE_SCENE && seq->scene != nullptr) { if (seq->flag & SEQ_SCENE_STRIPS) { build_scene_sequencer(seq->scene); } @@ -1696,7 +1696,7 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data, { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; ID *id = *idpoin; - if (id == NULL) { + if (id == nullptr) { return; } switch (GS(id->name)) { @@ -1719,7 +1719,7 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; ID *id = *idpoin; - if (id == NULL) { + if (id == nullptr) { return; } switch (GS(id->name)) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 7cb74ea8bc5..54a4768d12a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -106,27 +106,27 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { OperationNode *add_operation_node(ComponentNode *comp_node, OperationCode opcode, - const DepsEvalOperationCb &op = NULL, + const DepsEvalOperationCb &op = nullptr, const char *name = "", int name_tag = -1); OperationNode *add_operation_node(ID *id, NodeType comp_type, const char *comp_name, OperationCode opcode, - const DepsEvalOperationCb &op = NULL, + const DepsEvalOperationCb &op = nullptr, const char *name = "", int name_tag = -1); OperationNode *add_operation_node(ID *id, NodeType comp_type, OperationCode opcode, - const DepsEvalOperationCb &op = NULL, + const DepsEvalOperationCb &op = nullptr, const char *name = "", int name_tag = -1); OperationNode *ensure_operation_node(ID *id, NodeType comp_type, OperationCode opcode, - const DepsEvalOperationCb &op = NULL, + const DepsEvalOperationCb &op = nullptr, const char *name = "", int name_tag = -1); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 979e1a02e71..07010a5cbef 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -87,7 +87,7 @@ void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bC /* Find the chain's root. */ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - if (rootchan == NULL) { + if (rootchan == nullptr) { return; } @@ -154,12 +154,12 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) /* Armature. */ build_armature(armature); /* Rebuild pose if not up to date. */ - if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { - /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ - BKE_pose_rebuild(NULL, object, armature, true); + if (object->pose == nullptr || (object->pose->flag & POSE_RECALC)) { + /* By definition, no need to tag depsgraph as dirty from here, so we can pass nullptr bmain. */ + BKE_pose_rebuild(nullptr, object, armature, true); } /* Speed optimization for animation lookups. */ - if (object->pose != NULL) { + if (object->pose != nullptr) { BKE_pose_channels_hash_make(object->pose); if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { BKE_pose_update_constraint_flags(object->pose); @@ -243,12 +243,12 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) op_node->set_as_exit(); /* Custom properties. */ - if (pchan->prop != NULL) { + if (pchan->prop != nullptr) { add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name); + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name); } /* Build constraints. */ - if (pchan->constraints.first != NULL) { + if (pchan->constraints.first != nullptr) { build_pose_constraints(object, pchan, pchan_index, is_object_visible); } /** @@ -277,7 +277,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) } } /* Custom shape. */ - if (pchan->custom != NULL) { + if (pchan->custom != nullptr) { /* TODO(sergey): Use own visibility. */ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible); } @@ -291,7 +291,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) OperationNode *op_node; Object *object_cow = get_cow_datablock(object); /* Sanity check. */ - BLI_assert(object->pose != NULL); + BLI_assert(object->pose != nullptr); /* Armature. */ build_armature(armature); /* speed optimization for animation lookups */ @@ -322,9 +322,9 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) op_node->set_as_exit(); /* Custom properties. */ - if (pchan->prop != NULL) { + if (pchan->prop != nullptr) { add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name); + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name); } pchan_index++; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index 777512acf89..1edf9826208 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -46,7 +46,7 @@ void DepsgraphNodeBuilder::build_scene_render(Scene *scene, ViewLayer *view_laye build_scene_sequencer(scene); build_scene_speakers(scene, view_layer); } - if (scene->camera != NULL) { + if (scene->camera != nullptr) { build_object(-1, scene->camera, DEG_ID_LINKED_DIRECTLY, true); } } @@ -76,7 +76,7 @@ void DepsgraphNodeBuilder::build_scene_compositor(Scene *scene) if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_COMPOSITOR)) { return; } - if (scene->nodetree == NULL) { + if (scene->nodetree == nullptr) { return; } build_nodetree(scene->nodetree); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 82a65c3129b..d5e9c024812 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -77,10 +77,10 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) void DepsgraphNodeBuilder::build_freestyle_lineset(FreestyleLineSet *fls) { - if (fls->group != NULL) { - build_collection(NULL, fls->group); + if (fls->group != nullptr) { + build_collection(nullptr, fls->group); } - if (fls->linestyle != NULL) { + if (fls->linestyle != nullptr) { build_freestyle_linestyle(fls->linestyle); } } @@ -120,19 +120,19 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, } } build_layer_collections(&view_layer->layer_collections); - if (scene->camera != NULL) { + if (scene->camera != nullptr) { build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true); } /* Rigidbody. */ - if (scene->rigidbody_world != NULL) { + if (scene->rigidbody_world != nullptr) { build_rigidbody(scene); } /* Scene's animation and drivers. */ - if (scene->adt != NULL) { + if (scene->adt != nullptr) { build_animdata(&scene->id); } /* World. */ - if (scene->world != NULL) { + if (scene->world != nullptr) { build_world(scene->world); } /* Cache file. */ @@ -148,7 +148,7 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, build_movieclip(clip); } /* Material override. */ - if (view_layer->mat_override != NULL) { + if (view_layer->mat_override != nullptr) { build_material(view_layer->mat_override); } /* Freestyle linesets. */ @@ -170,7 +170,7 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, build_scene_compositor(scene); build_scene_parameters(scene); /* Build all set scenes. */ - if (scene->set != NULL) { + if (scene->set != nullptr) { ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 23402c68698..5483ff9c030 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -35,7 +35,7 @@ static void free_rootpchanmap_valueset(void *val) { /* Just need to free the set itself - the names stored are all references. */ GSet *values = (GSet *)val; - BLI_gset_free(values, NULL); + BLI_gset_free(values, nullptr); } RootPChanMap::RootPChanMap() @@ -47,7 +47,7 @@ RootPChanMap::RootPChanMap() RootPChanMap::~RootPChanMap() { /* Free the map, and all the value sets. */ - BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset); + BLI_ghash_free(map_, nullptr, free_rootpchanmap_valueset); } /* Debug contents of map */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d01e8d8eddd..5214fdbd246 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -114,6 +114,7 @@ extern "C" { #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" +#include "intern/depsgraph_relation.h" #include "intern/depsgraph_type.h" namespace DEG { @@ -126,7 +127,7 @@ namespace { bool driver_target_depends_on_time(const DriverTarget *target) { if (target->idtype == ID_SCE && - (target->rna_path != NULL && STREQ(target->rna_path, "frame_current"))) { + (target->rna_path != nullptr && STREQ(target->rna_path, "frame_current"))) { return true; } return false; @@ -194,16 +195,16 @@ bool object_particles_depends_on_time(Object *object) bool check_id_has_anim_component(ID *id) { AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { + if (adt == nullptr) { return false; } - return (adt->action != NULL) || (!BLI_listbase_is_empty(&adt->nla_tracks)); + return (adt->action != nullptr) || (!BLI_listbase_is_empty(&adt->nla_tracks)); } bool check_id_has_driver_component(ID *id) { AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { + if (adt == nullptr) { return false; } return !BLI_listbase_is_empty(&adt->drivers); @@ -240,7 +241,7 @@ bool object_have_geometry_component(const Object *object) DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache) - : DepsgraphBuilder(bmain, graph, cache), scene_(NULL), rna_node_query_(graph, this) + : DepsgraphBuilder(bmain, graph, cache), scene_(nullptr), rna_node_query_(graph, this) { } @@ -248,7 +249,7 @@ TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey &key) con { if (key.id) { /* XXX TODO */ - return NULL; + return nullptr; } else { return graph_->time_source; @@ -261,8 +262,8 @@ ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const if (!id_node) { fprintf(stderr, "find_node component: Could not find ID %s\n", - (key.id != NULL) ? key.id->name : "<null>"); - return NULL; + (key.id != nullptr) ? key.id->name : "<null>"); + return nullptr; } ComponentNode *node = id_node->find_component(key.type, key.name); @@ -272,7 +273,7 @@ ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const OperationNode *DepsgraphRelationBuilder::get_node(const OperationKey &key) const { OperationNode *op_node = find_node(key); - if (op_node == NULL) { + if (op_node == nullptr) { fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n", operationCodeAsString(key.opcode), @@ -290,18 +291,18 @@ OperationNode *DepsgraphRelationBuilder::find_node(const OperationKey &key) cons { IDNode *id_node = graph_->find_id_node(key.id); if (!id_node) { - return NULL; + return nullptr; } ComponentNode *comp_node = id_node->find_component(key.component_type, key.component_name); if (!comp_node) { - return NULL; + return nullptr; } return comp_node->find_operation(key.opcode, key.name, key.name_tag); } bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const { - return find_node(key) != NULL; + return find_node(key) != nullptr; } void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNodeHandle *handle, @@ -317,10 +318,11 @@ void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNode void DepsgraphRelationBuilder::add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks) { - if (customdata_masks != DEGCustomDataMeshMasks() && object != NULL && object->type == OB_MESH) { + if (customdata_masks != DEGCustomDataMeshMasks() && object != nullptr && + object->type == OB_MESH) { DEG::IDNode *id_node = graph_->find_id_node(&object->id); - if (id_node == NULL) { + if (id_node == nullptr) { BLI_assert(!"ID should always be valid"); } else { @@ -332,7 +334,7 @@ void DepsgraphRelationBuilder::add_customdata_mask(Object *object, void DepsgraphRelationBuilder::add_special_eval_flag(ID *id, uint32_t flag) { DEG::IDNode *id_node = graph_->find_id_node(id); - if (id_node == NULL) { + if (id_node == nullptr) { BLI_assert(!"ID should always be valid"); } else { @@ -358,7 +360,7 @@ Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc, (node_to) ? node_to->identifier().c_str() : "<None>", description); } - return NULL; + return nullptr; } Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from, @@ -379,7 +381,7 @@ Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_f (node_to) ? node_to->identifier().c_str() : "<None>", description); } - return NULL; + return nullptr; } void DepsgraphRelationBuilder::add_particle_collision_relations(const OperationKey &key, @@ -439,7 +441,7 @@ void DepsgraphRelationBuilder::add_particle_forcefield_relations(const Operation /* Absorption forces need collision relation. */ if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { - add_particle_collision_relations(key, object, NULL, "Force Absorption"); + add_particle_collision_relations(key, object, nullptr, "Force Absorption"); } } @@ -476,7 +478,7 @@ void DepsgraphRelationBuilder::begin_build() void DepsgraphRelationBuilder::build_id(ID *id) { - if (id == NULL) { + if (id == nullptr) { return; } switch (GS(id->name)) { @@ -490,10 +492,10 @@ void DepsgraphRelationBuilder::build_id(ID *id) build_camera((Camera *)id); break; case ID_GR: - build_collection(NULL, NULL, (Collection *)id); + build_collection(nullptr, nullptr, (Collection *)id); break; case ID_OB: - build_object(NULL, (Object *)id); + build_object(nullptr, (Object *)id); break; case ID_KE: build_shapekeys((Key *)id); @@ -560,7 +562,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll Object *object, Collection *collection) { - if (from_layer_collection != NULL) { + if (from_layer_collection != nullptr) { /* If we came from layer collection we don't go deeper, view layer * builder takes care of going deeper. * @@ -570,18 +572,19 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll return; } const bool group_done = built_map_.checkIsBuiltAndTag(collection); - OperationKey object_transform_final_key( - object != NULL ? &object->id : NULL, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); - ComponentKey duplicator_key(object != NULL ? &object->id : NULL, NodeType::DUPLI); + OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_FINAL); + ComponentKey duplicator_key(object != nullptr ? &object->id : nullptr, NodeType::DUPLI); if (!group_done) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - build_object(NULL, cob->ob); + build_object(nullptr, cob->ob); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, NULL, child->collection); + build_collection(nullptr, nullptr, child->collection); } } - if (object != NULL) { + if (object != nullptr) { FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, ob, graph_->mode) { ComponentKey dupli_transform_key(&ob->id, NodeType::TRANSFORM); add_relation(dupli_transform_key, object_transform_final_key, "Dupligroup"); @@ -601,7 +604,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll void DepsgraphRelationBuilder::build_object(Base *base, Object *object) { if (built_map_.checkIsBuiltAndTag(object)) { - if (base != NULL) { + if (base != nullptr) { build_object_flags(base, object); } return; @@ -623,34 +626,34 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) /* Various flags, flushing from bases/collections. */ build_object_flags(base, object); /* Parenting. */ - if (object->parent != NULL) { + if (object->parent != nullptr) { /* Make sure parent object's relations are built. */ - build_object(NULL, object->parent); + build_object(nullptr, object->parent); /* Parent relationship. */ build_object_parent(object); /* Local -> parent. */ add_relation(local_transform_key, parent_transform_key, "ObLocal -> ObParent"); } /* Modifiers. */ - if (object->modifiers.first != NULL) { + if (object->modifiers.first != nullptr) { BuilderWalkUserData data; data.builder = this; modifiers_foreachIDLink(object, modifier_walk, &data); } /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { + if (object->greasepencil_modifiers.first != nullptr) { BuilderWalkUserData data; data.builder = this; BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); } /* Shader FX. */ - if (object->shader_fx.first != NULL) { + if (object->shader_fx.first != nullptr) { BuilderWalkUserData data; data.builder = this; BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); } /* Constraints. */ - if (object->constraints.first != NULL) { + if (object->constraints.first != nullptr) { BuilderWalkUserData data; data.builder = this; BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); @@ -658,11 +661,11 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) /* Object constraints. */ OperationKey object_transform_simulation_init_key( &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); - if (object->constraints.first != NULL) { + if (object->constraints.first != nullptr) { OperationKey constraint_key( &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_CONSTRAINTS); /* Constraint relations. */ - build_constraints(&object->id, NodeType::TRANSFORM, "", &object->constraints, NULL); + build_constraints(&object->id, NodeType::TRANSFORM, "", &object->constraints, nullptr); /* operation order */ add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack"); add_relation(constraint_key, final_transform_key, "ObConstraints -> Done"); @@ -686,15 +689,15 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) /* Object data. */ build_object_data(object); /* Particle systems. */ - if (object->particlesystem.first != NULL) { + if (object->particlesystem.first != nullptr) { build_particle_systems(object); } /* Proxy object to copy from. */ build_object_proxy_from(object); build_object_proxy_group(object); /* Object dupligroup. */ - if (object->instance_collection != NULL) { - build_collection(NULL, object, object->instance_collection); + if (object->instance_collection != nullptr) { + build_collection(nullptr, object, object->instance_collection); } /* Point caches. */ build_object_pointcache(object); @@ -708,11 +711,11 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) void DepsgraphRelationBuilder::build_object_proxy_from(Object *object) { - if (object->proxy_from == NULL) { + if (object->proxy_from == nullptr) { return; } /* Object is linked here (comes from the library). */ - build_object(NULL, object->proxy_from); + build_object(nullptr, object->proxy_from); ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); @@ -720,11 +723,11 @@ void DepsgraphRelationBuilder::build_object_proxy_from(Object *object) void DepsgraphRelationBuilder::build_object_proxy_group(Object *object) { - if (object->proxy_group == NULL || object->proxy_group == object->proxy) { + if (object->proxy_group == nullptr || object->proxy_group == object->proxy) { return; } /* Object is local here (local in .blend file, users interacts with it). */ - build_object(NULL, object->proxy_group); + build_object(nullptr, object->proxy_group); OperationKey proxy_group_eval_key( &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); @@ -733,7 +736,7 @@ void DepsgraphRelationBuilder::build_object_proxy_group(Object *object) void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object) { - if (base == NULL) { + if (base == nullptr) { return; } OperationKey view_layer_done_key( @@ -749,7 +752,7 @@ void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object) void DepsgraphRelationBuilder::build_object_data(Object *object) { - if (object->data == NULL) { + if (object->data == nullptr) { return; } ID *obdata_id = (ID *)object->data; @@ -778,7 +781,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) break; } case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { build_proxy_rig(object); } else { @@ -799,7 +802,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) break; } Key *key = BKE_key_from_object(object); - if (key != NULL) { + if (key != nullptr) { ComponentKey geometry_key((ID *)object->data, NodeType::GEOMETRY); ComponentKey key_key(&key->id, NodeType::GEOMETRY); add_relation(key_key, geometry_key, "Shapekeys"); @@ -807,7 +810,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) } /* Materials. */ Material ***materials_ptr = give_matarar(object); - if (materials_ptr != NULL) { + if (materials_ptr != nullptr) { short *num_materials_ptr = give_totcolp(object); build_materials(*materials_ptr, *num_materials_ptr); } @@ -1029,7 +1032,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); /* Invalid constraint type. */ - if (cti == NULL) { + if (cti == nullptr) { continue; } /* Special case for camera tracking -- it doesn't use targets to @@ -1056,7 +1059,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { depends_on_camera = true; } - if (depends_on_camera && scene_->camera != NULL) { + if (depends_on_camera && scene_->camera != nullptr) { ComponentKey camera_key(&scene_->camera->id, NodeType::TRANSFORM); add_relation(camera_key, constraint_op_key, cti->name); } @@ -1077,10 +1080,10 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, } } else if (cti->get_constraint_targets) { - ListBase targets = {NULL, NULL}; + ListBase targets = {nullptr, nullptr}; cti->get_constraint_targets(con, &targets); LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { - if (ct->tar == NULL) { + if (ct->tar == nullptr) { continue; } if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { @@ -1208,13 +1211,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) void DepsgraphRelationBuilder::build_animdata_curves(ID *id) { AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { + if (adt == nullptr) { return; } - if (adt->action != NULL) { + if (adt->action != nullptr) { build_action(adt->action); } - if (adt->action == NULL && BLI_listbase_is_empty(&adt->nla_tracks)) { + if (adt->action == nullptr && BLI_listbase_is_empty(&adt->nla_tracks)) { return; } /* Ensure evaluation order from entry to exit. */ @@ -1226,20 +1229,20 @@ void DepsgraphRelationBuilder::build_animdata_curves(ID *id) /* Wire up dependency from action. */ ComponentKey adt_key(id, NodeType::ANIMATION); /* Relation from action itself. */ - if (adt->action != NULL) { + if (adt->action != nullptr) { ComponentKey action_key(&adt->action->id, NodeType::ANIMATION); add_relation(action_key, adt_key, "Action -> Animation"); } /* Get source operations. */ Node *node_from = get_node(adt_key); - BLI_assert(node_from != NULL); - if (node_from == NULL) { + BLI_assert(node_from != nullptr); + if (node_from == nullptr) { return; } OperationNode *operation_from = node_from->get_exit_operation(); - BLI_assert(operation_from != NULL); + BLI_assert(operation_from != nullptr); /* Build relations from animation operation to properties it changes. */ - if (adt->action != NULL) { + if (adt->action != nullptr) { build_animdata_curves_targets(id, adt_key, operation_from, &adt->action->curves); } LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { @@ -1263,7 +1266,7 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id, continue; } Node *node_to = rna_node_query_.find_node(&ptr, prop, RNAPointerSource::ENTRY); - if (node_to == NULL) { + if (node_to == nullptr) { continue; } OperationNode *operation_to = node_to->get_entry_operation(); @@ -1297,7 +1300,7 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id, ListBase *strips) { LISTBASE_FOREACH (NlaStrip *, strip, strips) { - if (strip->act != NULL) { + if (strip->act != nullptr) { build_action(strip->act); ComponentKey action_key(&strip->act->id, NodeType::ANIMATION); @@ -1305,7 +1308,7 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id, build_animdata_curves_targets(id, adt_key, operation_from, &strip->act->curves); } - else if (strip->strips.first != NULL) { + else if (strip->strips.first != nullptr) { build_animdata_nlastrip_targets(id, adt_key, operation_from, &strip->strips); } } @@ -1314,7 +1317,7 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id, void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) { AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { + if (adt == nullptr) { return; } ComponentKey adt_key(id, NodeType::ANIMATION); @@ -1339,7 +1342,7 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) * * TODO(sergey): Avoid liner lookup somehow. */ if (fcu->array_index > 0) { - FCurve *fcu_prev = NULL; + FCurve *fcu_prev = nullptr; LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { /* Writing to different RNA paths is */ const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; @@ -1351,11 +1354,11 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) continue; } /* Choose fcurve with highest possible array index. */ - if (fcu_prev == NULL || fcu_candidate->array_index > fcu_prev->array_index) { + if (fcu_prev == nullptr || fcu_candidate->array_index > fcu_prev->array_index) { fcu_prev = fcu_candidate; } } - if (fcu_prev != NULL) { + if (fcu_prev != nullptr) { OperationKey prev_driver_key(id, NodeType::PARAMETERS, OperationCode::DRIVER, @@ -1427,7 +1430,7 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) { /* Validate the RNA path pointer just in case. */ const char *rna_path = fcu->rna_path; - if (rna_path == NULL || rna_path[0] == '\0') { + if (rna_path == nullptr || rna_path[0] == '\0') { return; } /* Parse the RNA path to find the target property pointer. */ @@ -1457,16 +1460,16 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) /* Drivers on armature-level bone settings (i.e. bbone stuff), * which will affect the evaluation of corresponding pose bones. */ Bone *bone = (Bone *)property_entry_key.ptr.data; - if (bone != NULL) { + if (bone != nullptr) { /* Find objects which use this, and make their eval callbacks * depend on this. */ for (IDNode *to_node : graph_->id_nodes) { if (GS(to_node->id_orig->name) == ID_OB) { Object *object = (Object *)to_node->id_orig; /* We only care about objects with pose data which use this. */ - if (object->data == id_ptr && object->pose != NULL) { + if (object->data == id_ptr && object->pose != nullptr) { bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone->name); - if (pchan != NULL) { + if (pchan != nullptr) { OperationKey bone_key( &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone"); @@ -1494,14 +1497,14 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) PointerRNA id_ptr; PointerRNA ptr; RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { + if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, nullptr, nullptr)) { if (id_ptr.owner_id != ptr.owner_id) { ComponentKey cow_key(ptr.owner_id, NodeType::COPY_ON_WRITE); add_relation(cow_key, driver_key, "Driven CoW -> Driver", RELATION_CHECK_BEFORE_ADD); } } } - if (property_entry_key.prop != NULL && RNA_property_is_idprop(property_entry_key.prop)) { + if (property_entry_key.prop != nullptr && RNA_property_is_idprop(property_entry_key.prop)) { RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT); OperationKey parameters_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); add_relation(property_exit_key, parameters_key, "Driven Property -> Properties"); @@ -1523,16 +1526,16 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) /* Only used targets. */ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { ID *target_id = dtar->id; - if (target_id == NULL) { + if (target_id == nullptr) { continue; } build_id(target_id); build_driver_id_property(target_id, dtar->rna_path); /* Look up the proxy - matches dtar_id_ensure_proxy_from during evaluation. */ - Object *object = NULL; + Object *object = nullptr; if (GS(target_id->name) == ID_OB) { object = (Object *)target_id; - if (object->proxy_from != NULL) { + if (object->proxy_from != nullptr) { /* Redirect the target to the proxy, like in evaluation. */ object = object->proxy_from; target_id = &object->id; @@ -1545,7 +1548,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (object && object->type == OB_ARMATURE) && (dtar->pchan_name[0])) { bPoseChannel *target_pchan = BKE_pose_channel_find_name(object->pose, dtar->pchan_name); - if (target_pchan == NULL) { + if (target_pchan == nullptr) { continue; } OperationKey variable_key( @@ -1566,7 +1569,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) OperationKey target_key(target_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); add_relation(target_key, driver_key, "Target -> Driver"); } - else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') { + else if (dtar->rna_path != nullptr && dtar->rna_path[0] != '\0') { RNAPathKey variable_exit_key(target_id, dtar->rna_path, RNAPointerSource::EXIT); if (RNA_pointer_is_null(&variable_exit_key.ptr)) { continue; @@ -1578,7 +1581,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) add_relation(variable_exit_key, driver_key, "RNA Target -> Driver"); } else { - /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this + /* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this * is an incomplete target reference, so nothing to do here. */ } } @@ -1588,7 +1591,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_path) { - if (id == NULL || rna_path == NULL) { + if (id == nullptr || rna_path == nullptr) { return; } PointerRNA id_ptr, ptr; @@ -1598,7 +1601,7 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_ if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) { return; } - if (prop == NULL) { + if (prop == nullptr) { return; } if (!RNA_property_is_idprop(prop)) { @@ -1630,7 +1633,7 @@ void DepsgraphRelationBuilder::build_world(World *world) build_animdata(&world->id); build_parameters(&world->id); /* world's nodetree */ - if (world->nodetree != NULL) { + if (world->nodetree != nullptr) { build_nodetree(world->nodetree); OperationKey ntree_key( &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); @@ -1660,7 +1663,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) LISTBASE_FOREACH (EffectorRelation *, effector_relation, effector_relations) { ComponentKey effector_transform_key(&effector_relation->ob->id, NodeType::TRANSFORM); add_relation(effector_transform_key, rb_init_key, "RigidBody Field"); - if (effector_relation->pd != NULL) { + if (effector_relation->pd != nullptr) { const short shape = effector_relation->pd->shape; if (ELEM(shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS)) { ComponentKey effector_geometry_key(&effector_relation->ob->id, NodeType::GEOMETRY); @@ -1669,8 +1672,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) } } /* Objects. */ - if (rbw->group != NULL) { - build_collection(NULL, NULL, rbw->group); + if (rbw->group != nullptr) { + build_collection(nullptr, nullptr, rbw->group); FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { if (object->type != OB_MESH) { continue; @@ -1690,7 +1693,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* Geometry must be known to create the rigid body. RBO_MESH_BASE * uses the non-evaluated mesh, so then the evaluation is * unnecessary. */ - if (object->rigidbody_object != NULL && + if (object->rigidbody_object != nullptr && object->rigidbody_object->mesh_source != RBO_MESH_BASE) { /* NOTE: We prefer this relation to be never killed, to avoid * access partially evaluated mesh from solver. */ @@ -1709,18 +1712,18 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* Constraints. */ - if (rbw->constraints != NULL) { + if (rbw->constraints != nullptr) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { - /* When either ob1 or ob2 is NULL, the constraint doesn't + if (rbc == nullptr || rbc->ob1 == nullptr || rbc->ob2 == nullptr) { + /* When either ob1 or ob2 is nullptr, the constraint doesn't * work. */ continue; } /* Make sure indirectly linked objects are fully built. */ - build_object(NULL, object); - build_object(NULL, rbc->ob1); - build_object(NULL, rbc->ob2); + build_object(nullptr, object); + build_object(nullptr, rbc->ob1); + build_object(nullptr, rbc->ob2); /* final result of the constraint object's transform controls how * the constraint affects the physics sim for these objects. */ ComponentKey trans_key(&object->id, NodeType::TRANSFORM); @@ -1776,8 +1779,8 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object) add_particle_collision_relations( psys_key, object, part->collision_group, "Particle Collision"); } - else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd != NULL && - psys->clmd->coll_parms != NULL) { + else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd != nullptr && + psys->clmd->coll_parms != nullptr) { add_particle_collision_relations( psys_key, object, psys->clmd->coll_parms->group, "Hair Collision"); } @@ -1785,17 +1788,17 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object) add_particle_forcefield_relations( psys_key, object, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field"); /* Boids .*/ - if (part->boids != NULL) { + if (part->boids != nullptr) { LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { - Object *ruleob = NULL; + Object *ruleob = nullptr; if (rule->type == eBoidRuleType_Avoid) { ruleob = ((BoidRuleGoalAvoid *)rule)->ob; } else if (rule->type == eBoidRuleType_FollowLeader) { ruleob = ((BoidRuleFollowLeader *)rule)->ob; } - if (ruleob != NULL) { + if (ruleob != nullptr) { ComponentKey ruleob_key(&ruleob->id, NodeType::TRANSFORM); add_relation(ruleob_key, psys_key, "Boid Rule"); } @@ -1805,11 +1808,11 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object) /* Keyed particle targets. */ if (part->phystype == PART_PHYS_KEYED) { LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { - if (particle_target->ob == NULL || particle_target->ob == object) { + if (particle_target->ob == nullptr || particle_target->ob == object) { continue; } /* Make sure target object is pulled into the graph. */ - build_object(NULL, particle_target->ob); + build_object(nullptr, particle_target->ob); /* Use geometry component, since that's where particles are * actually evaluated. */ ComponentKey target_key(&particle_target->ob->id, NodeType::GEOMETRY); @@ -1819,16 +1822,16 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object) /* Visualization. */ switch (part->ren_as) { case PART_DRAW_OB: - if (part->instance_object != NULL) { + if (part->instance_object != nullptr) { /* Make sure object's relations are all built. */ - build_object(NULL, part->instance_object); + build_object(nullptr, part->instance_object); /* Build relation for the particle visualization. */ build_particle_system_visualization_object(object, psys, part->instance_object); } break; case PART_DRAW_GR: - if (part->instance_collection != NULL) { - build_collection(NULL, NULL, part->instance_collection); + if (part->instance_collection != nullptr) { + build_collection(nullptr, nullptr, part->instance_collection); LISTBASE_FOREACH (CollectionObject *, go, &part->instance_collection->gobject) { build_particle_system_visualization_object(object, psys, go->ob); } @@ -1861,7 +1864,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part) /* Texture slots. */ for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) { MTex *mtex = part->mtex[mtex_index]; - if (mtex == NULL || mtex->tex == NULL) { + if (mtex == nullptr || mtex->tex == nullptr) { continue; } build_texture(mtex->tex); @@ -1872,7 +1875,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part) RELATION_FLAG_FLUSH_USER_EDIT_ONLY); /* TODO(sergey): Consider moving texture space handling to an own * function. */ - if (mtex->texco == TEXCO_OBJECT && mtex->object != NULL) { + if (mtex->texco == TEXCO_OBJECT && mtex->object != nullptr) { ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM); add_relation(object_key, particle_settings_eval_key, "Particle Texture Space"); } @@ -1956,7 +1959,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); rel->flag |= RELATION_FLAG_NO_FLUSH; /* Modifiers */ - if (object->modifiers.first != NULL) { + if (object->modifiers.first != nullptr) { ModifierUpdateDepsgraphContext ctx = {}; ctx.scene = scene_; ctx.object = object; @@ -1974,7 +1977,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) } } /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { + if (object->greasepencil_modifiers.first != nullptr) { ModifierUpdateDepsgraphContext ctx = {}; ctx.scene = scene_; ctx.object = object; @@ -1993,7 +1996,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) } } /* Shader FX. */ - if (object->shader_fx.first != NULL) { + if (object->shader_fx.first != nullptr) { ModifierUpdateDepsgraphContext ctx = {}; ctx.scene = scene_; ctx.object = object; @@ -2053,8 +2056,8 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) /* Object data data-block. */ build_object_data_geometry_datablock((ID *)object->data); Key *key = BKE_key_from_object(object); - if (key != NULL) { - if (key->adt != NULL) { + if (key != nullptr) { + if (key->adt != nullptr) { if (key->adt->action || key->adt->nla_tracks.first) { ComponentKey obdata_key((ID *)object->data, NodeType::GEOMETRY); ComponentKey adt_key(&key->id, NodeType::ANIMATION); @@ -2087,7 +2090,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) build_parameters(obdata); /* ShapeKeys. */ Key *key = BKE_key_from_id(obdata); - if (key != NULL) { + if (key != nullptr) { build_shapekeys(key); } /* Link object data evaluation node to exit operation. */ @@ -2103,22 +2106,22 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) break; case ID_CU: { Curve *cu = (Curve *)obdata; - if (cu->bevobj != NULL) { + if (cu->bevobj != nullptr) { ComponentKey bevob_geom_key(&cu->bevobj->id, NodeType::GEOMETRY); add_relation(bevob_geom_key, obdata_geom_eval_key, "Curve Bevel Geometry"); ComponentKey bevob_key(&cu->bevobj->id, NodeType::TRANSFORM); add_relation(bevob_key, obdata_geom_eval_key, "Curve Bevel Transform"); - build_object(NULL, cu->bevobj); + build_object(nullptr, cu->bevobj); } - if (cu->taperobj != NULL) { + if (cu->taperobj != nullptr) { ComponentKey taperob_key(&cu->taperobj->id, NodeType::GEOMETRY); add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); - build_object(NULL, cu->taperobj); + build_object(nullptr, cu->taperobj); } - if (cu->textoncurve != NULL) { + if (cu->textoncurve != nullptr) { ComponentKey textoncurve_key(&cu->textoncurve->id, NodeType::GEOMETRY); add_relation(textoncurve_key, obdata_geom_eval_key, "Text on Curve"); - build_object(NULL, cu->textoncurve); + build_object(nullptr, cu->textoncurve); } break; } @@ -2141,7 +2144,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) * we need to rebuild the bGPDstroke->triangles caches). */ for (int i = 0; i < gpd->totcol; i++) { Material *ma = gpd->mat[i]; - if ((ma != NULL) && (ma->gp_style != NULL)) { + if ((ma != nullptr) && (ma->gp_style != nullptr)) { OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); add_relation(material_key, geometry_key, "Material -> GP Data"); } @@ -2170,8 +2173,8 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera) } build_animdata(&camera->id); build_parameters(&camera->id); - if (camera->dof.focus_object != NULL) { - build_object(NULL, camera->dof.focus_object); + if (camera->dof.focus_object != nullptr) { + build_object(nullptr, camera->dof.focus_object); ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); ComponentKey dof_ob_key(&camera->dof.focus_object->id, NodeType::TRANSFORM); add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); @@ -2187,7 +2190,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) build_animdata(&lamp->id); build_parameters(&lamp->id); /* light's nodetree */ - if (lamp->nodetree != NULL) { + if (lamp->nodetree != nullptr) { build_nodetree(lamp->nodetree); ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); @@ -2198,7 +2201,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) { - if (ntree == NULL) { + if (ntree == nullptr) { return; } if (built_map_.checkIsBuiltAndTag(ntree)) { @@ -2210,7 +2213,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) /* nodetree's nodes... */ LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; - if (id == NULL) { + if (id == nullptr) { continue; } ID_Type id_type = GS(id->name); @@ -2230,7 +2233,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) add_relation(image_key, shading_key, "Image -> Node"); } else if (id_type == ID_OB) { - build_object(NULL, (Object *)id); + build_object(nullptr, (Object *)id); ComponentKey object_transform_key(id, NodeType::TRANSFORM); add_relation(object_transform_key, shading_key, "Object Transform -> Node"); if (object_have_geometry_component(reinterpret_cast<Object *>(id))) { @@ -2245,8 +2248,8 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) * * On the one hand it's annoying to always pull it in, but on another hand it's also annoying * to have hardcoded node-type exception here. */ - if (node_scene->camera != NULL) { - build_object(NULL, node_scene->camera); + if (node_scene->camera != nullptr) { + build_object(nullptr, node_scene->camera); } } else if (id_type == ID_TXT) { @@ -2296,7 +2299,7 @@ void DepsgraphRelationBuilder::build_material(Material *material) build_animdata(&material->id); build_parameters(&material->id); /* material's nodetree */ - if (material->nodetree != NULL) { + if (material->nodetree != nullptr) { build_nodetree(material->nodetree); OperationKey ntree_key( &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); @@ -2309,7 +2312,7 @@ void DepsgraphRelationBuilder::build_material(Material *material) void DepsgraphRelationBuilder::build_materials(Material **materials, int num_materials) { for (int i = 0; i < num_materials; i++) { - if (materials[i] == NULL) { + if (materials[i] == nullptr) { continue; } build_material(materials[i]); @@ -2329,7 +2332,7 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture) build_nodetree(texture->nodetree); /* Special cases for different IDs which texture uses. */ if (texture->type == TEX_IMAGE) { - if (texture->ima != NULL) { + if (texture->ima != nullptr) { build_image(texture->ima); } } @@ -2411,7 +2414,7 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask) for (int i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; MaskParent *parent = &point->parent; - if (parent == NULL || parent->id == NULL) { + if (parent == nullptr || parent->id == nullptr) { continue; } build_id(parent->id); @@ -2463,7 +2466,7 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker) } build_animdata(&speaker->id); build_parameters(&speaker->id); - if (speaker->sound != NULL) { + if (speaker->sound != nullptr) { build_sound(speaker->sound); ComponentKey speaker_key(&speaker->id, NodeType::AUDIO); ComponentKey sound_key(&speaker->sound->id, NodeType::AUDIO); @@ -2482,7 +2485,7 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound) void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene) { - if (scene->ed == NULL) { + if (scene->ed == nullptr) { return; } build_scene_audio(scene); @@ -2492,18 +2495,18 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene) Sequence *seq; bool has_audio_strips = false; SEQ_BEGIN (scene->ed, seq) { - if (seq->sound != NULL) { + if (seq->sound != nullptr) { build_sound(seq->sound); ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO); add_relation(sound_key, sequencer_key, "Sound -> Sequencer"); has_audio_strips = true; } - if (seq->scene != NULL) { + if (seq->scene != nullptr) { build_scene_parameters(seq->scene); /* This is to support 3D audio. */ has_audio_strips = true; } - if (seq->type == SEQ_TYPE_SCENE && seq->scene != NULL) { + if (seq->type == SEQ_TYPE_SCENE && seq->scene != nullptr) { if (seq->flag & SEQ_SCENE_STRIPS) { build_scene_sequencer(seq->scene); ComponentKey sequence_scene_audio_key(&seq->scene->id, NodeType::AUDIO); @@ -2533,7 +2536,7 @@ void DepsgraphRelationBuilder::build_scene_speakers(Scene * /*scene*/, ViewLayer if (object->type != OB_SPEAKER || !need_pull_base_into_graph(base)) { continue; } - build_object(NULL, base->object); + build_object(nullptr, base->object); } } @@ -2559,7 +2562,7 @@ void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id) void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree) { - if (ntree == NULL) { + if (ntree == nullptr) { return; } build_nested_datablock(owner, &ntree->id); @@ -2567,7 +2570,7 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key) { - if (key == NULL) { + if (key == nullptr) { return; } build_nested_datablock(owner, &key->id); @@ -2624,7 +2627,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) /* All entry operations of each component should wait for a proper * copy of ID. */ OperationNode *op_entry = comp_node->get_entry_operation(); - if (op_entry != NULL) { + if (op_entry != nullptr) { Relation *rel = graph_->add_new_relation(op_cow, op_entry, "CoW Dependency"); rel->flag |= rel_flag; } @@ -2670,7 +2673,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) if (GS(id_orig->name) == ID_OB) { Object *object = (Object *)id_orig; ID *object_data_id = (ID *)object->data; - if (object_data_id != NULL) { + if (object_data_id != nullptr) { if (deg_copy_on_write_is_needed(object_data_id)) { OperationKey data_copy_on_write_key( object_data_id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); @@ -2682,6 +2685,26 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) BLI_assert(object->type == OB_EMPTY); } } + +#if 0 + /* NOTE: Relation is disabled since AnimationBackup() is disabled. + * See comment in AnimationBackup:init_from_id(). */ + + /* Copy-on-write of write will iterate over f-curves to store current values corresponding + * to their RNA path. This means that action must be copied prior to the ID's copy-on-write, + * otherwise depsgraph might try to access freed data. */ + AnimData *animation_data = BKE_animdata_from_id(id_orig); + if (animation_data != nullptr) { + if (animation_data->action != nullptr) { + OperationKey action_copy_on_write_key( + &animation_data->action->id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + add_relation(action_copy_on_write_key, + copy_on_write_key, + "Eval Order", + RELATION_FLAG_GODMODE | RELATION_FLAG_NO_FLUSH); + } + } +#endif } /* **** ID traversal callbacks functions **** */ @@ -2693,7 +2716,7 @@ void DepsgraphRelationBuilder::modifier_walk(void *user_data, { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; ID *id = *idpoin; - if (id == NULL) { + if (id == nullptr) { return; } data->builder->build_id(id); @@ -2706,7 +2729,7 @@ void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; ID *id = *idpoin; - if (id == NULL) { + if (id == nullptr) { return; } data->builder->build_id(id); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 5c543ce9c23..11eb31c68f6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -368,7 +368,7 @@ struct DepsNodeHandle { const char *default_name = "") : builder(builder), node(node), default_name(default_name) { - BLI_assert(node != NULL); + BLI_assert(node != nullptr); } DepsgraphRelationBuilder *builder; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h index 4412fa3fca3..eeeb58100b0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -36,7 +36,7 @@ template<typename KeyType> OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType &key) { Node *node = get_node(key); - return node != NULL ? node->get_exit_operation() : NULL; + return node != nullptr ? node->get_exit_operation() : nullptr; } template<typename KeyFrom, typename KeyTo> @@ -47,8 +47,8 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, { Node *node_from = get_node(key_from); Node *node_to = get_node(key_to); - OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr; + OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr; if (op_from && op_to) { return add_operation_relation(op_from, op_to, description, flags); } @@ -80,7 +80,7 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, key_to.identifier().c_str()); } } - return NULL; + return nullptr; } template<typename KeyTo> @@ -91,11 +91,11 @@ Relation *DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from, { TimeSourceNode *time_from = get_node(key_from); Node *node_to = get_node(key_to); - OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (time_from != NULL && op_to != NULL) { + OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr; + if (time_from != nullptr && op_to != nullptr) { return add_time_relation(time_from, op_to, description, flags); } - return NULL; + return nullptr; } template<typename KeyType> @@ -105,9 +105,9 @@ Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_ int flags) { Node *node_from = get_node(key_from); - OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr; OperationNode *op_to = handle->node->get_entry_operation(); - if (op_from != NULL && op_to != NULL) { + if (op_from != nullptr && op_to != nullptr) { return add_operation_relation(op_from, op_to, description, flags); } else { @@ -124,7 +124,7 @@ Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_ key_from.identifier().c_str()); } } - return NULL; + return nullptr; } template<typename KeyTo> @@ -135,7 +135,7 @@ Relation *DepsgraphRelationBuilder::add_depends_on_transform_relation(ID *id, { if (GS(id->name) == ID_OB) { Object *object = reinterpret_cast<Object *>(id); - if (object->rigidbody_object != NULL) { + if (object->rigidbody_object != nullptr) { OperationKey transform_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); return add_relation(transform_key, key_to, description, flags); } @@ -162,12 +162,12 @@ bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom &key_from, /* Get operations for requested keys. */ Node *node_from = get_node(key_from); Node *node_to = get_node(key_to); - if (node_from == NULL || node_to == NULL) { + if (node_from == nullptr || node_to == nullptr) { return false; } OperationNode *op_from = node_from->get_exit_operation(); OperationNode *op_to = node_to->get_entry_operation(); - if (op_from == NULL || op_to == NULL) { + if (op_from == nullptr || op_to == nullptr) { return false; } /* Different armatures, bone can't be the same. */ @@ -193,12 +193,12 @@ bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(const KeyFrom &k /* Get operations for requested keys. */ Node *node_from = get_node(key_from); Node *node_to = get_node(key_to); - if (node_from == NULL || node_to == NULL) { + if (node_from == nullptr || node_to == nullptr) { return false; } OperationNode *op_from = node_from->get_exit_operation(); OperationNode *op_to = node_to->get_entry_operation(); - if (op_from == NULL || op_to == NULL) { + if (op_from == nullptr || op_to == nullptr) { return false; } /* Check if this is actually a node tree. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 35af968d46e..6c449900f03 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -30,7 +30,7 @@ namespace DEG { //////////////////////////////////////////////////////////////////////////////// // Time source. -TimeSourceKey::TimeSourceKey() : id(NULL) +TimeSourceKey::TimeSourceKey() : id(nullptr) { } @@ -46,7 +46,7 @@ string TimeSourceKey::identifier() const //////////////////////////////////////////////////////////////////////////////// // Component. -ComponentKey::ComponentKey() : id(NULL), type(NodeType::UNDEFINED), name("") +ComponentKey::ComponentKey() : id(nullptr), type(NodeType::UNDEFINED), name("") { } @@ -72,7 +72,7 @@ string ComponentKey::identifier() const // Operation. OperationKey::OperationKey() - : id(NULL), + : id(nullptr), component_type(NodeType::UNDEFINED), component_name(""), opcode(OperationCode::OPERATION), @@ -176,7 +176,7 @@ RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) : id(i int index; if (!RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) { ptr = PointerRNA_NULL; - prop = NULL; + prop = nullptr; } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 4a86b16627c..12cd6936a13 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -58,6 +58,7 @@ extern "C" { #include "intern/node/deg_node_operation.h" #include "intern/depsgraph_type.h" +#include "intern/depsgraph_relation.h" namespace DEG { @@ -70,7 +71,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, bKinematicConstraint *data = (bKinematicConstraint *)con->data; /* Attach owner to IK Solver to. */ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - if (rootchan == NULL) { + if (rootchan == nullptr) { return; } OperationKey pchan_local_key( @@ -90,7 +91,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key; /* IK target */ /* TODO(sergey): This should get handled as part of the constraint code. */ - if (data->tar != NULL) { + if (data->tar != nullptr) { /* Different object - requires its transform. */ if (data->tar != object) { ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); @@ -119,7 +120,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, } /* Pole Target. */ /* TODO(sergey): This should get handled as part of the constraint code. */ - if (data->poletar != NULL) { + if (data->poletar != nullptr) { /* Different object - requires its transform. */ if (data->poletar != object) { ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); @@ -146,7 +147,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, "\nStarting IK Build: pchan = %s, target = (%s, %s), " "segcount = %d\n", pchan->name, - data->tar ? data->tar->id.name : "NULL", + data->tar ? data->tar->id.name : "nullptr", data->subtarget, data->rootbone); bPoseChannel *parchan = pchan; @@ -160,7 +161,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, add_relation(parchan_transforms_key, solver_key, "IK Solver Owner"); /* Walk to the chain's root. */ int segcount = 0; - while (parchan != NULL) { + while (parchan != nullptr) { /* Make IK-solver dependent on this bone's result, since it can only run * after the standard results of the bone are know. Validate links step * on the bone will ensure that users of this bone only grab the result @@ -217,7 +218,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, /* Attach owner to IK Solver. */ add_relation(transforms_key, solver_key, "Spline IK Solver Owner", RELATION_FLAG_GODMODE); /* Attach path dependency to solver. */ - if (data->tar != NULL) { + if (data->tar != nullptr) { ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY); add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK"); ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM); @@ -231,7 +232,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, root_map->add_bone(pchan->name, rootchan->name); /* Walk to the chain's root/ */ int segcount = 1; - for (bPoseChannel *parchan = pchan->parent; parchan != NULL && segcount < data->chainlen; + for (bPoseChannel *parchan = pchan->parent; parchan != nullptr && segcount < data->chainlen; parchan = parchan->parent, segcount++) { /* Make Spline IK solver dependent on this bone's result, since it can * only run after the standard results of the bone are know. Validate @@ -257,7 +258,7 @@ void DepsgraphRelationBuilder::build_inter_ik_chains(Object *object, const bPoseChannel *rootchan, const RootPChanMap *root_map) { - bPoseChannel *deepest_root = NULL; + bPoseChannel *deepest_root = nullptr; const char *root_name = rootchan->name; /* Find shared IK chain root. */ @@ -267,7 +268,7 @@ void DepsgraphRelationBuilder::build_inter_ik_chains(Object *object, } deepest_root = parchan; } - if (deepest_root == NULL) { + if (deepest_root == nullptr) { return; } @@ -362,7 +363,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) /* Local to pose parenting operation. */ add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose"); /* Parent relation. */ - if (pchan->parent != NULL) { + if (pchan->parent != nullptr) { OperationCode parent_key_opcode; /* NOTE: this difference in handling allows us to prevent lockups * while ensuring correct poses for separate chains. */ @@ -377,7 +378,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone"); } /* Build constraints. */ - if (pchan->constraints.first != NULL) { + if (pchan->constraints.first != nullptr) { /* Build relations for indirectly linked objects. */ BuilderWalkUserData data; data.builder = this; @@ -442,8 +443,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object) add_relation(bone_ready_key, pose_cleanup_key, "Ready -> Cleanup"); } /* Custom shape. */ - if (pchan->custom != NULL) { - build_object(NULL, pchan->custom); + if (pchan->custom != nullptr) { + build_object(nullptr, pchan->custom); } } } @@ -486,13 +487,13 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) * the parent bone, some users expect the parent to be ready if the * bone itself is (e.g. for computing the local space matrix). */ - if (pchan->parent != NULL) { + if (pchan->parent != nullptr) { OperationKey parent_key( &object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE); add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone"); } - if (pchan->prop != NULL) { + if (pchan->prop != nullptr) { OperationKey bone_parameters( &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); OperationKey from_bone_parameters( diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc index 4e0c2cbba0c..08191bcecc8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -42,8 +42,8 @@ void DepsgraphRelationBuilder::build_scene_render(Scene *scene, ViewLayer *view_ build_scene_sequencer(scene); build_scene_speakers(scene, view_layer); } - if (scene->camera != NULL) { - build_object(NULL, scene->camera); + if (scene->camera != nullptr) { + build_object(nullptr, scene->camera); } } @@ -64,7 +64,7 @@ void DepsgraphRelationBuilder::build_scene_compositor(Scene *scene) if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_COMPOSITOR)) { return; } - if (scene->nodetree == NULL) { + if (scene->nodetree == nullptr) { return; } build_nodetree(scene->nodetree); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index e81ed8b410c..41e91ba7286 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -70,7 +70,7 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) continue; } if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { - build_collection(lc, NULL, lc->collection); + build_collection(lc, nullptr, lc->collection); } build_layer_collections(&lc->layer_collections); } @@ -78,10 +78,10 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) void DepsgraphRelationBuilder::build_freestyle_lineset(FreestyleLineSet *fls) { - if (fls->group != NULL) { - build_collection(NULL, NULL, fls->group); + if (fls->group != nullptr) { + build_collection(nullptr, nullptr, fls->group); } - if (fls->linestyle != NULL) { + if (fls->linestyle != nullptr) { build_freestyle_linestyle(fls->linestyle); } } @@ -95,7 +95,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, /* Scene objects. */ /* NOTE: Nodes builder requires us to pass CoW base because it's being * passed to the evaluation functions. During relations builder we only - * do NULL-pointer check of the base, so it's fine to pass original one. */ + * do nullptr-pointer check of the base, so it's fine to pass original one. */ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (need_pull_base_into_graph(base)) { build_object(base, base->object); @@ -104,19 +104,19 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, build_layer_collections(&view_layer->layer_collections); - if (scene->camera != NULL) { - build_object(NULL, scene->camera); + if (scene->camera != nullptr) { + build_object(nullptr, scene->camera); } /* Rigidbody. */ - if (scene->rigidbody_world != NULL) { + if (scene->rigidbody_world != nullptr) { build_rigidbody(scene); } /* Scene's animation and drivers. */ - if (scene->adt != NULL) { + if (scene->adt != nullptr) { build_animdata(&scene->id); } /* World. */ - if (scene->world != NULL) { + if (scene->world != nullptr) { build_world(scene->world); } /* Masks. */ @@ -128,7 +128,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, build_movieclip(clip); } /* Material override. */ - if (view_layer->mat_override != NULL) { + if (view_layer->mat_override != nullptr) { build_material(view_layer->mat_override); } /* Freestyle linesets. */ @@ -149,7 +149,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, build_scene_sequencer(scene); } /* Build all set scenes. */ - if (scene->set != NULL) { + if (scene->set != nullptr) { ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index d092240e665..853f8995d68 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -57,14 +57,14 @@ namespace DEG { class RNANodeQueryIDData { public: - explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(NULL) + explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(nullptr) { } ~RNANodeQueryIDData() { - if (contraint_to_pchan_map_ != NULL) { - BLI_ghash_free(contraint_to_pchan_map_, NULL, NULL); + if (contraint_to_pchan_map_ != nullptr) { + BLI_ghash_free(contraint_to_pchan_map_, nullptr, nullptr); } } @@ -76,13 +76,13 @@ class RNANodeQueryIDData { void ensure_constraint_to_pchan_map() { - if (contraint_to_pchan_map_ != NULL) { + if (contraint_to_pchan_map_ != nullptr) { return; } BLI_assert(GS(id_->name) == ID_OB); const Object *object = reinterpret_cast<const Object *>(id_); contraint_to_pchan_map_ = BLI_ghash_ptr_new("id data pchan constraint map"); - if (object->pose != NULL) { + if (object->pose != nullptr) { LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) { LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) { BLI_ghash_insert(contraint_to_pchan_map_, @@ -105,7 +105,7 @@ class RNANodeQueryIDData { /* ***************************** Node Identifier **************************** */ RNANodeIdentifier::RNANodeIdentifier() - : id(NULL), + : id(nullptr), type(NodeType::UNDEFINED), component_name(""), operation_code(OperationCode::OPERATION), @@ -116,7 +116,7 @@ RNANodeIdentifier::RNANodeIdentifier() bool RNANodeIdentifier::is_valid() const { - return id != NULL && type != NodeType::UNDEFINED; + return id != nullptr && type != NodeType::UNDEFINED; } /* ********************************** Query ********************************* */ @@ -140,7 +140,7 @@ RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder) RNANodeQuery::~RNANodeQuery() { - BLI_ghash_free(id_data_map_, NULL, ghash_id_data_free_func); + BLI_ghash_free(id_data_map_, nullptr, ghash_id_data_free_func); } Node *RNANodeQuery::find_node(const PointerRNA *ptr, @@ -149,16 +149,16 @@ Node *RNANodeQuery::find_node(const PointerRNA *ptr, { const RNANodeIdentifier node_identifier = construct_node_identifier(ptr, prop, source); if (!node_identifier.is_valid()) { - return NULL; + return nullptr; } IDNode *id_node = depsgraph_->find_id_node(node_identifier.id); - if (id_node == NULL) { - return NULL; + if (id_node == nullptr) { + return nullptr; } ComponentNode *comp_node = id_node->find_component(node_identifier.type, node_identifier.component_name); - if (comp_node == NULL) { - return NULL; + if (comp_node == nullptr) { + return nullptr; } if (node_identifier.operation_code == OperationCode::OPERATION) { return comp_node; @@ -173,7 +173,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, RNAPointerSource source) { RNANodeIdentifier node_identifier; - if (ptr->type == NULL) { + if (ptr->type == nullptr) { return node_identifier; } /* Set default values for returns. */ @@ -183,7 +183,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, node_identifier.operation_name = ""; node_identifier.operation_name_tag = -1; /* Handling of commonly known scenarios. */ - if (prop != NULL && RNA_property_is_idprop(prop)) { + if (prop != nullptr && RNA_property_is_idprop(prop)) { node_identifier.type = NodeType::PARAMETERS; node_identifier.operation_code = OperationCode::ID_PROPERTY; node_identifier.operation_name = RNA_property_identifier( @@ -196,7 +196,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, node_identifier.type = NodeType::BONE; node_identifier.component_name = pchan->name; /* However check property name for special handling. */ - if (prop != NULL) { + if (prop != nullptr) { Object *object = reinterpret_cast<Object *>(node_identifier.id); const char *prop_name = RNA_property_identifier(prop); /* B-Bone properties should connect to the final operation. */ @@ -245,7 +245,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, * at a given constraint, but for rigging one might use constraint * influence to be used to drive some corrective shape keys or so. */ const bPoseChannel *pchan = id_data->get_pchan_for_constraint(constraint); - if (pchan == NULL) { + if (pchan == nullptr) { node_identifier.type = NodeType::TRANSFORM; node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; } @@ -260,10 +260,10 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, Object *object = reinterpret_cast<Object *>(ptr->owner_id); bConstraintTarget *tgt = (bConstraintTarget *)ptr->data; /* Check whether is object or bone constraint. */ - bPoseChannel *pchan = NULL; + bPoseChannel *pchan = nullptr; bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan); - if (con != NULL) { - if (pchan != NULL) { + if (con != nullptr) { + if (pchan != nullptr) { node_identifier.type = NodeType::BONE; node_identifier.operation_code = OperationCode::BONE_LOCAL; node_identifier.component_name = pchan->name; @@ -299,7 +299,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, } else if (ptr->type == &RNA_Object) { /* Transforms props? */ - if (prop != NULL) { + if (prop != nullptr) { const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); /* TODO(sergey): How to optimize this? */ if (strstr(prop_identifier, "location") || strstr(prop_identifier, "rotation") || @@ -370,7 +370,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, node_identifier.type = NodeType::GEOMETRY; return node_identifier; } - if (prop != NULL) { + if (prop != nullptr) { /* All unknown data effectively falls under "parameter evaluation". */ node_identifier.type = NodeType::PARAMETERS; node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 13cf8e63832..fc7c546e294 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -30,6 +30,7 @@ #include "intern/node/deg_node_operation.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" #include "intern/debug/deg_debug.h" namespace DEG { diff --git a/source/blender/depsgraph/intern/debug/deg_debug.cc b/source/blender/depsgraph/intern/debug/deg_debug.cc index b811f11f721..74a042989db 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug.cc @@ -28,10 +28,50 @@ #include "BLI_hash.h" #include "BLI_string.h" +#include "PIL_time_utildefines.h" + #include "BKE_global.h" namespace DEG { +DepsgraphDebug::DepsgraphDebug() + : flags(G.debug), is_ever_evaluated(false), graph_evaluation_start_time_(0) +{ +} + +bool DepsgraphDebug::do_time_debug() const +{ + return ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); +} + +void DepsgraphDebug::begin_graph_evaluation() +{ + if (!do_time_debug()) { + return; + } + + const double current_time = PIL_check_seconds_timer(); + + if (is_ever_evaluated) { + fps_samples_.add_sample(current_time - graph_evaluation_start_time_); + } + + graph_evaluation_start_time_ = current_time; +} + +void DepsgraphDebug::end_graph_evaluation() +{ + if (!do_time_debug()) { + return; + } + + const double graph_eval_end_time = PIL_check_seconds_timer(); + printf("Depsgraph updated in %f seconds.\n", graph_eval_end_time - graph_evaluation_start_time_); + printf("Depsgraph evaluation FPS: %f\n", 1.0f / fps_samples_.get_averaged()); + + is_ever_evaluated = true; +} + bool terminal_do_color(void) { return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0; diff --git a/source/blender/depsgraph/intern/debug/deg_debug.h b/source/blender/depsgraph/intern/debug/deg_debug.h index 3e4da644641..21a802828dc 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug.h +++ b/source/blender/depsgraph/intern/debug/deg_debug.h @@ -24,6 +24,7 @@ #pragma once #include "intern/depsgraph_type.h" +#include "intern/debug/deg_time_average.h" #include "BKE_global.h" @@ -31,6 +32,38 @@ namespace DEG { +class DepsgraphDebug { + public: + DepsgraphDebug(); + + bool do_time_debug() const; + + void begin_graph_evaluation(); + void end_graph_evaluation(); + + /* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */ + int flags; + + /* Name of this dependency graph (is used for debug prints, helping to distinguish graphs + * created for different view layer). */ + string name; + + /* Is true when dependency graph was evaluated at least once. + * This is NOT an indication that depsgraph is at its evaluated state. */ + bool is_ever_evaluated; + + protected: + /* Maximum number of counters used to calculate frame rate of depsgraph update. */ + static const constexpr int MAX_FPS_COUNTERS = 64; + + /* Point in time when last graph evaluation began. + * Is initialized from begin_graph_evaluation() when time debug is enabled. + */ + double graph_evaluation_start_time_; + + AveragedTimeSampler<MAX_FPS_COUNTERS> fps_samples_; +}; + #define DEG_DEBUG_PRINTF(depsgraph, type, ...) \ do { \ if (DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_##type) { \ diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index ee3959a0861..b2f2359a954 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -36,6 +36,8 @@ extern "C" { #include "DEG_depsgraph_debug.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" + #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" @@ -553,7 +555,7 @@ static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgr deg_debug_graphviz_node(ctx, node); } TimeSourceNode *time_source = graph->find_time_source(); - if (time_source != NULL) { + if (time_source != nullptr) { deg_debug_graphviz_node(ctx, time_source); } } @@ -570,7 +572,7 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const De } TimeSourceNode *time_source = graph->find_time_source(); - if (time_source != NULL) { + if (time_source != nullptr) { deg_debug_graphviz_node_relations(ctx, time_source); } } diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc index 4a668e817fe..c37188bc3ca 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc @@ -156,7 +156,7 @@ void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph, const char *label, const char *output_filename) { - if (depsgraph == NULL) { + if (depsgraph == nullptr) { return; } DEG::DebugContext ctx; diff --git a/source/blender/depsgraph/intern/debug/deg_time_average.h b/source/blender/depsgraph/intern/debug/deg_time_average.h new file mode 100644 index 00000000000..9794e9a88c3 --- /dev/null +++ b/source/blender/depsgraph/intern/debug/deg_time_average.h @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +namespace DEG { + +// Utility class which takes care of calculating average of time series, such as +// FPS counters. +template<int MaxSamples> class AveragedTimeSampler { + public: + AveragedTimeSampler() : num_samples_(0), next_sample_index_(0) + { + } + + void add_sample(double value) + { + samples_[next_sample_index_] = value; + + // Move to the next index, keeping wrapping at the end of array into account. + ++next_sample_index_; + if (next_sample_index_ == MaxSamples) { + next_sample_index_ = 0; + } + + // Update number of stored samples. + if (num_samples_ != MaxSamples) { + ++num_samples_; + } + } + + double get_averaged() const + { + double sum = 0.0; + for (int i = 0; i < num_samples_; ++i) { + sum += samples_[i]; + } + return sum / num_samples_; + } + + protected: + double samples_[MaxSamples]; + + // Number of samples which are actually stored in the array. + int num_samples_; + + // Index in the samples_ array under which next sample will be stored. + int next_sample_index_; +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 292c3b361d8..ce6797939b5 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -46,6 +46,7 @@ extern "C" { #include "intern/depsgraph_update.h" #include "intern/depsgraph_physics.h" +#include "intern/depsgraph_relation.h" #include "intern/depsgraph_registry.h" #include "intern/eval/deg_eval_copy_on_write.h" @@ -66,7 +67,7 @@ template<typename T> static void remove_from_vector(vector<T> *vector, const T & } Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) - : time_source(NULL), + : time_source(nullptr), need_update(true), need_update_time(false), bmain(bmain), @@ -74,7 +75,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati view_layer(view_layer), mode(mode), ctime(BKE_scene_frame_get(scene)), - scene_cow(NULL), + scene_cow(nullptr), is_active(false), is_evaluating(false), is_render_pipeline_depsgraph(false) @@ -82,7 +83,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati BLI_spin_init(&lock); id_hash = BLI_ghash_ptr_new("Depsgraph id hash"); entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags"); - debug_flags = G.debug; memset(id_type_updated, 0, sizeof(id_type_updated)); memset(id_type_exist, 0, sizeof(id_type_exist)); memset(physics_relations, 0, sizeof(physics_relations)); @@ -91,9 +91,9 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati Depsgraph::~Depsgraph() { clear_id_nodes(); - BLI_ghash_free(id_hash, NULL, NULL); - BLI_gset_free(entry_tags, NULL); - if (time_source != NULL) { + BLI_ghash_free(id_hash, nullptr, nullptr); + BLI_gset_free(entry_tags, nullptr); + if (time_source != nullptr) { OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); } BLI_spin_end(&lock); @@ -103,9 +103,9 @@ Depsgraph::~Depsgraph() TimeSourceNode *Depsgraph::add_time_source() { - if (time_source == NULL) { + if (time_source == nullptr) { DepsNodeFactory *factory = type_get_factory(NodeType::TIMESOURCE); - time_source = (TimeSourceNode *)factory->create_node(NULL, "", "Time Source"); + time_source = (TimeSourceNode *)factory->create_node(nullptr, "", "Time Source"); } return time_source; } @@ -143,7 +143,7 @@ IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint) void Depsgraph::clear_id_nodes_conditional(const std::function<bool(ID_Type id_type)> &filter) { for (IDNode *id_node : id_nodes) { - if (id_node->id_cow == NULL) { + if (id_node->id_cow == nullptr) { /* This means builder "stole" ownership of the copy-on-written * datablock for her own dirty needs. */ continue; @@ -170,7 +170,7 @@ void Depsgraph::clear_id_nodes() OBJECT_GUARDED_DELETE(id_node, IDNode); } /* Clear containers. */ - BLI_ghash_clear(id_hash, NULL, NULL); + BLI_ghash_clear(id_hash, nullptr, nullptr); id_nodes.clear(); /* Clear physics relation caches. */ clear_physics_relations(this); @@ -179,11 +179,11 @@ void Depsgraph::clear_id_nodes() /* Add new relation between two nodes */ Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags) { - Relation *rel = NULL; + Relation *rel = nullptr; if (flags & RELATION_CHECK_BEFORE_ADD) { rel = check_nodes_connected(from, to, description); } - if (rel != NULL) { + if (rel != nullptr) { rel->flag |= flags; return rel; } @@ -212,49 +212,12 @@ Relation *Depsgraph::check_nodes_connected(const Node *from, if (rel->to != to) { continue; } - if (description != NULL && !STREQ(rel->name, description)) { + if (description != nullptr && !STREQ(rel->name, description)) { continue; } return rel; } - return NULL; -} - -/* ************************ */ -/* Relationships Management */ - -Relation::Relation(Node *from, Node *to, const char *description) - : from(from), to(to), name(description), flag(0) -{ - /* Hook it up to the nodes which use it. - * - * NOTE: We register relation in the nodes which this link connects to here - * in constructor but we don't unregister it in the destructor. - * - * Reasoning: - * - * - Destructor is currently used on global graph destruction, so there's no - * real need in avoiding dangling pointers, all the memory is to be freed - * anyway. - * - * - Unregistering relation is not a cheap operation, so better to have it - * as an explicit call if we need this. */ - from->outlinks.push_back(this); - to->inlinks.push_back(this); -} - -Relation::~Relation() -{ - /* Sanity check. */ - BLI_assert(from != NULL && to != NULL); -} - -void Relation::unlink() -{ - /* Sanity check. */ - BLI_assert(from != NULL && to != NULL); - remove_from_vector(&from->outlinks, this); - remove_from_vector(&to->inlinks, this); + return nullptr; } /* Low level tagging -------------------------------------- */ @@ -263,7 +226,7 @@ void Relation::unlink() void Depsgraph::add_entry_tag(OperationNode *node) { /* Sanity check. */ - if (node == NULL) { + if (node == nullptr) { return; } /* Add to graph-level set of directly modified nodes to start searching @@ -276,16 +239,16 @@ void Depsgraph::add_entry_tag(OperationNode *node) void Depsgraph::clear_all_nodes() { clear_id_nodes(); - if (time_source != NULL) { + if (time_source != nullptr) { OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); - time_source = NULL; + time_source = nullptr; } } ID *Depsgraph::get_cow_id(const ID *id_orig) const { IDNode *id_node = find_id_node(id_orig); - if (id_node == NULL) { + if (id_node == nullptr) { /* This function is used from places where we expect ID to be either * already a copy-on-write version or have a corresponding copy-on-write * version. @@ -325,7 +288,7 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval /* Free graph's contents and graph itself */ void DEG_graph_free(Depsgraph *graph) { - if (graph == NULL) { + if (graph == nullptr) { return; } using DEG::Depsgraph; @@ -342,10 +305,10 @@ bool DEG_is_evaluating(struct Depsgraph *depsgraph) bool DEG_is_active(const struct Depsgraph *depsgraph) { - if (depsgraph == NULL) { + if (depsgraph == nullptr) { /* Happens for such cases as work object in what_does_obaction(), * and sine render pipeline parts. Shouldn't really be accepting - * NULL depsgraph, but is quite hard to get proper one in those + * nullptr depsgraph, but is quite hard to get proper one in those * cases. */ return false; } diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 43829f4e045..7801f95e008 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -40,6 +40,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_physics.h" +#include "intern/debug/deg_debug.h" #include "intern/depsgraph_type.h" struct GHash; @@ -53,47 +54,9 @@ namespace DEG { struct IDNode; struct Node; struct OperationNode; +struct Relation; struct TimeSourceNode; -/* *************************** */ -/* Relationships Between Nodes */ - -/* Settings/Tags on Relationship. - * NOTE: Is a bitmask, allowing accumulation. */ -enum RelationFlag { - /* "cyclic" link - when detecting cycles, this relationship was the one - * which triggers a cyclic relationship to exist in the graph. */ - RELATION_FLAG_CYCLIC = (1 << 0), - /* Update flush will not go through this relation. */ - RELATION_FLAG_NO_FLUSH = (1 << 1), - /* Only flush along the relation is update comes from a node which was - * affected by user input. */ - RELATION_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2), - /* The relation can not be killed by the cyclic dependencies solver. */ - RELATION_FLAG_GODMODE = (1 << 4), - /* Relation will check existence before being added. */ - RELATION_CHECK_BEFORE_ADD = (1 << 5), -}; - -/* B depends on A (A -> B) */ -struct Relation { - Relation(Node *from, Node *to, const char *description); - ~Relation(); - - void unlink(); - - /* the nodes in the relationship (since this is shared between the nodes) */ - Node *from; /* A */ - Node *to; /* B */ - - /* relationship attributes */ - const char *name; /* label for debugging */ - int flag; /* Bitmask of RelationFlag) */ -}; - -/* ********* */ -/* Depsgraph */ - /* Dependency Graph object */ struct Depsgraph { // TODO(sergey): Go away from C++ container and use some native BLI. @@ -107,7 +70,7 @@ struct Depsgraph { TimeSourceNode *find_time_source() const; IDNode *find_id_node(const ID *id) const; - IDNode *add_id_node(ID *id, ID *id_cow_hint = NULL); + IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr); void clear_id_nodes(); void clear_id_nodes_conditional(const std::function<bool(ID_Type id_type)> &filter); @@ -115,7 +78,7 @@ struct Depsgraph { Relation *add_new_relation(Node *from, Node *to, const char *description, int flags = 0); /* Check whether two nodes are connected by relation with given - * description. Description might be NULL to check ANY relation between + * description. Description might be nullptr to check ANY relation between * given nodes. */ Relation *check_nodes_connected(const Node *from, const Node *to, const char *description); @@ -194,9 +157,7 @@ struct Depsgraph { * to read stuff from. */ bool is_active; - /* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */ - int debug_flags; - string debug_name; + DepsgraphDebug debug; bool is_evaluating; diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 0acf777e2f0..a570e042c26 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -59,6 +59,7 @@ extern "C" { #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" +#include "intern/depsgraph_relation.h" #include "intern/depsgraph_registry.h" #include "intern/depsgraph_type.h" @@ -143,7 +144,7 @@ void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle, ID *id = DEG_get_id_from_handle(node_handle); DEG::ComponentKey point_cache_key(id, DEG::NodeType::POINT_CACHE); DEG::Relation *rel = relation_builder->add_relation(comp_key, point_cache_key, "Point Cache"); - if (rel != NULL) { + if (rel != nullptr) { rel->flag |= DEG::RELATION_FLAG_FLUSH_USER_EDIT_ONLY; } else { @@ -376,7 +377,7 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder { virtual void build_object_proxy_group(Object *object, bool is_visible) override { - if (object->proxy_group == NULL) { + if (object->proxy_group == nullptr) { return; } if (!filter_.contains(&object->proxy_group->id)) { @@ -407,7 +408,7 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder { virtual void build_object_proxy_group(Object *object) override { - if (object->proxy_group == NULL) { + if (object->proxy_group == nullptr) { return; } if (!filter_.contains(&object->proxy_group->id)) { @@ -478,7 +479,7 @@ void DEG_graph_tag_relations_update(Depsgraph *graph) * TODO(sergey): Try to make it so we don't flush updates * to the whole depsgraph. */ DEG::IDNode *id_node = deg_graph->find_id_node(°_graph->scene->id); - if (id_node != NULL) { + if (id_node != nullptr) { id_node->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_RELATIONS); } } diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index bb60db5209c..25f7e9117d1 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -38,6 +38,7 @@ extern "C" { #include "DEG_depsgraph_query.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" #include "intern/depsgraph_type.h" #include "intern/debug/deg_debug.h" #include "intern/node/deg_node_component.h" @@ -47,31 +48,31 @@ extern "C" { void DEG_debug_flags_set(Depsgraph *depsgraph, int flags) { DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); - deg_graph->debug_flags = flags; + deg_graph->debug.flags = flags; } int DEG_debug_flags_get(const Depsgraph *depsgraph) { const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); - return deg_graph->debug_flags; + return deg_graph->debug.flags; } void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name) { DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); - deg_graph->debug_name = name; + deg_graph->debug.name = name; } const char *DEG_debug_name_get(struct Depsgraph *depsgraph) { const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph); - return deg_graph->debug_name.c_str(); + return deg_graph->debug.name.c_str(); } bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2) { - BLI_assert(graph1 != NULL); - BLI_assert(graph2 != NULL); + BLI_assert(graph1 != nullptr); + BLI_assert(graph2 != nullptr); const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1); const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2); if (deg_graph1->operations.size() != deg_graph2->operations.size()) { @@ -233,7 +234,7 @@ void DEG_stats_simple(const Depsgraph *graph, } DEG::TimeSourceNode *time_source = deg_graph->find_time_source(); - if (time_source != NULL) { + if (time_source != nullptr) { tot_rels += time_source->inlinks.size(); } diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc index f47081cd54e..cabb95fe732 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.cc +++ b/source/blender/depsgraph/intern/depsgraph_physics.cc @@ -67,8 +67,8 @@ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collection) { const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); - if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == NULL) { - return NULL; + if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == nullptr) { + return nullptr; } ID *collection_orig = DEG_get_original_id(&collection->id); @@ -82,8 +82,8 @@ ListBase *DEG_get_collision_relations(const Depsgraph *graph, { const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); - if (deg_graph->physics_relations[type] == NULL) { - return NULL; + if (deg_graph->physics_relations[type] == nullptr) { + return nullptr; } ID *collection_orig = DEG_get_original_id(&collection->id); return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[type], collection_orig); @@ -106,7 +106,7 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, if (ob1 == object) { continue; } - if (filter_function == NULL || + if (filter_function == nullptr || filter_function(ob1, modifiers_findByType(ob1, (ModifierType)modifier_type))) { DEG_add_object_pointcache_relation(handle, ob1, DEG_OB_COMP_TRANSFORM, name); DEG_add_object_pointcache_relation(handle, ob1, DEG_OB_COMP_GEOMETRY, name); @@ -144,7 +144,7 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, } /* Smoke flow relations. */ - if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source != NULL) { + if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source != nullptr) { DEG_add_object_pointcache_relation( handle, relation->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain"); DEG_add_object_pointcache_relation( @@ -154,7 +154,7 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, /* Absorption forces need collision relation. */ if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { DEG_add_collision_relations( - handle, object, NULL, eModifierType_Collision, NULL, "Force Absorption"); + handle, object, nullptr, eModifierType_Collision, nullptr, "Force Absorption"); } } } @@ -166,13 +166,13 @@ namespace DEG { ListBase *build_effector_relations(Depsgraph *graph, Collection *collection) { GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; - if (hash == NULL) { + if (hash == nullptr) { graph->physics_relations[DEG_PHYSICS_EFFECTOR] = BLI_ghash_ptr_new( "Depsgraph physics relations hash"); hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; } ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection)); - if (relations == NULL) { + if (relations == nullptr) { ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph); relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection); BLI_ghash_insert(hash, &collection->id, relations); @@ -186,12 +186,12 @@ ListBase *build_collision_relations(Depsgraph *graph, { const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); GHash *hash = graph->physics_relations[type]; - if (hash == NULL) { + if (hash == nullptr) { graph->physics_relations[type] = BLI_ghash_ptr_new("Depsgraph physics relations hash"); hash = graph->physics_relations[type]; } ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection)); - if (relations == NULL) { + if (relations == nullptr) { ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph); relations = BKE_collision_relations_create(depsgraph, collection, modifier_type); BLI_ghash_insert(hash, &collection->id, relations); @@ -221,17 +221,17 @@ void clear_physics_relations(Depsgraph *graph) switch (type) { case DEG_PHYSICS_EFFECTOR: - BLI_ghash_free(graph->physics_relations[i], NULL, free_effector_relations); + BLI_ghash_free(graph->physics_relations[i], nullptr, free_effector_relations); break; case DEG_PHYSICS_COLLISION: case DEG_PHYSICS_SMOKE_COLLISION: case DEG_PHYSICS_DYNAMIC_BRUSH: - BLI_ghash_free(graph->physics_relations[i], NULL, free_collision_relations); + BLI_ghash_free(graph->physics_relations[i], nullptr, free_collision_relations); break; case DEG_PHYSICS_RELATIONS_NUM: break; } - graph->physics_relations[i] = NULL; + graph->physics_relations[i] = nullptr; } } } diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 3b0f49e0150..4205f79b9c0 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -103,7 +103,7 @@ bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type) uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id) { - if (graph == NULL) { + if (graph == nullptr) { /* Happens when converting objects to mesh from a python script * after modifying scene graph. * @@ -114,7 +114,7 @@ uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id) const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id)); - if (id_node == NULL) { + if (id_node == nullptr) { /* TODO(sergey): Does it mean we need to check set scene? */ return 0; } @@ -126,7 +126,7 @@ void DEG_get_customdata_mask_for_object(const Depsgraph *graph, Object *ob, CustomData_MeshMasks *r_mask) { - if (graph == NULL) { + if (graph == nullptr) { /* Happens when converting objects to mesh from a python script * after modifying scene graph. * @@ -137,7 +137,7 @@ void DEG_get_customdata_mask_for_object(const Depsgraph *graph, const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(&ob->id)); - if (id_node == NULL) { + if (id_node == nullptr) { /* TODO(sergey): Does it mean we need to check set scene? */ return; } @@ -155,7 +155,7 @@ Scene *DEG_get_evaluated_scene(const Depsgraph *graph) Scene *scene_cow = deg_graph->scene_cow; /* TODO(sergey): Shall we expand data-block here? Or is it OK to assume * that caller is OK with just a pointer in case scene is not updated yet? */ - BLI_assert(scene_cow != NULL && DEG::deg_copy_on_write_is_expanded(&scene_cow->id)); + BLI_assert(scene_cow != nullptr && DEG::deg_copy_on_write_is_expanded(&scene_cow->id)); return scene_cow; } @@ -163,15 +163,15 @@ ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph) { const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); Scene *scene_cow = DEG_get_evaluated_scene(graph); - if (scene_cow == NULL) { - return NULL; /* Happens with new, not-yet-built/evaluated graphes. */ + if (scene_cow == nullptr) { + return nullptr; /* Happens with new, not-yet-built/evaluated graphes. */ } /* Do name-based lookup. */ /* TODO(sergey): Can this be optimized? */ ViewLayer *view_layer_orig = deg_graph->view_layer; ViewLayer *view_layer_cow = (ViewLayer *)BLI_findstring( &scene_cow->view_layers, view_layer_orig->name, offsetof(ViewLayer, name)); - BLI_assert(view_layer_cow != NULL); + BLI_assert(view_layer_cow != nullptr); return view_layer_cow; } @@ -182,15 +182,15 @@ Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object) ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id) { - if (id == NULL) { - return NULL; + if (id == nullptr) { + return nullptr; } /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(), * but here we never do assert, since we don't know nature of the * incoming ID data-block. */ const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph; const DEG::IDNode *id_node = deg_graph->find_id_node(id); - if (id_node == NULL) { + if (id_node == nullptr) { return id; } return id_node->id_cow; @@ -201,7 +201,7 @@ void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph, PointerRNA *ptr, PointerRNA *r_ptr_eval) { - if ((ptr == NULL) || (r_ptr_eval == NULL)) { + if ((ptr == nullptr) || (r_ptr_eval == nullptr)) { return; } ID *orig_id = ptr->owner_id; @@ -233,7 +233,7 @@ void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph, if (path) { PointerRNA cow_id_ptr; RNA_id_pointer_create(cow_id, &cow_id_ptr); - if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, NULL)) { + if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, nullptr)) { /* Couldn't find COW copy of data */ fprintf(stderr, "%s: Couldn't resolve RNA path ('%s') relative to COW ID (%p) for '%s'\n", @@ -261,10 +261,10 @@ Object *DEG_get_original_object(Object *object) ID *DEG_get_original_id(ID *id) { - if (id == NULL) { - return NULL; + if (id == nullptr) { + return nullptr; } - if (id->orig_id == NULL) { + if (id->orig_id == nullptr) { return id; } BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0); diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index b7a40fb69bd..0a28e379ef5 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -40,6 +40,7 @@ extern "C" { #include "DEG_depsgraph_query.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_id.h" @@ -87,7 +88,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph, { /* Start with getting ID node from the graph. */ IDNode *target_id_node = graph->find_id_node(id); - if (target_id_node == NULL) { + if (target_id_node == nullptr) { /* TODO(sergey): Shall we inform or assert here about attempt to start * iterating over non-existing ID? */ return; @@ -210,7 +211,7 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph, { /* Start with getting ID node from the graph. */ IDNode *target_id_node = graph->find_id_node(id); - if (target_id_node == NULL) { + if (target_id_node == nullptr) { /* TODO(sergey): Shall we inform or assert here about attempt to start * iterating over non-existing ID? */ return; diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index db469612f76..90ab7565f4a 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -67,7 +67,7 @@ namespace { void deg_invalidate_iterator_work_data(DEGObjectIterData *data) { #ifdef INVALIDATE_WORK_DATA - BLI_assert(data != NULL); + BLI_assert(data != nullptr); memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); #else (void)data; @@ -76,14 +76,14 @@ void deg_invalidate_iterator_work_data(DEGObjectIterData *data) void verify_id_properties_freed(DEGObjectIterData *data) { - if (data->dupli_object_current == NULL) { + if (data->dupli_object_current == nullptr) { // We didn't enter duplication yet, so we can't have any dangling // pointers. return; } const Object *dupli_object = data->dupli_object_current->ob; Object *temp_dupli_object = &data->temp_dupli_object; - if (temp_dupli_object->id.properties == NULL) { + if (temp_dupli_object->id.properties == nullptr) { // No ID properties in temp datablock -- no leak is possible. return; } @@ -94,7 +94,7 @@ void verify_id_properties_freed(DEGObjectIterData *data) // Free memory which is owned by temporary storage which is about to // get overwritten. IDP_FreeProperty(temp_dupli_object->id.properties); - temp_dupli_object->id.properties = NULL; + temp_dupli_object->id.properties = nullptr; } static bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject *dob) @@ -120,7 +120,7 @@ static bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, Dupl bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - while (data->dupli_object_next != NULL) { + while (data->dupli_object_next != nullptr) { DupliObject *dob = data->dupli_object_next; Object *obd = dob->ob; @@ -215,7 +215,7 @@ void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node) if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) { ob_visibility = BKE_object_visibility(object, data->eval_mode); - if (deg_object_hide_original(data->eval_mode, object, NULL)) { + if (deg_object_hide_original(data->eval_mode, object, nullptr)) { return; } } @@ -249,10 +249,10 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) return; } - data->dupli_parent = NULL; - data->dupli_list = NULL; - data->dupli_object_next = NULL; - data->dupli_object_current = NULL; + data->dupli_parent = nullptr; + data->dupli_list = nullptr; + data->dupli_object_next = nullptr; + data->dupli_object_current = nullptr; data->scene = DEG_get_evaluated_scene(depsgraph); data->id_node_index = 0; data->num_id_nodes = num_id_nodes; @@ -281,10 +281,10 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) else { verify_id_properties_freed(data); free_object_duplilist(data->dupli_list); - data->dupli_parent = NULL; - data->dupli_list = NULL; - data->dupli_object_next = NULL; - data->dupli_object_current = NULL; + data->dupli_parent = nullptr; + data->dupli_list = nullptr; + data->dupli_object_next = nullptr; + data->dupli_object_current = nullptr; deg_invalidate_iterator_work_data(data); } } @@ -303,7 +303,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) void DEG_iterator_objects_end(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - if (data != NULL) { + if (data != nullptr) { /* Force crash in case the iterator data is referenced and accessed down * the line. (T51718) */ deg_invalidate_iterator_work_data(data); diff --git a/source/blender/depsgraph/intern/depsgraph_relation.cc b/source/blender/depsgraph/intern/depsgraph_relation.cc new file mode 100644 index 00000000000..1b2de2cc807 --- /dev/null +++ b/source/blender/depsgraph/intern/depsgraph_relation.cc @@ -0,0 +1,73 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/depsgraph_relation.h" /* own include */ + +#include "BLI_utildefines.h" + +#include "intern/depsgraph_type.h" +#include "intern/node/deg_node.h" + +namespace DEG { + +/* TODO(sergey): Find a better place for this. */ +template<typename T> static void remove_from_vector(vector<T> *vector, const T &value) +{ + vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end()); +} + +Relation::Relation(Node *from, Node *to, const char *description) + : from(from), to(to), name(description), flag(0) +{ + /* Hook it up to the nodes which use it. + * + * NOTE: We register relation in the nodes which this link connects to here + * in constructor but we don't unregister it in the destructor. + * + * Reasoning: + * + * - Destructor is currently used on global graph destruction, so there's no + * real need in avoiding dangling pointers, all the memory is to be freed + * anyway. + * + * - Unregistering relation is not a cheap operation, so better to have it + * as an explicit call if we need this. */ + from->outlinks.push_back(this); + to->inlinks.push_back(this); +} + +Relation::~Relation() +{ + /* Sanity check. */ + BLI_assert(from != nullptr && to != nullptr); +} + +void Relation::unlink() +{ + /* Sanity check. */ + BLI_assert(from != nullptr && to != nullptr); + remove_from_vector(&from->outlinks, this); + remove_from_vector(&to->inlinks, this); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_relation.h b/source/blender/depsgraph/intern/depsgraph_relation.h new file mode 100644 index 00000000000..2f9f0249b1f --- /dev/null +++ b/source/blender/depsgraph/intern/depsgraph_relation.h @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +namespace DEG { + +struct Node; + +/* Settings/Tags on Relationship. + * NOTE: Is a bitmask, allowing accumulation. */ +enum RelationFlag { + /* "cyclic" link - when detecting cycles, this relationship was the one + * which triggers a cyclic relationship to exist in the graph. */ + RELATION_FLAG_CYCLIC = (1 << 0), + /* Update flush will not go through this relation. */ + RELATION_FLAG_NO_FLUSH = (1 << 1), + /* Only flush along the relation is update comes from a node which was + * affected by user input. */ + RELATION_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2), + /* The relation can not be killed by the cyclic dependencies solver. */ + RELATION_FLAG_GODMODE = (1 << 4), + /* Relation will check existence before being added. */ + RELATION_CHECK_BEFORE_ADD = (1 << 5), +}; + +/* B depends on A (A -> B) */ +struct Relation { + Relation(Node *from, Node *to, const char *description); + ~Relation(); + + void unlink(); + + /* the nodes in the relationship (since this is shared between the nodes) */ + Node *from; /* A */ + Node *to; /* B */ + + /* relationship attributes */ + const char *name; /* label for debugging */ + int flag; /* Bitmask of RelationFlag) */ +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index ce5917110d6..b019c079dab 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -246,7 +246,7 @@ void id_tag_update_ntree_special( Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) { bNodeTree *ntree = ntreeFromID(id); - if (ntree == NULL) { + if (ntree == nullptr) { return; } graph_id_tag_update(bmain, graph, &ntree->id, flag, update_source); @@ -257,7 +257,7 @@ void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) /* NOTE: We handle this immediately, without delaying anything, to be * sure we don't cause threading issues with OpenGL. */ /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ - DEGEditorUpdateContext update_ctx = {NULL}; + DEGEditorUpdateContext update_ctx = {nullptr}; update_ctx.bmain = bmain; update_ctx.depsgraph = (::Depsgraph *)graph; update_ctx.scene = graph->scene; @@ -281,7 +281,7 @@ void depsgraph_tag_component(Depsgraph *graph, /* NOTE: Animation component might not be existing yet (which happens when adding new driver or * adding a new keyframe), so the required copy-on-write tag needs to be taken care explicitly * here. */ - if (component_node == NULL) { + if (component_node == nullptr) { if (component_type == NodeType::ANIMATION) { depsgraph_id_tag_copy_on_write(graph, id_node, update_source); } @@ -292,7 +292,7 @@ void depsgraph_tag_component(Depsgraph *graph, } else { OperationNode *operation_node = component_node->find_operation(operation_code); - if (operation_node != NULL) { + if (operation_node != nullptr) { operation_node->tag_update(graph, update_source); } } @@ -315,7 +315,7 @@ void deg_graph_id_tag_legacy_compat( case ID_OB: { Object *object = (Object *)id; ID *data_id = (ID *)object->data; - if (data_id != NULL) { + if (data_id != nullptr) { graph_id_tag_update(bmain, depsgraph, data_id, 0, update_source); } break; @@ -325,9 +325,9 @@ void deg_graph_id_tag_legacy_compat( * tagging here. */ case ID_ME: { Mesh *mesh = (Mesh *)id; - if (mesh->key != NULL) { + if (mesh->key != nullptr) { ID *key_id = &mesh->key->id; - if (key_id != NULL) { + if (key_id != nullptr) { graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source); } } @@ -335,9 +335,9 @@ void deg_graph_id_tag_legacy_compat( } case ID_LT: { Lattice *lattice = (Lattice *)id; - if (lattice->key != NULL) { + if (lattice->key != nullptr) { ID *key_id = &lattice->key->id; - if (key_id != NULL) { + if (key_id != nullptr) { graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source); } } @@ -345,9 +345,9 @@ void deg_graph_id_tag_legacy_compat( } case ID_CU: { Curve *curve = (Curve *)id; - if (curve->key != NULL) { + if (curve->key != nullptr) { ID *key_id = &curve->key->id; - if (key_id != NULL) { + if (key_id != nullptr) { graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source); } } @@ -367,13 +367,13 @@ static void graph_id_tag_update_single_flag(Main *bmain, eUpdateSource update_source) { if (tag == ID_RECALC_EDITORS) { - if (graph != NULL && graph->is_active) { + if (graph != nullptr && graph->is_active) { depsgraph_update_editors_tag(bmain, graph, id); } return; } else if (tag == ID_RECALC_TIME) { - if (graph != NULL) { + if (graph != nullptr) { graph->need_update_time = true; } return; @@ -389,14 +389,14 @@ static void graph_id_tag_update_single_flag(Main *bmain, return; } /* Some sanity checks before moving forward. */ - if (id_node == NULL) { + if (id_node == nullptr) { /* Happens when object is tagged for update and not yet in the * dependency graph (but will be after relations update). */ return; } /* Tag ID recalc flag. */ DepsNodeFactory *factory = type_get_factory(component_type); - BLI_assert(factory != NULL); + BLI_assert(factory != nullptr); id_node->id_cow->recalc |= factory->id_recalc_tag(); /* Tag corresponding dependency graph operation for update. */ if (component_type == NodeType::ID_REF) { @@ -413,7 +413,7 @@ static void graph_id_tag_update_single_flag(Main *bmain, string stringify_append_bit(const string &str, IDRecalcFlag tag) { const char *tag_name = DEG_update_tag_as_string(tag); - if (tag_name == NULL) { + if (tag_name == nullptr) { return str; } string result = str; @@ -468,7 +468,7 @@ int deg_recalc_flags_for_legacy_zero() int deg_recalc_flags_effective(Depsgraph *graph, int flags) { - if (graph != NULL) { + if (graph != nullptr) { if (!graph->is_active) { return 0; } @@ -489,7 +489,7 @@ void deg_graph_node_tag_zero(Main *bmain, IDNode *id_node, eUpdateSource update_source) { - if (id_node == NULL) { + if (id_node == nullptr) { return; } ID *id = id_node->id_orig; @@ -514,7 +514,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti const ID_Type id_type = GS(id_node->id_orig->name); if (id_type == ID_OB) { Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig); - if (object_orig->proxy != NULL) { + if (object_orig->proxy != nullptr) { object_orig->proxy->proxy_from = object_orig; } } @@ -528,7 +528,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti if (!DEG::deg_copy_on_write_is_expanded(id_node->id_cow)) { flag |= ID_RECALC_COPY_ON_WRITE; if (do_time) { - if (BKE_animdata_from_id(id_node->id_orig) != NULL) { + if (BKE_animdata_from_id(id_node->id_orig) != nullptr) { flag |= ID_RECALC_ANIMATION; } } @@ -612,7 +612,7 @@ NodeType geometry_tag_to_component(const ID *id) void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) { - graph_id_tag_update(bmain, NULL, id, flag, update_source); + graph_id_tag_update(bmain, nullptr, id, flag, update_source); for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { graph_id_tag_update(bmain, depsgraph, id, flag, update_source); } @@ -621,8 +621,8 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) void graph_id_tag_update( Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) { - const int debug_flags = (graph != NULL) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug; - if (graph != NULL && graph->is_evaluating) { + const int debug_flags = (graph != nullptr) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug; + if (graph != nullptr && graph->is_evaluating) { if (debug_flags & G_DEBUG_DEPSGRAPH) { printf("ID tagged for update during dependency graph evaluation."); } @@ -635,8 +635,8 @@ void graph_id_tag_update( stringify_update_bitfield(flag).c_str(), update_source_as_string(update_source)); } - IDNode *id_node = (graph != NULL) ? graph->find_id_node(id) : NULL; - if (graph != NULL) { + IDNode *id_node = (graph != nullptr) ? graph->find_id_node(id) : nullptr; + if (graph != nullptr) { DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(graph), GS(id->name)); } if (flag == 0) { @@ -644,7 +644,7 @@ void graph_id_tag_update( } /* Store original flag in the ID. * Allows to have more granularity than a node-factory based flags. */ - if (id_node != NULL) { + if (id_node != nullptr) { id_node->id_cow->recalc |= flag; } /* When ID is tagged for update based on an user edits store the recalc flags in the original ID. @@ -730,7 +730,7 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) case ID_RECALC_ALL: return "ALL"; } - return NULL; + return nullptr; } /* Data-Based Tagging */ @@ -743,7 +743,7 @@ void DEG_id_tag_update(ID *id, int flag) void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag) { - if (id == NULL) { + if (id == nullptr) { /* Ideally should not happen, but old depsgraph allowed this. */ return; } @@ -804,7 +804,7 @@ void DEG_ids_check_recalc( { bool updated = time || DEG_id_type_any_updated(depsgraph); - DEGEditorUpdateContext update_ctx = {NULL}; + DEGEditorUpdateContext update_ctx = {nullptr}; update_ctx.bmain = bmain; update_ctx.depsgraph = depsgraph; update_ctx.scene = scene; diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc index ed4ec592fc7..d10bfaaace8 100644 --- a/source/blender/depsgraph/intern/depsgraph_update.cc +++ b/source/blender/depsgraph/intern/depsgraph_update.cc @@ -29,19 +29,19 @@ namespace DEG { -static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL; -static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; +static DEG_EditorUpdateIDCb deg_editor_update_id_cb = nullptr; +static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = nullptr; void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id) { - if (deg_editor_update_id_cb != NULL) { + if (deg_editor_update_id_cb != nullptr) { deg_editor_update_id_cb(update_ctx, id); } } void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated) { - if (deg_editor_update_scene_cb != NULL) { + if (deg_editor_update_scene_cb != nullptr) { deg_editor_update_scene_cb(update_ctx, updated); } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index ff30bf7571a..df61a1416bd 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -52,6 +52,7 @@ #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" namespace DEG { @@ -86,7 +87,7 @@ enum class EvaluationStage { /* Workaround for areas which can not be evaluated in threads. * - * For example, metaballs, which are iterating over all bases and are requesting duplilists + * For example, metaballs, which are iterating over all bases and are requesting dupli-lists * to see whether there are metaballs inside. */ SINGLE_THREADED_WORKAROUND, }; @@ -364,14 +365,15 @@ void deg_evaluate_on_refresh(Depsgraph *graph) if (BLI_gset_len(graph->entry_tags) == 0) { return; } - const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); - const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0; + + graph->debug.begin_graph_evaluation(); + graph->is_evaluating = true; depsgraph_ensure_view_layer(graph); /* Set up evaluation state. */ DepsgraphEvalState state; state.graph = graph; - state.do_stats = do_time_debug; + state.do_stats = graph->debug.do_time_debug(); state.need_single_thread_pass = false; /* Set up task scheduler and pull for threaded evaluation. */ TaskScheduler *task_scheduler; @@ -418,9 +420,8 @@ void deg_evaluate_on_refresh(Depsgraph *graph) BLI_task_scheduler_free(task_scheduler); } graph->is_evaluating = false; - if (do_time_debug) { - printf("Depsgraph updated in %f seconds.\n", PIL_check_seconds_timer() - start_time); - } + + graph->debug.end_graph_evaluation(); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index a1bb0aab029..b74e5715e14 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -120,13 +120,13 @@ union NestedIDHackTempStorage { World world; }; -/* Set nested owned ID pointers to NULL. */ +/* Set nested owned ID pointers to nullptr. */ void nested_id_hack_discard_pointers(ID *id_cow) { switch (GS(id_cow->name)) { # define SPECIAL_CASE(id_type, dna_type, field) \ case id_type: { \ - ((dna_type *)id_cow)->field = NULL; \ + ((dna_type *)id_cow)->field = nullptr; \ break; \ } @@ -144,9 +144,9 @@ void nested_id_hack_discard_pointers(ID *id_cow) Scene *scene_cow = (Scene *)id_cow; /* Node trees always have their own ID node in the graph, and are * being copied as part of their copy-on-write process. */ - scene_cow->nodetree = NULL; + scene_cow->nodetree = nullptr; /* Tool settings pointer is shared with the original scene. */ - scene_cow->toolsettings = NULL; + scene_cow->toolsettings = nullptr; break; } @@ -154,7 +154,7 @@ void nested_id_hack_discard_pointers(ID *id_cow) /* Clear the ParticleSettings pointer to prevent doubly-freeing it. */ Object *ob = (Object *)id_cow; LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { - psys->part = NULL; + psys->part = nullptr; } break; } @@ -165,7 +165,7 @@ void nested_id_hack_discard_pointers(ID *id_cow) } } -/* Set ID pointer of nested owned IDs (nodetree, key) to NULL. +/* Set ID pointer of nested owned IDs (nodetree, key) to nullptr. * * Return pointer to a new ID to be used. */ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage, const ID *id) @@ -174,7 +174,7 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage # define SPECIAL_CASE(id_type, dna_type, field, variable) \ case id_type: { \ storage->variable = *(dna_type *)id; \ - storage->variable.field = NULL; \ + storage->variable.field = nullptr; \ return &storage->variable.id; \ } @@ -190,8 +190,8 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage case ID_SCE: { storage->scene = *(Scene *)id; - storage->scene.toolsettings = NULL; - storage->scene.nodetree = NULL; + storage->scene.toolsettings = nullptr; + storage->scene.nodetree = nullptr; return &storage->scene.id; } @@ -206,7 +206,7 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage /* Set ID pointer of nested owned IDs (nodetree, key) to the original value. */ void nested_id_hack_restore_pointers(const ID *old_id, ID *new_id) { - if (new_id == NULL) { + if (new_id == nullptr) { return; } switch (GS(old_id->name)) { @@ -240,9 +240,9 @@ void ntree_hack_remap_pointers(const Depsgraph *depsgraph, ID *id_cow) # define SPECIAL_CASE(id_type, dna_type, field, field_type) \ case id_type: { \ dna_type *data = (dna_type *)id_cow; \ - if (data->field != NULL) { \ + if (data->field != nullptr) { \ ID *ntree_id_cow = depsgraph->get_cow_id(&data->field->id); \ - if (ntree_id_cow != NULL) { \ + if (ntree_id_cow != nullptr) { \ DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n", \ data->field->id.name, \ data->field, \ @@ -287,7 +287,7 @@ bool id_copy_inplace_no_main(const ID *id, ID *newid) #endif bool result = BKE_id_copy_ex( - NULL, (ID *)id_for_copy, &newid, (LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE)); + nullptr, (ID *)id_for_copy, &newid, (LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE)); #ifdef NESTED_ID_NASTY_WORKAROUND if (result) { @@ -310,7 +310,7 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene) #endif bool result = BKE_id_copy_ex( - NULL, id_for_copy, (ID **)&new_scene, LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE); + nullptr, id_for_copy, (ID **)&new_scene, LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE); #ifdef NESTED_ID_NASTY_WORKAROUND if (result) { @@ -339,7 +339,7 @@ ViewLayer *get_original_view_layer(const Depsgraph *depsgraph, const IDNode *id_ * properly fixed. * * TODO(sergey): Support indirectly linked scene. */ - return NULL; + return nullptr; } /* Remove all view layers but the one which corresponds to an input one. */ @@ -359,27 +359,27 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph, * NOTE: Need to keep view layers for all scenes, even indirect ones. This is because of * render layer node possibly pointing to another scene. */ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene_cow->view_layers) { - view_layer->basact = NULL; + view_layer->basact = nullptr; } return; } else if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) { /* Indirectly linked scenes means it's not an input scene and not a set scene, and is pulled * via some driver. Such scenes should not have view layers after copy. */ - view_layer_input = NULL; + view_layer_input = nullptr; } else { view_layer_input = get_original_view_layer(depsgraph, id_node); } - ViewLayer *view_layer_eval = NULL; + ViewLayer *view_layer_eval = nullptr; /* Find evaluated view layer. At the same time we free memory used by * all other of the view layers. */ for (ViewLayer *view_layer_cow = reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first), *view_layer_next; - view_layer_cow != NULL; + view_layer_cow != nullptr; view_layer_cow = view_layer_next) { view_layer_next = view_layer_cow->next; - if (view_layer_input != NULL && STREQ(view_layer_input->name, view_layer_cow->name)) { + if (view_layer_input != nullptr && STREQ(view_layer_input->name, view_layer_cow->name)) { view_layer_eval = view_layer_cow; } else { @@ -387,8 +387,8 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph, } } /* Make evaluated view layer the only one in the evaluated scene (if it exists). */ - if (view_layer_eval != NULL) { - view_layer_eval->prev = view_layer_eval->next = NULL; + if (view_layer_eval != nullptr) { + view_layer_eval->prev = view_layer_eval->next = nullptr; } scene_cow->view_layers.first = view_layer_eval; scene_cow->view_layers.last = view_layer_eval; @@ -405,10 +405,10 @@ void scene_remove_all_bases(Scene *scene_cow) * objects. */ void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *view_layer) { - if (view_layer == NULL) { + if (view_layer == nullptr) { return; } - ListBase enabled_bases = {NULL, NULL}; + ListBase enabled_bases = {nullptr, nullptr}; LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) { /* TODO(sergey): Would be cool to optimize this somehow, or make it so * builder tags bases. @@ -427,7 +427,7 @@ void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *vie } else { if (base == view_layer->basact) { - view_layer->basact = NULL; + view_layer->basact = nullptr; } MEM_freeN(base); } @@ -438,7 +438,7 @@ void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *vie void view_layer_update_orig_base_pointers(const ViewLayer *view_layer_orig, ViewLayer *view_layer_eval) { - if (view_layer_orig == NULL || view_layer_eval == NULL) { + if (view_layer_orig == nullptr || view_layer_eval == nullptr) { /* Happens when scene is only used for parameters or compositor/sequencer. */ return; } @@ -478,7 +478,7 @@ void update_sequence_orig_pointers(const ListBase *sequences_orig, ListBase *seq { Sequence *sequence_orig = reinterpret_cast<Sequence *>(sequences_orig->first); Sequence *sequence_cow = reinterpret_cast<Sequence *>(sequences_cow->first); - while (sequence_orig != NULL) { + while (sequence_orig != nullptr) { update_sequence_orig_pointers(&sequence_orig->seqbase, &sequence_cow->seqbase); sequence_cow->orig_sequence = sequence_orig; sequence_cow = sequence_cow->next; @@ -488,7 +488,7 @@ void update_sequence_orig_pointers(const ListBase *sequences_orig, ListBase *seq void update_scene_orig_pointers(const Scene *scene_orig, Scene *scene_cow) { - if (scene_orig->ed != NULL) { + if (scene_orig->ed != nullptr) { update_sequence_orig_pointers(&scene_orig->ed->seqbase, &scene_cow->ed->seqbase); } } @@ -515,7 +515,7 @@ struct RemapCallbackUserData { int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, int /*cb_flag*/) { - if (*id_p == NULL) { + if (*id_p == nullptr) { return IDWALK_RET_NOP; } RemapCallbackUserData *user_data = (RemapCallbackUserData *)user_data_v; @@ -535,7 +535,7 @@ int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, i const ID_Type id_type_self = GS(id_self->name); if (id_type == ID_OB && id_type_self == ID_SCE) { IDNode *id_node = depsgraph->find_id_node(id_orig); - if (id_node == NULL) { + if (id_node == nullptr) { id_cow = id_orig; } else { @@ -549,7 +549,7 @@ int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, i else { id_cow = depsgraph->get_cow_id(id_orig); } - BLI_assert(id_cow != NULL); + BLI_assert(id_cow != nullptr); DEG_COW_PRINT( " Remapping datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); *id_p = id_cow; @@ -605,12 +605,12 @@ void update_mesh_edit_mode_pointers(const ID *id_orig, ID *id_cow) * edit_mesh to object. */ const Mesh *mesh_orig = (const Mesh *)id_orig; Mesh *mesh_cow = (Mesh *)id_cow; - if (mesh_orig->edit_mesh == NULL) { + if (mesh_orig->edit_mesh == nullptr) { return; } mesh_cow->edit_mesh = (BMEditMesh *)MEM_dupallocN(mesh_orig->edit_mesh); - mesh_cow->edit_mesh->mesh_eval_cage = NULL; - mesh_cow->edit_mesh->mesh_eval_final = NULL; + mesh_cow->edit_mesh->mesh_eval_cage = nullptr; + mesh_cow->edit_mesh->mesh_eval_final = nullptr; } /* Edit data is stored and owned by original datablocks, copied ones @@ -646,7 +646,7 @@ void update_list_orig_pointers(const ListBase *listbase_orig, { T *element_orig = reinterpret_cast<T *>(listbase_orig->first); T *element_cow = reinterpret_cast<T *>(listbase->first); - while (element_orig != NULL) { + while (element_orig != nullptr) { element_cow->*orig_field = element_orig; element_cow = element_cow->next; element_orig = element_orig->next; @@ -679,9 +679,9 @@ void reset_particle_system_edit_eval(const Depsgraph *depsgraph, Object *object_ } LISTBASE_FOREACH (ParticleSystem *, psys, &object_cow->particlesystem) { ParticleSystem *orig_psys = psys->orig_psys; - if (orig_psys->edit != NULL) { - orig_psys->edit->psys_eval = NULL; - orig_psys->edit->psmd_eval = NULL; + if (orig_psys->edit != nullptr) { + orig_psys->edit->psys_eval = nullptr; + orig_psys->edit->psmd_eval = nullptr; } } } @@ -710,7 +710,7 @@ void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *stri { NlaStrip *strip_orig = reinterpret_cast<NlaStrip *>(strips_orig->first); NlaStrip *strip_cow = reinterpret_cast<NlaStrip *>(strips_cow->first); - while (strip_orig != NULL) { + while (strip_orig != nullptr) { strip_cow->orig_strip = strip_orig; update_nla_strips_orig_pointers(&strip_orig->strips, &strip_cow->strips); strip_cow = strip_cow->next; @@ -722,7 +722,7 @@ void update_nla_tracks_orig_pointers(const ListBase *tracks_orig, ListBase *trac { NlaTrack *track_orig = reinterpret_cast<NlaTrack *>(tracks_orig->first); NlaTrack *track_cow = reinterpret_cast<NlaTrack *>(tracks_cow->first); - while (track_orig != NULL) { + while (track_orig != nullptr) { update_nla_strips_orig_pointers(&track_orig->strips, &track_cow->strips); track_cow = track_cow->next; track_orig = track_orig->next; @@ -732,11 +732,11 @@ void update_nla_tracks_orig_pointers(const ListBase *tracks_orig, ListBase *trac void update_animation_data_after_copy(const ID *id_orig, ID *id_cow) { const AnimData *anim_data_orig = BKE_animdata_from_id(const_cast<ID *>(id_orig)); - if (anim_data_orig == NULL) { + if (anim_data_orig == nullptr) { return; } AnimData *anim_data_cow = BKE_animdata_from_id(id_cow); - BLI_assert(anim_data_cow != NULL); + BLI_assert(anim_data_cow != nullptr); update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks); } @@ -747,14 +747,14 @@ void update_proxy_pointers_after_copy(const Depsgraph *depsgraph, const Object *object_orig, Object *object_cow) { - if (object_cow->proxy != NULL) { + if (object_cow->proxy != nullptr) { if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy->id)) { - object_cow->proxy = NULL; + object_cow->proxy = nullptr; } } - if (object_cow->proxy_group != NULL) { + if (object_cow->proxy_group != nullptr) { if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy_group->id)) { - object_cow->proxy_group = NULL; + object_cow->proxy_group = nullptr; } } } @@ -785,7 +785,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, const bArmature *armature_orig = (bArmature *)object_orig->data; bArmature *armature_cow = (bArmature *)object_cow->data; BKE_pose_remap_bone_pointers(armature_cow, object_cow->pose); - if (armature_orig->edbo == NULL) { + if (armature_orig->edbo == nullptr) { update_pose_orig_pointers(object_orig->pose, object_cow->pose); } BKE_pose_pchan_index_rebuild(object_cow->pose); @@ -819,7 +819,7 @@ int foreach_libblock_validate_callback(void *user_data, int /*cb_flag*/) { ValidateData *data = (ValidateData *)user_data; - if (*id_p != NULL) { + if (*id_p != nullptr) { if (!check_datablock_expanded(*id_p)) { data->is_valid = false; /* TODO(sergey): Store which is not valid? */ @@ -906,12 +906,12 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, * is not to be remapped again. */ deg_tag_copy_on_write_id(id_cow, id_orig); /* Perform remapping of the nodes. */ - RemapCallbackUserData user_data = {NULL}; + RemapCallbackUserData user_data = {nullptr}; user_data.depsgraph = depsgraph; user_data.node_builder = node_builder; user_data.create_placeholders = create_placeholders; BKE_library_foreach_ID_link( - NULL, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP); + nullptr, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP); /* Correct or tweak some pointers which are not taken care by foreach * from above. */ update_id_after_copy(depsgraph, id_node, id_orig, id_cow); @@ -926,7 +926,7 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, bool create_placeholders) { DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); - BLI_assert(id_node != NULL); + BLI_assert(id_node != nullptr); return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders); } @@ -950,7 +950,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig) { DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); - BLI_assert(id_node != NULL); + BLI_assert(id_node != nullptr); return deg_update_copy_on_write_datablock(depsgraph, id_node); } @@ -959,47 +959,47 @@ namespace { void discard_armature_edit_mode_pointers(ID *id_cow) { bArmature *armature_cow = (bArmature *)id_cow; - armature_cow->edbo = NULL; + armature_cow->edbo = nullptr; } void discard_curve_edit_mode_pointers(ID *id_cow) { Curve *curve_cow = (Curve *)id_cow; - curve_cow->editnurb = NULL; - curve_cow->editfont = NULL; + curve_cow->editnurb = nullptr; + curve_cow->editfont = nullptr; } void discard_mball_edit_mode_pointers(ID *id_cow) { MetaBall *mball_cow = (MetaBall *)id_cow; - mball_cow->editelems = NULL; + mball_cow->editelems = nullptr; } void discard_lattice_edit_mode_pointers(ID *id_cow) { Lattice *lt_cow = (Lattice *)id_cow; - lt_cow->editlatt = NULL; + lt_cow->editlatt = nullptr; } void discard_mesh_edit_mode_pointers(ID *id_cow) { Mesh *mesh_cow = (Mesh *)id_cow; - if (mesh_cow->edit_mesh == NULL) { + if (mesh_cow->edit_mesh == nullptr) { return; } BKE_editmesh_free_derivedmesh(mesh_cow->edit_mesh); MEM_freeN(mesh_cow->edit_mesh); - mesh_cow->edit_mesh = NULL; + mesh_cow->edit_mesh = nullptr; } void discard_scene_pointers(ID *id_cow) { Scene *scene_cow = (Scene *)id_cow; - scene_cow->toolsettings = NULL; - scene_cow->eevee.light_cache = NULL; + scene_cow->toolsettings = nullptr; + scene_cow->eevee.light_cache = nullptr; } -/* NULL-ify all edit mode pointers which points to data from +/* nullptr-ify all edit mode pointers which points to data from * original object. */ void discard_edit_mode_pointers(ID *id_cow) { @@ -1053,8 +1053,8 @@ void deg_free_copy_on_write_datablock(ID *id_cow) * caches from modifying object->data. This is currently happening * due to mesh/curve datablock boundbox tagging dirty. */ Object *ob_cow = (Object *)id_cow; - ob_cow->data = NULL; - ob_cow->sculpt = NULL; + ob_cow->data = nullptr; + ob_cow->sculpt = nullptr; break; } default: @@ -1081,12 +1081,13 @@ void deg_evaluate_copy_on_write(struct ::Depsgraph *graph, const IDNode *id_node bool deg_validate_copy_on_write_datablock(ID *id_cow) { - if (id_cow == NULL) { + if (id_cow == nullptr) { return false; } ValidateData data; data.is_valid = true; - BKE_library_foreach_ID_link(NULL, id_cow, foreach_libblock_validate_callback, &data, IDWALK_NOP); + BKE_library_foreach_ID_link( + nullptr, id_cow, foreach_libblock_validate_callback, &data, IDWALK_NOP); return data.is_valid; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index 2f83c2f54b9..1992c80e036 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -52,11 +52,11 @@ struct IDNode; */ ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph, const IDNode *id_node, - DepsgraphNodeBuilder *node_builder = NULL, + DepsgraphNodeBuilder *node_builder = nullptr, bool create_placeholders = false); ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph, struct ID *id_orig, - DepsgraphNodeBuilder *node_builder = NULL, + DepsgraphNodeBuilder *node_builder = nullptr, bool create_placeholders = false); /* Makes sure given CoW data-block is brought back to state of the original diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 96e2974a7ab..d99f6cccc69 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -49,6 +49,7 @@ extern "C" { #include "intern/debug/deg_debug.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" #include "intern/depsgraph_update.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_component.h" @@ -156,7 +157,7 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node, * whole IK solver, otherwise result might be unpredictable. */ if (comp_node->type == NodeType::BONE) { ComponentNode *pose_comp = id_node->find_component(NodeType::EVAL_POSE); - BLI_assert(pose_comp != NULL); + BLI_assert(pose_comp != nullptr); if (pose_comp->custom_flags == COMPONENT_STATE_NONE) { queue->push_front(pose_comp->get_entry_operation()); pose_comp->custom_flags = COMPONENT_STATE_SCHEDULED; @@ -172,7 +173,7 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node, */ BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQueue *queue) { - OperationNode *result = NULL; + OperationNode *result = nullptr; for (Relation *rel : op_node->outlinks) { /* Flush is forbidden, completely. */ if (rel->flag & RELATION_FLAG_NO_FLUSH) { @@ -196,7 +197,7 @@ BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQ if (to_node->scheduled) { continue; } - if (result != NULL) { + if (result != nullptr) { queue->push_front(to_node); } else { @@ -210,7 +211,7 @@ BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQ void flush_engine_data_update(ID *id) { DrawDataList *draw_data_list = DRW_drawdatalist_from_id(id); - if (draw_data_list == NULL) { + if (draw_data_list == nullptr) { return; } LISTBASE_FOREACH (DrawData *, draw_data, draw_data_list) { @@ -235,7 +236,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd continue; } DepsNodeFactory *factory = type_get_factory(comp_node->type); - BLI_assert(factory != NULL); + BLI_assert(factory != nullptr); id_cow->recalc |= factory->id_recalc_tag(); } GHASH_FOREACH_END(); @@ -336,8 +337,8 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph) void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) { /* Sanity checks. */ - BLI_assert(bmain != NULL); - BLI_assert(graph != NULL); + BLI_assert(bmain != nullptr); + BLI_assert(graph != nullptr); /* Nothing to update, early out. */ if (graph->need_update_time) { const Scene *scene_orig = graph->scene; @@ -364,7 +365,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) while (!queue.empty()) { OperationNode *op_node = queue.front(); queue.pop_front(); - while (op_node != NULL) { + while (op_node != nullptr) { /* Tag operation as required for update. */ op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; /* Inform corresponding ID and component nodes about the change. */ @@ -392,7 +393,7 @@ void deg_graph_clear_tags(Depsgraph *graph) DEPSOP_FLAG_USER_MODIFIED); } /* Clear any entry tags which haven't been flushed. */ - BLI_gset_clear(graph->entry_tags, NULL); + BLI_gset_clear(graph->entry_tags, nullptr); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index 88390ab412f..40a17666880 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -32,13 +32,14 @@ namespace DEG { RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph) - : scene_backup(depsgraph), + : animation_backup(depsgraph), + scene_backup(depsgraph), sound_backup(depsgraph), object_backup(depsgraph), - drawdata_ptr(NULL), + drawdata_ptr(nullptr), movieclip_backup(depsgraph) { - drawdata_backup.first = drawdata_backup.last = NULL; + drawdata_backup.first = drawdata_backup.last = nullptr; } void RuntimeBackup::init_from_id(ID *id) @@ -47,6 +48,8 @@ void RuntimeBackup::init_from_id(ID *id) return; } + animation_backup.init_from_id(id); + const ID_Type id_type = GS(id->name); switch (id_type) { case ID_OB: @@ -68,14 +71,16 @@ void RuntimeBackup::init_from_id(ID *id) /* Note that we never free GPU draw data from here since that's not * safe for threading and draw data is likely to be re-used. */ drawdata_ptr = DRW_drawdatalist_from_id(id); - if (drawdata_ptr != NULL) { + if (drawdata_ptr != nullptr) { drawdata_backup = *drawdata_ptr; - drawdata_ptr->first = drawdata_ptr->last = NULL; + drawdata_ptr->first = drawdata_ptr->last = nullptr; } } void RuntimeBackup::restore_to_id(ID *id) { + animation_backup.restore_to_id(id); + const ID_Type id_type = GS(id->name); switch (id_type) { case ID_OB: @@ -93,7 +98,7 @@ void RuntimeBackup::restore_to_id(ID *id) default: break; } - if (drawdata_ptr != NULL) { + if (drawdata_ptr != nullptr) { *drawdata_ptr = drawdata_backup; } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h index 31ae3164e37..cc8c6ae0d5b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h @@ -25,6 +25,7 @@ #include "DNA_ID.h" +#include "intern/eval/deg_eval_runtime_backup_animation.h" #include "intern/eval/deg_eval_runtime_backup_movieclip.h" #include "intern/eval/deg_eval_runtime_backup_object.h" #include "intern/eval/deg_eval_runtime_backup_scene.h" @@ -38,12 +39,13 @@ class RuntimeBackup { public: explicit RuntimeBackup(const Depsgraph *depsgraph); - /* NOTE: Will reset all runtime fields which has been backed up to NULL. */ + /* NOTE: Will reset all runtime fields which has been backed up to nullptr. */ void init_from_id(ID *id); /* Restore fields to the given ID. */ void restore_to_id(ID *id); + AnimationBackup animation_backup; SceneBackup scene_backup; SoundBackup sound_backup; ObjectRuntimeBackup object_backup; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc new file mode 100644 index 00000000000..e3beeb52ab1 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc @@ -0,0 +1,144 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_runtime_backup_animation.h" + +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "intern/depsgraph.h" + +namespace DEG { + +namespace { + +struct AnimatedPropertyStoreCalbackData { + AnimationBackup *backup; + + /* ID which needs to be stored. + * Is used to check possibly nested IDs which f-curves are pointing to. */ + ID *id; + + PointerRNA id_pointer_rna; +}; + +void animated_property_store_cb(ID *id, FCurve *fcurve, void *data_v) +{ + AnimatedPropertyStoreCalbackData *data = reinterpret_cast<AnimatedPropertyStoreCalbackData *>( + data_v); + if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') { + return; + } + if (id != data->id) { + return; + } + + /* Resolve path to the property. */ + PathResolvedRNA resolved_rna; + if (!BKE_animsys_store_rna_setting( + &data->id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna)) { + return; + } + + /* Read property value. */ + float value; + if (!BKE_animsys_read_rna_setting(&resolved_rna, &value)) { + return; + } + + data->backup->values_backup.emplace_back(fcurve->rna_path, fcurve->array_index, value); +} + +} // namespace + +AnimationValueBackup::AnimationValueBackup() +{ +} + +AnimationValueBackup::AnimationValueBackup(const string &rna_path, int array_index, float value) + : rna_path(rna_path), array_index(array_index), value(value) +{ +} + +AnimationValueBackup::~AnimationValueBackup() +{ +} + +AnimationBackup::AnimationBackup(const Depsgraph *depsgraph) +{ + meed_value_backup = !depsgraph->is_active; + reset(); +} + +void AnimationBackup::reset() +{ +} + +void AnimationBackup::init_from_id(ID *id) +{ + /* NOTE: This animation backup nicely preserves values which are animated and + * are not touched by frame/depsgraph post_update handler. + * + * But it makes it impossible to have user edits to animated properties: for + * example, translation of object with animated location will not work with + * the current version of backup. */ + return; + + AnimatedPropertyStoreCalbackData data; + data.backup = this; + data.id = id; + RNA_id_pointer_create(id, &data.id_pointer_rna); + BKE_fcurves_id_cb(id, animated_property_store_cb, &data); +} + +void AnimationBackup::restore_to_id(ID *id) +{ + return; + + PointerRNA id_pointer_rna; + RNA_id_pointer_create(id, &id_pointer_rna); + for (const AnimationValueBackup &value_backup : values_backup) { + /* Resolve path to the property. + * + * NOTE: Do it again (after storing), since the sub-data pointers might be + * changed after copy-on-write. */ + PathResolvedRNA resolved_rna; + if (!BKE_animsys_store_rna_setting(&id_pointer_rna, + value_backup.rna_path.c_str(), + value_backup.array_index, + &resolved_rna)) { + return; + } + + /* Write property value. */ + if (!BKE_animsys_write_rna_setting(&resolved_rna, value_backup.value)) { + return; + } + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h new file mode 100644 index 00000000000..d97ee2b0556 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h @@ -0,0 +1,65 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +#include "BKE_modifier.h" + +#include "intern/depsgraph_type.h" + +namespace DEG { + +struct Depsgraph; + +class AnimationValueBackup { + public: + AnimationValueBackup(); + AnimationValueBackup(const string &rna_path, int array_index, float value); + ~AnimationValueBackup(); + + AnimationValueBackup(const AnimationValueBackup &other) = default; + AnimationValueBackup(AnimationValueBackup &&other) noexcept = default; + + AnimationValueBackup &operator=(const AnimationValueBackup &other) = default; + AnimationValueBackup &operator=(AnimationValueBackup &&other) = default; + + string rna_path; + int array_index; + float value; +}; + +/* Backup of animated properties values. */ +class AnimationBackup { + public: + AnimationBackup(const Depsgraph *depsgraph); + + void reset(); + + void init_from_id(ID *id); + void restore_to_id(ID *id); + + bool meed_value_backup; + vector<AnimationValueBackup> values_backup; +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc index c5744533083..3361c26a077 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc @@ -26,7 +26,7 @@ namespace DEG { ModifierDataBackupID::ModifierDataBackupID(const Depsgraph * /*depsgraph*/) - : ModifierDataBackupID(NULL, eModifierType_None) + : ModifierDataBackupID(nullptr, eModifierType_None) { } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc index 54838475bbf..d552c8da99a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc @@ -36,8 +36,8 @@ MovieClipBackup::MovieClipBackup(const Depsgraph * /*depsgraph*/) void MovieClipBackup::reset() { - anim = NULL; - cache = NULL; + anim = nullptr; + cache = nullptr; } void MovieClipBackup::init_from_movieclip(MovieClip *movieclip) @@ -46,8 +46,8 @@ void MovieClipBackup::init_from_movieclip(MovieClip *movieclip) cache = movieclip->cache; /* Clear pointers stored in the movie clip, so they are not freed when copied-on-written * datablock is freed for re-allocation. */ - movieclip->anim = NULL; - movieclip->cache = NULL; + movieclip->anim = nullptr; + movieclip->cache = nullptr; } void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc index a6a042f3e7b..df7338e1076 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc @@ -52,7 +52,7 @@ void ObjectRuntimeBackup::init_from_object(Object *object) /* Object update will override actual object->data to an evaluated version. * Need to make sure we don't have data set to evaluated one before free * anything. */ - if (mesh_eval != NULL && object->data == mesh_eval) { + if (mesh_eval != nullptr && object->data == mesh_eval) { object->data = runtime.mesh_orig; } /* Make a backup of base flags. */ @@ -73,22 +73,22 @@ inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) { LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { - if (modifier_data->runtime == NULL) { + if (modifier_data->runtime == nullptr) { continue; } - BLI_assert(modifier_data->orig_modifier_data != NULL); + BLI_assert(modifier_data->orig_modifier_data != nullptr); ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime)); - modifier_data->runtime = NULL; + modifier_data->runtime = nullptr; } } void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object) { - if (object->pose != NULL) { + if (object->pose != nullptr) { LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - /* This is NULL in Edit mode. */ - if (pchan->orig_pchan != NULL) { + /* This is nullptr in Edit mode. */ + if (pchan->orig_pchan != nullptr) { pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime; BKE_pose_channel_runtime_reset(&pchan->runtime); } @@ -103,7 +103,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object) object->runtime = runtime; object->runtime.mesh_orig = mesh_orig; object->runtime.bb = bb; - if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) { + if (object->type == OB_MESH && object->runtime.mesh_eval != nullptr) { if (object->id.recalc & ID_RECALC_GEOMETRY) { /* If geometry is tagged for update it means, that part of * evaluated mesh are not valid anymore. In this case we can not @@ -138,33 +138,33 @@ void ObjectRuntimeBackup::restore_to_object(Object *object) void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) { LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { - BLI_assert(modifier_data->orig_modifier_data != NULL); + BLI_assert(modifier_data->orig_modifier_data != nullptr); ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find( modifier_data_id); if (runtime_data_iterator != modifier_runtime_data.end()) { modifier_data->runtime = runtime_data_iterator->second; - runtime_data_iterator->second = NULL; + runtime_data_iterator->second = nullptr; } } for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) { const ModifierDataBackupID modifier_data_id = value.first; void *runtime = value.second; - if (value.second == NULL) { + if (value.second == nullptr) { continue; } const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type); - BLI_assert(modifier_type_info != NULL); + BLI_assert(modifier_type_info != nullptr); modifier_type_info->freeRuntimeData(runtime); } } void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) { - if (object->pose != NULL) { + if (object->pose != nullptr) { LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - /* This is NULL in Edit mode. */ - if (pchan->orig_pchan != NULL) { + /* This is nullptr in Edit mode. */ + if (pchan->orig_pchan != nullptr) { PoseChannelRuntimeDataBackup::iterator runtime_data_iterator = pose_channel_runtime_data.find(pchan->orig_pchan); if (runtime_data_iterator != pose_channel_runtime_data.end()) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc index a288fb6ab92..a1d6961cf5d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc @@ -35,10 +35,10 @@ SceneBackup::SceneBackup(const Depsgraph *depsgraph) : sequencer_backup(depsgrap void SceneBackup::reset() { - sound_scene = NULL; - playback_handle = NULL; - sound_scrub_handle = NULL; - speaker_handles = NULL; + sound_scene = nullptr; + playback_handle = nullptr; + sound_scrub_handle = nullptr; + speaker_handles = nullptr; rigidbody_last_time = -1; } @@ -49,16 +49,16 @@ void SceneBackup::init_from_scene(Scene *scene) sound_scrub_handle = scene->sound_scrub_handle; speaker_handles = scene->speaker_handles; - if (scene->rigidbody_world != NULL) { + if (scene->rigidbody_world != nullptr) { rigidbody_last_time = scene->rigidbody_world->ltime; } /* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock * is freed for re-allocation. */ - scene->sound_scene = NULL; - scene->playback_handle = NULL; - scene->sound_scrub_handle = NULL; - scene->speaker_handles = NULL; + scene->sound_scene = nullptr; + scene->playback_handle = nullptr; + scene->sound_scrub_handle = nullptr; + scene->speaker_handles = nullptr; sequencer_backup.init_from_scene(scene); } @@ -70,7 +70,7 @@ void SceneBackup::restore_to_scene(Scene *scene) scene->sound_scrub_handle = sound_scrub_handle; scene->speaker_handles = speaker_handles; - if (scene->rigidbody_world != NULL) { + if (scene->rigidbody_world != nullptr) { scene->rigidbody_world->ltime = rigidbody_last_time; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc index 0150281a4ef..f26d78d3138 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc @@ -34,14 +34,14 @@ SequenceBackup::SequenceBackup(const Depsgraph * /*depsgraph*/) void SequenceBackup::reset() { - scene_sound = NULL; + scene_sound = nullptr; } void SequenceBackup::init_from_sequence(Sequence *sequence) { scene_sound = sequence->scene_sound; - sequence->scene_sound = NULL; + sequence->scene_sound = nullptr; } void SequenceBackup::restore_to_sequence(Sequence *sequence) @@ -52,7 +52,7 @@ void SequenceBackup::restore_to_sequence(Sequence *sequence) bool SequenceBackup::isEmpty() const { - return (scene_sound == NULL); + return (scene_sound == nullptr); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc index 08c2697aab3..adc7fd570e8 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc @@ -63,7 +63,7 @@ void SequencerBackup::restore_to_scene(Scene *scene) /* Cleanup audio while the scene is still known. */ for (SequencesBackupMap::value_type &it : sequences_backup) { SequenceBackup &sequence_backup = it.second; - if (sequence_backup.scene_sound != NULL) { + if (sequence_backup.scene_sound != nullptr) { BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound); } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc index 0c54032e32c..f427d57a8ef 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc @@ -36,9 +36,9 @@ SoundBackup::SoundBackup(const Depsgraph * /*depsgraph*/) void SoundBackup::reset() { - cache = NULL; - waveform = NULL; - playback_handle = NULL; + cache = nullptr; + waveform = nullptr; + playback_handle = nullptr; } void SoundBackup::init_from_sound(bSound *sound) @@ -47,9 +47,9 @@ void SoundBackup::init_from_sound(bSound *sound) waveform = sound->waveform; playback_handle = sound->playback_handle; - sound->cache = NULL; - sound->waveform = NULL; - sound->playback_handle = NULL; + sound->cache = nullptr; + sound->waveform = nullptr; + sound->playback_handle = nullptr; } void SoundBackup::restore_to_sound(bSound *sound) diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 16c934e72fe..5002f2890ae 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -28,6 +28,7 @@ #include "BLI_utildefines.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_factory.h" diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index acfc8d19bc7..3878362d936 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -191,11 +191,11 @@ struct Node { virtual OperationNode *get_entry_operation() { - return NULL; + return nullptr; } virtual OperationNode *get_exit_operation() { - return NULL; + return nullptr; } virtual NodeClass get_class() const; diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 830c53cfc76..334f55c0942 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -104,7 +104,7 @@ static void comp_node_hash_value_free(void *value_v) } ComponentNode::ComponentNode() - : entry_operation(NULL), exit_operation(NULL), affects_directly_visible(false) + : entry_operation(nullptr), exit_operation(nullptr), affects_directly_visible(false) { operations_map = BLI_ghash_new(comp_node_hash_key, comp_node_hash_key_cmp, "Depsgraph id hash"); } @@ -120,7 +120,7 @@ void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/) ComponentNode::~ComponentNode() { clear_operations(); - if (operations_map != NULL) { + if (operations_map != nullptr) { BLI_ghash_free(operations_map, comp_node_hash_key_free, comp_node_hash_value_free); } } @@ -135,8 +135,8 @@ string ComponentNode::identifier() const OperationNode *ComponentNode::find_operation(OperationIDKey key) const { - OperationNode *node = NULL; - if (operations_map != NULL) { + OperationNode *node = nullptr; + if (operations_map != nullptr) { node = (OperationNode *)BLI_ghash_lookup(operations_map, &key); } else { @@ -162,13 +162,13 @@ OperationNode *ComponentNode::find_operation(OperationCode opcode, OperationNode *ComponentNode::get_operation(OperationIDKey key) const { OperationNode *node = find_operation(key); - if (node == NULL) { + if (node == nullptr) { fprintf(stderr, "%s: find_operation(%s) failed\n", this->identifier().c_str(), key.identifier().c_str()); BLI_assert(!"Request for non-existing operation, should not happen"); - return NULL; + return nullptr; } return node; } @@ -183,7 +183,7 @@ OperationNode *ComponentNode::get_operation(OperationCode opcode, bool ComponentNode::has_operation(OperationIDKey key) const { - return find_operation(key) != NULL; + return find_operation(key) != nullptr; } bool ComponentNode::has_operation(OperationCode opcode, const char *name, int name_tag) const @@ -229,19 +229,19 @@ OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb &op, void ComponentNode::set_entry_operation(OperationNode *op_node) { - BLI_assert(entry_operation == NULL); + BLI_assert(entry_operation == nullptr); entry_operation = op_node; } void ComponentNode::set_exit_operation(OperationNode *op_node) { - BLI_assert(exit_operation == NULL); + BLI_assert(exit_operation == nullptr); exit_operation = op_node; } void ComponentNode::clear_operations() { - if (operations_map != NULL) { + if (operations_map != nullptr) { BLI_ghash_clear(operations_map, comp_node_hash_key_free, comp_node_hash_value_free); } for (OperationNode *op_node : operations) { @@ -253,14 +253,14 @@ void ComponentNode::clear_operations() void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source) { OperationNode *entry_op = get_entry_operation(); - if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + if (entry_op != nullptr && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) { return; } for (OperationNode *op_node : operations) { op_node->tag_update(graph, source); } // It is possible that tag happens before finalization. - if (operations_map != NULL) { + if (operations_map != nullptr) { GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) { op_node->tag_update(graph, source); } @@ -273,8 +273,8 @@ OperationNode *ComponentNode::get_entry_operation() if (entry_operation) { return entry_operation; } - else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) { - OperationNode *op_node = NULL; + else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) { + OperationNode *op_node = nullptr; /* TODO(sergey): This is somewhat slow. */ GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) { op_node = tmp; @@ -287,7 +287,7 @@ OperationNode *ComponentNode::get_entry_operation() else if (operations.size() == 1) { return operations[0]; } - return NULL; + return nullptr; } OperationNode *ComponentNode::get_exit_operation() @@ -295,8 +295,8 @@ OperationNode *ComponentNode::get_exit_operation() if (exit_operation) { return exit_operation; } - else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) { - OperationNode *op_node = NULL; + else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) { + OperationNode *op_node = nullptr; /* TODO(sergey): This is somewhat slow. */ GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) { op_node = tmp; @@ -309,7 +309,7 @@ OperationNode *ComponentNode::get_exit_operation() else if (operations.size() == 1) { return operations[0]; } - return NULL; + return nullptr; } void ComponentNode::finalize_build(Depsgraph * /*graph*/) @@ -319,8 +319,8 @@ void ComponentNode::finalize_build(Depsgraph * /*graph*/) operations.push_back(op_node); } GHASH_FOREACH_END(); - BLI_ghash_free(operations_map, comp_node_hash_key_free, NULL); - operations_map = NULL; + BLI_ghash_free(operations_map, comp_node_hash_key_free, nullptr); + operations_map = nullptr; } /* Bone Component ========================================= */ diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index 53fbc6e617c..c25f0bbd7aa 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -65,7 +65,7 @@ struct ComponentNode : public Node { virtual string identifier() const override; /* Find an existing operation, if requested operation does not exist - * NULL will be returned. */ + * nullptr will be returned. */ OperationNode *find_operation(OperationIDKey key) const; OperationNode *find_operation(OperationCode opcode, const char *name, int name_tag) const; diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.cc b/source/blender/depsgraph/intern/node/deg_node_factory.cc index 4a11ed2a4fb..9dfd018b4fd 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory.cc +++ b/source/blender/depsgraph/intern/node/deg_node_factory.cc @@ -26,11 +26,11 @@ namespace DEG { /* Global type registry */ -static DepsNodeFactory *node_typeinfo_registry[static_cast<int>(NodeType::NUM_TYPES)] = {NULL}; +static DepsNodeFactory *node_typeinfo_registry[static_cast<int>(NodeType::NUM_TYPES)] = {nullptr}; void register_node_typeinfo(DepsNodeFactory *factory) { - BLI_assert(factory != NULL); + BLI_assert(factory != nullptr); const int type_as_int = static_cast<int>(factory->type()); node_typeinfo_registry[type_as_int] = factory; } diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index e14513a1aa2..853198109a2 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -101,7 +101,7 @@ static void id_deps_node_hash_value_free(void *value_v) /* Initialize 'id' node - from pointer data given. */ void IDNode::init(const ID *id, const char *UNUSED(subdata)) { - BLI_assert(id != NULL); + BLI_assert(id != nullptr); /* Store ID-pointer. */ id_orig = (ID *)id; eval_flags = 0; @@ -126,7 +126,7 @@ void IDNode::init_copy_on_write(ID *id_cow_hint) /* Create pointer as early as possible, so we can use it for function * bindings. Rest of data we'll be copying to the new datablock when * it is actually needed. */ - if (id_cow_hint != NULL) { + if (id_cow_hint != nullptr) { // BLI_assert(deg_copy_on_write_is_needed(id_orig)); if (deg_copy_on_write_is_needed(id_orig)) { id_cow = id_cow_hint; @@ -154,22 +154,22 @@ IDNode::~IDNode() void IDNode::destroy() { - if (id_orig == NULL) { + if (id_orig == nullptr) { return; } BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free); /* Free memory used by this CoW ID. */ - if (id_cow != id_orig && id_cow != NULL) { + if (id_cow != id_orig && id_cow != nullptr) { deg_free_copy_on_write_datablock(id_cow); MEM_freeN(id_cow); - id_cow = NULL; + id_cow = nullptr; DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); } /* Tag that the node is freed. */ - id_orig = NULL; + id_orig = nullptr; } string IDNode::identifier() const diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 35184253f5c..886c25b5a4e 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -57,7 +57,7 @@ struct IDNode : public Node { }; virtual void init(const ID *id, const char *subdata) override; - void init_copy_on_write(ID *id_cow_hint = NULL); + void init_copy_on_write(ID *id_cow_hint = nullptr); ~IDNode(); void destroy(); diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 09a761d282f..e313b5ccee7 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -241,13 +241,13 @@ void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source) void OperationNode::set_as_entry() { - BLI_assert(owner != NULL); + BLI_assert(owner != nullptr); owner->set_entry_operation(this); } void OperationNode::set_as_exit() { - BLI_assert(owner != NULL); + BLI_assert(owner != nullptr); owner->set_exit_operation(this); } diff --git a/source/blender/depsgraph/intern/node/deg_node_time.cc b/source/blender/depsgraph/intern/node/deg_node_time.cc index cae98ef56c0..ff3e950bb44 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.cc +++ b/source/blender/depsgraph/intern/node/deg_node_time.cc @@ -26,6 +26,7 @@ #include "DNA_scene_types.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" namespace DEG { diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 2c29083199a..2e0afc5d8d7 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1529,18 +1529,10 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { /* Get per-material split surface */ - char *auto_layer_names; - int *auto_layer_is_srgb; - int auto_layer_count; struct GPUBatch **mat_geom = NULL; if (!use_sculpt_pbvh) { - mat_geom = DRW_cache_object_surface_material_get(ob, - gpumat_array, - materials_len, - &auto_layer_names, - &auto_layer_is_srgb, - &auto_layer_count); + mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); } if (use_sculpt_pbvh) { @@ -1577,28 +1569,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i], oedata); ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata); - char *name = auto_layer_names; - for (int j = 0; j < auto_layer_count; j++) { - /* TODO don't add these uniform when not needed (default pass shaders). */ - /* FIXME: This is broken, as it overrides any autolayers srgb bool of the previous mesh - * that shares the same material. */ - if (shgrp_array[i]) { - DRW_shgroup_uniform_bool_copy(shgrp_array[i], name, auto_layer_is_srgb[j]); - } - if (shgrp_depth_array[i]) { - DRW_shgroup_uniform_bool_copy(shgrp_depth_array[i], name, auto_layer_is_srgb[j]); - } - if (shgrp_depth_clip_array[i]) { - DRW_shgroup_uniform_bool_copy( - shgrp_depth_clip_array[i], name, auto_layer_is_srgb[j]); - } - /* Go to next layer name. */ - while (*name != '\0') { - name++; - } - name += 1; - } - /* Shadow Pass */ struct GPUMaterial *gpumat; const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree); diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 849807e24b5..97290abe4b7 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -35,6 +35,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_action.h" #include "BKE_armature.h" #include "BKE_modifier.h" @@ -990,6 +991,15 @@ static bool set_pchan_color(const ArmatureDrawContext *ctx, /** \name Drawing Color Helpers * \{ */ +static void bone_locked_color_shade(float color[4]) +{ + float locked_color[4]; + + UI_GetThemeColor4fv(TH_BONE_LOCKED_WEIGHT, locked_color); + + interp_v3_v3v3(color, color, locked_color, locked_color[3]); +} + static const float *get_bone_solid_color(const ArmatureDrawContext *ctx, const EditBone *UNUSED(eBone), const bPoseChannel *pchan, @@ -1005,6 +1015,11 @@ static const float *get_bone_solid_color(const ArmatureDrawContext *ctx, static float disp_color[4]; copy_v4_v4(disp_color, pchan->draw_data->solid_color); set_pchan_color(ctx, PCHAN_COLOR_SOLID, boneflag, constflag, disp_color); + + if (boneflag & BONE_DRAW_LOCKED_WEIGHT) { + bone_locked_color_shade(disp_color); + } + return disp_color; } @@ -1025,7 +1040,7 @@ static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext * const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag); static float consts_color[4]; - if ((arm->flag & ARM_POSEMODE) && + if ((arm->flag & ARM_POSEMODE) && !(boneflag & BONE_DRAW_LOCKED_WEIGHT) && set_pchan_color(ctx, PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) { interp_v3_v3v3(consts_color, col, consts_color, 0.5f); } @@ -1081,6 +1096,10 @@ static const float *get_bone_wire_color(const ArmatureDrawContext *ctx, else if (arm->flag & ARM_POSEMODE) { copy_v4_v4(disp_color, pchan->draw_data->wire_color); set_pchan_color(ctx, PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color); + + if (boneflag & BONE_DRAW_LOCKED_WEIGHT) { + bone_locked_color_shade(disp_color); + } } else { copy_v3_v3(disp_color, ctx->color.vertex); @@ -1534,7 +1553,7 @@ static void draw_bone_custom_shape(ArmatureDrawContext *ctx, drw_shgroup_bone_custom_empty(ctx, disp_mat, col_wire, pchan->custom); } } - if ((boneflag & BONE_DRAWWIRE) == 0) { + if ((boneflag & BONE_DRAWWIRE) == 0 && (boneflag & BONE_DRAW_LOCKED_WEIGHT) == 0) { drw_shgroup_bone_custom_solid(ctx, disp_mat, col_solid, col_hint, col_wire, pchan->custom); } else { @@ -2026,6 +2045,8 @@ static void draw_armature_edit(ArmatureDrawContext *ctx) boneflag |= BONE_DRAW_ACTIVE; } + boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; + draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag); if (arm->drawtype == ARM_ENVELOPE) { @@ -2070,6 +2091,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) bPoseChannel *pchan; int index = -1; const bool show_text = DRW_state_show_text(); + bool draw_locked_weights = false; /* We can't safely draw non-updated pose, might contain NULL bone pointers... */ if (ob->pose->flag & POSE_RECALC) { @@ -2105,6 +2127,28 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) } } + /* In weight paint mode retrieve the vertex group lock status. */ + if ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) && + (draw_ctx->obact != NULL)) { + draw_locked_weights = true; + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT; + } + + const Object *obact_orig = DEG_get_original_object(draw_ctx->obact); + + LISTBASE_FOREACH (bDeformGroup *, dg, &obact_orig->defbase) { + if (dg->flag & DG_LOCK_WEIGHT) { + pchan = BKE_pose_channel_find_name(ob->pose, dg->name); + + if (pchan) { + pchan->bone->flag |= BONE_DRAW_LOCKED_WEIGHT; + } + } + } + } + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) { Bone *bone = pchan->bone; const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0; @@ -2136,6 +2180,10 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) boneflag |= BONE_DRAW_ACTIVE; } + if (!draw_locked_weights) { + boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; + } + draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag); if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 04dd9ab85bb..0a3252f0b9b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -4,13 +4,18 @@ in vec3 pos; in vec3 nor; in vec2 au; /* active texture layer */ # ifdef V3D_SHADING_VERTEX_COLOR -in vec3 ac; /* active color */ +in vec4 ac; /* active color */ # endif # define uv au #else /* HAIR_SHADER */ + # ifdef V3D_SHADING_TEXTURE_COLOR uniform samplerBuffer au; /* active texture layer */ # endif +# ifdef V3D_SHADING_VERTEX_COLOR +uniform samplerBuffer ac; /* active color layer */ +# endif + flat out float hair_rand; #endif /* HAIR_SHADER */ @@ -37,16 +42,6 @@ float integer_noise(int n) return (float(nn) / 1073741824.0); } -#ifdef V3D_SHADING_VERTEX_COLOR -vec3 srgb_to_linear_attr(vec3 c) -{ - c = max(c, vec3(0.0)); - vec3 c1 = c * (1.0 / 12.92); - vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4)); - return mix(c1, c2, step(vec3(0.04045), c)); -} -#endif - vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand) { /* To "simulate" anisotropic shading, randomize hair normal per strand. */ @@ -90,7 +85,9 @@ void main() #ifdef V3D_SHADING_VERTEX_COLOR # ifndef HAIR_SHADER - vertexColor = srgb_to_linear_attr(ac); + vertexColor = ac.rgb; +# else + vertexColor = hair_get_customdata_vec4(ac).rgb; # endif #endif diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 15e8e1711dd..26402e66318 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -1138,8 +1138,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); - geoms = DRW_cache_object_surface_material_get( - ob, gpumat_array, materials_len, NULL, NULL, NULL); + geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); for (int i = 0; i < materials_len; i++) { if (geoms != NULL && geoms[i] != NULL) { Material *mat = give_current_material(ob, i + 1); diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 4366c87678f..97bea58f31b 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -757,7 +757,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( - ob, gpumat_array, materials_len, NULL, NULL, NULL); + ob, gpumat_array, materials_len); if (mat_geom) { for (int i = 0; i < materials_len; i++) { if (mat_geom[i] == NULL) { diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index d1823292585..6bb58bf8795 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -846,25 +846,11 @@ int DRW_cache_object_material_count_get(struct Object *ob) GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, struct GPUMaterial **gpumat_array, - uint gpumat_array_len, - char **auto_layer_names, - int **auto_layer_is_srgb, - int *auto_layer_count) + uint gpumat_array_len) { - if (auto_layer_names != NULL) { - *auto_layer_names = NULL; - *auto_layer_is_srgb = NULL; - *auto_layer_count = 0; - } - switch (ob->type) { case OB_MESH: - return DRW_cache_mesh_surface_shaded_get(ob, - gpumat_array, - gpumat_array_len, - auto_layer_names, - auto_layer_is_srgb, - auto_layer_count); + return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len); case OB_CURVE: return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len); case OB_SURF: @@ -2757,18 +2743,10 @@ GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob) /* Return list of batches with length equal to max(1, totcol). */ GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob, struct GPUMaterial **gpumat_array, - uint gpumat_array_len, - char **auto_layer_names, - int **auto_layer_is_srgb, - int *auto_layer_count) + uint gpumat_array_len) { BLI_assert(ob->type == OB_MESH); - return DRW_mesh_batch_cache_get_surface_shaded(ob->data, - gpumat_array, - gpumat_array_len, - auto_layer_names, - auto_layer_is_srgb, - auto_layer_count); + return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len); } /* Return list of batches with length equal to max(1, totcol). */ @@ -2919,8 +2897,7 @@ GPUBatch **DRW_cache_curve_surface_shaded_get(Object *ob, struct Curve *cu = ob->data; struct Mesh *mesh_eval = ob->runtime.mesh_eval; if (mesh_eval != NULL) { - return DRW_mesh_batch_cache_get_surface_shaded( - mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL); + return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len); } else { return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len); @@ -3060,8 +3037,7 @@ GPUBatch **DRW_cache_text_surface_shaded_get(Object *ob, return NULL; } if (mesh_eval != NULL) { - return DRW_mesh_batch_cache_get_surface_shaded( - mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL); + return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len); } else { return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len); @@ -3155,8 +3131,7 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob, struct Curve *cu = ob->data; struct Mesh *mesh_eval = ob->runtime.mesh_eval; if (mesh_eval != NULL) { - return DRW_mesh_batch_cache_get_surface_shaded( - mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL); + return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len); } else { return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len); diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index a77a847409b..508a6f2c46d 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -54,10 +54,7 @@ struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob); struct GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob); struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, struct GPUMaterial **gpumat_array, - uint gpumat_array_len, - char **auto_layer_names, - int **auto_layer_is_srgb, - int *auto_layer_count); + uint gpumat_array_len); struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob); int DRW_cache_object_material_count_get(struct Object *ob); @@ -128,10 +125,7 @@ struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_edges_get(struct Object *ob); struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob, struct GPUMaterial **gpumat_array, - uint gpumat_array_len, - char **auto_layer_names, - int **auto_layer_is_srgb, - int *auto_layer_count); + uint gpumat_array_len); struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index 2d10199782b..9228147af44 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -213,12 +213,6 @@ typedef struct MeshBatchCache { GPUBatch **surface_per_mat; - /* arrays of bool uniform names (and value) that will be use to - * set srgb conversion for auto attributes.*/ - char *auto_layer_names; - int *auto_layer_is_srgb; - int auto_layer_len; - DRWBatchFlag batch_requested; DRWBatchFlag batch_ready; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index c98494ebdd9..ee0597c6b21 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -1928,7 +1928,7 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME); BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) { GPU_vertformat_alias_add(&format, "c"); @@ -1948,12 +1948,20 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf) GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); - MLoopCol *vcol_data = (MLoopCol *)vbo->data; + typedef struct gpuMeshVcol { + ushort r, g, b, a; + } gpuMeshVcol; + + gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data; for (int i = 0; i < 8; i++) { if (vcol_layers & (1 << i)) { - void *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - memcpy(vcol_data, layer_data, sizeof(*vcol_data) * mr->loop_len); - vcol_data += mr->loop_len; + MLoopCol *mcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + for (int l = 0; l < mr->loop_len; l++, mcol++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + } } } return NULL; diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index e5a363f3115..755f794d201 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -133,10 +133,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Mesh *me); struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me, struct GPUMaterial **gpumat_array, - uint gpumat_array_len, - char **auto_layer_names, - int **auto_layer_is_srgb, - int *auto_layer_count); + uint gpumat_array_len); struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 167e48e9c2d..87f93bf6fd6 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -230,68 +230,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, return cd_used; } -static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me, - DRW_MeshCDMask cd_used, - char **r_auto_layers_names, - int **r_auto_layers_srgb, - int *r_auto_layers_len) -{ - const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - - int uv_len_used = count_bits_i(cd_used.uv); - int vcol_len_used = count_bits_i(cd_used.vcol); - int uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV); - int vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL); - - uint auto_names_len = 32 * (uv_len_used + vcol_len_used); - uint auto_ofs = 0; - /* Allocate max, resize later. */ - char *auto_names = MEM_callocN(sizeof(char) * auto_names_len, __func__); - int *auto_is_srgb = MEM_callocN(sizeof(int) * (uv_len_used + vcol_len_used), __func__); - - for (int i = 0; i < uv_len; i++) { - if ((cd_used.uv & (1 << i)) != 0) { - const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); - char safe_name[GPU_MAX_SAFE_ATTRIB_NAME]; - GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME); - auto_ofs += BLI_snprintf_rlen( - auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name); - /* +1 to include '\0' terminator. */ - auto_ofs += 1; - } - } - - uint auto_is_srgb_ofs = uv_len_used; - for (int i = 0; i < vcol_len; i++) { - if ((cd_used.vcol & (1 << i)) != 0) { - const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); - /* We only do vcols that are not overridden by a uv layer with same name. */ - if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) { - char safe_name[GPU_MAX_SAFE_ATTRIB_NAME]; - GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME); - auto_ofs += BLI_snprintf_rlen( - auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name); - /* +1 to include '\0' terminator. */ - auto_ofs += 1; - auto_is_srgb[auto_is_srgb_ofs] = true; - auto_is_srgb_ofs++; - } - } - } - - auto_names = MEM_reallocN(auto_names, sizeof(char) * auto_ofs); - auto_is_srgb = MEM_reallocN(auto_is_srgb, sizeof(int) * auto_is_srgb_ofs); - - /* WATCH: May have been referenced somewhere before freeing. */ - MEM_SAFE_FREE(*r_auto_layers_names); - MEM_SAFE_FREE(*r_auto_layers_srgb); - - *r_auto_layers_names = auto_names; - *r_auto_layers_srgb = auto_is_srgb; - *r_auto_layers_len = auto_is_srgb_ofs; -} - /** \} */ /* ---------------------------------------------------------------------- */ @@ -492,8 +430,6 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) mesh_cd_layers_type_clear(&cache->cd_used); MEM_SAFE_FREE(cache->surface_per_mat); - MEM_SAFE_FREE(cache->auto_layer_names); - MEM_SAFE_FREE(cache->auto_layer_is_srgb); cache->mat_len = 0; } @@ -771,10 +707,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me) GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me, struct GPUMaterial **gpumat_array, - uint gpumat_array_len, - char **auto_layer_names, - int **auto_layer_is_srgb, - int *auto_layer_count) + uint gpumat_array_len) { MeshBatchCache *cache = mesh_batch_cache_get(me); DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(me, gpumat_array, gpumat_array_len); @@ -783,21 +716,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me, mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); - if (!mesh_cd_layers_type_overlap(cache->cd_used, cd_needed)) { - mesh_cd_extract_auto_layers_names_and_srgb(me, - cache->cd_needed, - &cache->auto_layer_names, - &cache->auto_layer_is_srgb, - &cache->auto_layer_len); - } - mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); - if (auto_layer_names) { - *auto_layer_names = cache->auto_layer_names; - *auto_layer_is_srgb = cache->auto_layer_is_srgb; - *auto_layer_count = cache->auto_layer_len; - } for (int i = 0; i < cache->mat_len; i++) { DRW_batch_request(&cache->surface_per_mat[i]); } diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index f699388c38c..795e7be63b1 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -1182,7 +1182,7 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME); BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name); - col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_U16, 4, GPU_FETCH_FLOAT); if (i == active_col) { GPU_vertformat_alias_add(&format, "c"); diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index 70a9b7ba1fa..ae489fb5233 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -179,9 +179,9 @@ void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *ar, bDopeShee rcti rect; rect.xmin = 0; - rect.xmax = ceilf(ar->sizex * UI_DPI_FAC); - rect.ymin = ar->sizey * UI_DPI_FAC - UI_TIME_SCRUB_MARGIN_Y; - rect.ymax = ceilf(ar->sizey * UI_DPI_FAC); + rect.xmax = ar->winx; + rect.ymin = ar->winy - UI_TIME_SCRUB_MARGIN_Y; + rect.ymax = ar->winy; uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 9a1582679a4..4162e92cfea 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -79,6 +79,7 @@ static bool editbone_unique_check(void *arg, const char *name) return dupli && dupli != data->bone; } +/* If bone is already in list, pass it as param to ignore it. */ void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone) { struct { diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 4c4bac6a249..5486d60d5d7 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -460,14 +460,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event) ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]); - /* handle pressure sensitivity (which is supplied by tablets) */ - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - selem->pressure = wmtab->Pressure; - } - else { - selem->pressure = 1.0f; - } + /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */ + selem->pressure = event->tablet.pressure; bool is_depth_found = stroke_elem_project_fallback_elem( cdd, cdd->prev.location_world_valid, selem); diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 04b5d8f6d40..5eaf14e361b 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -1461,12 +1461,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en /* Check if tablet eraser is being used (when processing events) */ static bool gpencil_is_tablet_eraser_active(const wmEvent *event) { - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - return (wmtab->Active == EVT_TABLET_ERASER); - } - - return false; + return (event->tablet.active == EVT_TABLET_ERASER); } /* ------------------------------- */ @@ -1686,7 +1681,6 @@ static void annotation_draw_apply_event( tGPsdata *p = op->customdata; PointerRNA itemptr; float mousef[2]; - int tablet = 0; /* convert from window-space to area-space mouse coordinates * add any x,y override position for fake events @@ -1720,29 +1714,20 @@ static void annotation_draw_apply_event( p->curtime = PIL_check_seconds_timer(); - /* handle pressure sensitivity (which is supplied by tablets) */ - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; + /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */ + p->pressure = event->tablet.pressure; - tablet = (wmtab->Active != EVT_TABLET_NONE); - p->pressure = wmtab->Pressure; - - /* Hack for pressure sensitive eraser on D+RMB when using a tablet: - * The pen has to float over the tablet surface, resulting in - * zero pressure (T47101). Ignore pressure values if floating - * (i.e. "effectively zero" pressure), and only when the "active" - * end is the stylus (i.e. the default when not eraser) - */ - if (p->paintmode == GP_PAINTMODE_ERASER) { - if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) { - p->pressure = 1.0f; - } + /* Hack for pressure sensitive eraser on D+RMB when using a tablet: + * The pen has to float over the tablet surface, resulting in + * zero pressure (T47101). Ignore pressure values if floating + * (i.e. "effectively zero" pressure), and only when the "active" + * end is the stylus (i.e. the default when not eraser) + */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) { + p->pressure = 1.0f; } } - else { - /* No tablet data -> No pressure info is available */ - p->pressure = 1.0f; - } /* special exception for start of strokes (i.e. maybe for just a dot) */ if (p->flags & GP_PAINTFLAG_FIRSTRUN) { @@ -1758,7 +1743,7 @@ static void annotation_draw_apply_event( /* special exception here for too high pressure values on first touch in * windows for some tablets, then we just skip first touch... */ - if (tablet && (p->pressure >= 0.99f)) { + if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) { return; } } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 91e70e0e089..c2f1e9f091a 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -1977,7 +1977,6 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven GP_Sculpt_Settings *gset = &ts->gp_sculpt; PointerRNA itemptr; float mouse[2]; - int tablet = 0; mouse[0] = event->mval[0] + 1; mouse[1] = event->mval[1] + 1; @@ -1989,24 +1988,14 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false); RNA_boolean_set(&itemptr, "is_start", gso->first); - /* handle pressure sensitivity (which is supplied by tablets) */ - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - float pressure = wmtab->Pressure; - - tablet = (wmtab->Active != EVT_TABLET_NONE); - - /* special exception here for too high pressure values on first touch in - * windows for some tablets: clamp the values to be sane - */ - if (tablet && (pressure >= 0.99f)) { - pressure = 1.0f; - } - RNA_float_set(&itemptr, "pressure", pressure); - } - else { - RNA_float_set(&itemptr, "pressure", 1.0f); + /* handle pressure sensitivity (which is supplied by tablets and otherwise 1.0) */ + float pressure = event->tablet.pressure; + /* special exception here for too high pressure values on first touch in + * windows for some tablets: clamp the values to be sane */ + if (pressure >= 0.99f) { + pressure = 1.0f; } + RNA_float_set(&itemptr, "pressure", pressure); if (!gso->is_weight_mode) { if (event->shift) { diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 6a91417e7f3..09ff24f05fc 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -2553,12 +2553,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en /* Check if tablet eraser is being used (when processing events) */ static bool gpencil_is_tablet_eraser_active(const wmEvent *event) { - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - return (wmtab->Active == EVT_TABLET_ERASER); - } - - return false; + return (event->tablet.active == EVT_TABLET_ERASER); } /* ------------------------------- */ @@ -3020,7 +3015,6 @@ static void gpencil_draw_apply_event(bContext *C, GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; PointerRNA itemptr; float mousef[2]; - int tablet = 0; bool is_speed_guide = ((guide->use_guide) && (p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW))); @@ -3055,29 +3049,20 @@ static void gpencil_draw_apply_event(bContext *C, p->curtime = PIL_check_seconds_timer(); - /* handle pressure sensitivity (which is supplied by tablets) */ - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; + /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */ + p->pressure = event->tablet.pressure; - tablet = (wmtab->Active != EVT_TABLET_NONE); - p->pressure = wmtab->Pressure; - - /* Hack for pressure sensitive eraser on D+RMB when using a tablet: - * The pen has to float over the tablet surface, resulting in - * zero pressure (T47101). Ignore pressure values if floating - * (i.e. "effectively zero" pressure), and only when the "active" - * end is the stylus (i.e. the default when not eraser) - */ - if (p->paintmode == GP_PAINTMODE_ERASER) { - if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) { - p->pressure = 1.0f; - } + /* Hack for pressure sensitive eraser on D+RMB when using a tablet: + * The pen has to float over the tablet surface, resulting in + * zero pressure (T47101). Ignore pressure values if floating + * (i.e. "effectively zero" pressure), and only when the "active" + * end is the stylus (i.e. the default when not eraser) + */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) { + p->pressure = 1.0f; } } - else { - /* No tablet data -> No pressure info is available */ - p->pressure = 1.0f; - } /* special eraser modes */ if (p->paintmode == GP_PAINTMODE_ERASER) { @@ -3101,7 +3086,7 @@ static void gpencil_draw_apply_event(bContext *C, /* special exception here for too high pressure values on first touch in * windows for some tablets, then we just skip first touch... */ - if (tablet && (p->pressure >= 0.99f)) { + if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) { return; } diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 7ac42967dda..40f5cade0d5 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -140,56 +140,45 @@ typedef struct EditBone { (CHECK_TYPE_INLINE(ebone, EditBone *), \ (((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED))) -/* used in armature_select_hierarchy_exec() */ +/* used in armature_select.c and pose_select.c */ #define BONE_SELECT_PARENT 0 #define BONE_SELECT_CHILD 1 +/* armature_add.c */ +EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name); +EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm, + float length, + bool view_aligned); + +/* armature_edit.c */ +float ED_armature_ebone_roll_to_vector(const EditBone *bone, + const float new_up_axis[3], + const bool axis_only); +void ED_armature_origin_set( + struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around); +void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props); +void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props); + +/* armature_naming.c */ +void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone); +void ED_armature_bone_rename(struct Main *bmain, + struct bArmature *arm, + const char *oldnamep, + const char *newnamep); +void ED_armature_bones_flip_names(struct Main *bmain, + struct bArmature *arm, + struct ListBase *bones_names, + const bool do_strip_numbers); + /* armature_ops.c */ void ED_operatortypes_armature(void); void ED_operatormacros_armature(void); void ED_keymap_armature(struct wmKeyConfig *keyconf); -/* editarmature.c */ -void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm); -void ED_armature_to_edit(struct bArmature *arm); -void ED_armature_edit_free(struct bArmature *arm); - -bool ED_armature_edit_deselect_all(struct Object *obedit); -bool ED_armature_edit_deselect_all_visible(struct Object *obedit); - -bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len); -bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len); -bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C); - -bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer, - struct View3D *v3d, - struct Base *base, - const unsigned int *buffer, - short hits, - bool extend, - bool deselect, - bool toggle, - bool do_nearest); - -void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer, - struct Base *base_select); - -bool ED_armature_edit_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); - -bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op); - +/* armature_relations.c */ int join_armature_exec(struct bContext *C, struct wmOperator *op); -float ED_armature_ebone_roll_to_vector(const EditBone *bone, - const float new_up_axis[3], - const bool axis_only); -EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name); -EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone *ebo); -void ED_armature_edit_sync_selection(struct ListBase *edbo); -void ED_armature_edit_validate_active(struct bArmature *arm); - -void ED_armature_edit_refresh_layer_used(struct bArmature *arm); +/* armature_select.c */ struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases, uint bases_len, int hit, @@ -198,63 +187,59 @@ struct Object *ED_armature_object_and_ebone_from_select_buffer(struct Object **o uint objects_len, int hit, struct EditBone **r_ebone); - struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases, uint bases_len, int hit, struct Bone **r_bone); +bool ED_armature_edit_deselect_all(struct Object *obedit); +bool ED_armature_edit_deselect_all_visible(struct Object *obedit); +bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len); +bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len); +bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C); +bool ED_armature_edit_select_pick( + struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op); -EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm, - float length, - bool view_aligned); -EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name); +/* armature_skinning.c */ +#define ARM_GROUPS_NAME 1 +#define ARM_GROUPS_ENVELOPE 2 +#define ARM_GROUPS_AUTO 3 +void ED_object_vgroup_calc_from_armature(struct ReportList *reports, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct Object *par, + const int mode, + const bool mirror); +/* editarmature_undo.c */ +void ED_armature_undosys_type(struct UndoType *ut); + +/* armature_utils.c */ +void ED_armature_edit_sync_selection(struct ListBase *edbo); +void ED_armature_edit_validate_active(struct bArmature *arm); +void ED_armature_edit_refresh_layer_used(struct bArmature *arm); void ED_armature_ebone_remove_ex(struct bArmature *arm, EditBone *exBone, bool clear_connected); void ED_armature_ebone_remove(struct bArmature *arm, EditBone *exBone); - bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child); EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const unsigned int ebone_child_tot); - void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3]); void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4]); - void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]); void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); - +EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name); +EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone *ebo); void ED_armature_ebone_transform_mirror_update(struct bArmature *arm, EditBone *ebo, bool check_select); void ED_armature_edit_transform_mirror_update(struct Object *obedit); -void ED_armature_origin_set( - struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around); - -void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props); - -void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props); - -#define ARM_GROUPS_NAME 1 -#define ARM_GROUPS_ENVELOPE 2 -#define ARM_GROUPS_AUTO 3 - -void ED_object_vgroup_calc_from_armature(struct ReportList *reports, - struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct Object *par, - const int mode, - const bool mirror); - -/* if bone is already in list, pass it as param to ignore it */ -void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone); -void ED_armature_bone_rename(struct Main *bmain, - struct bArmature *arm, - const char *oldnamep, - const char *newnamep); -void ED_armature_bones_flip_names(struct Main *bmain, - struct bArmature *arm, - struct ListBase *bones_names, - const bool do_strip_numbers); +void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm); +void ED_armature_to_edit(struct bArmature *arm); +void ED_armature_edit_free(struct bArmature *arm); +void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); +void ED_armature_ebone_listbase_free(struct ListBase *lb); +void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src); /* low level selection functions which handle */ int ED_armature_ebone_selectflag_get(const EditBone *ebone); @@ -263,27 +248,12 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select); void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag); void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag); -/* editarmature_undo.c */ -void ED_armature_undosys_type(struct UndoType *ut); - -/* armature_utils.c */ -void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); -void ED_armature_ebone_listbase_free(struct ListBase *lb); -void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src); - -/* poseobject.c */ +/* pose_edit.c */ +struct Object *ED_pose_object_from_context(struct bContext *C); bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob); bool ED_object_posemode_exit(struct bContext *C, struct Object *ob); bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob); bool ED_object_posemode_enter(struct bContext *C, struct Object *ob); -bool ED_pose_deselect_all_multi_ex(struct Base **bases, - uint bases_len, - int select_mode, - const bool ignore_visibility); -bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility); -bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility); -void ED_pose_bone_select_tag_update(struct Object *ob); -void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); /* Corresponds to eAnimvizCalcRange. */ typedef enum ePosePathCalcRange { @@ -296,7 +266,26 @@ void ED_pose_recalculate_paths(struct bContext *C, struct Object *ob, ePosePathCalcRange range); -struct Object *ED_pose_object_from_context(struct bContext *C); +/* pose_select.c */ +bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer, + struct View3D *v3d, + struct Base *base, + const unsigned int *buffer, + short hits, + bool extend, + bool deselect, + bool toggle, + bool do_nearest); +void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer, + struct Base *base_select); +bool ED_pose_deselect_all_multi_ex(struct Base **bases, + uint bases_len, + int select_mode, + const bool ignore_visibility); +bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility); +bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility); +void ED_pose_bone_select_tag_update(struct Object *ob); +void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); /* meshlaplacian.c */ void ED_mesh_deform_bind_callback(struct MeshDeformModifierData *mmd, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 6a801fc9928..9e0272d1402 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -69,7 +69,7 @@ void ED_region_exit(struct bContext *C, struct ARegion *ar); void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar); void ED_region_pixelspace(struct ARegion *ar); void ED_region_update_rect(struct ARegion *ar); -void ED_region_init(struct ARegion *ar); +void ED_region_floating_initialize(struct ARegion *ar); void ED_region_tag_redraw(struct ARegion *ar); void ED_region_tag_redraw_partial(struct ARegion *ar, const struct rcti *rct, bool rebuild); void ED_region_tag_redraw_overlay(struct ARegion *ar); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 44c734e264a..fabf6baed23 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -134,7 +134,7 @@ DEF_ICON(RECOVER_LAST) DEF_ICON(THREE_DOTS) DEF_ICON(FULLSCREEN_ENTER) DEF_ICON(FULLSCREEN_EXIT) -DEF_ICON_BLANK(135) +DEF_ICON(BRUSHES_ALL) /* BUTTONS */ DEF_ICON_SHADING(LIGHT) @@ -452,11 +452,11 @@ DEF_ICON(NODE_INSERT_OFF) DEF_ICON(NODE_TOP) DEF_ICON(NODE_SIDE) DEF_ICON(NODE_CORNER) -DEF_ICON_BLANK(698) -DEF_ICON_BLANK(699) -DEF_ICON_BLANK(700) -DEF_ICON_BLANK(701) -DEF_ICON_BLANK(702) +DEF_ICON(ANCHOR_TOP) +DEF_ICON(ANCHOR_BOTTOM) +DEF_ICON(ANCHOR_LEFT) +DEF_ICON(ANCHOR_RIGHT) +DEF_ICON(ANCHOR_CENTER) DEF_ICON_BLANK(703) DEF_ICON_BLANK(704) DEF_ICON_BLANK(705) @@ -793,7 +793,7 @@ DEF_ICON(BOOKMARKS) DEF_ICON(FONTPREVIEW) DEF_ICON(FILTER) DEF_ICON(NEWFOLDER) -DEF_ICON_BLANK(794) +DEF_ICON(FOLDER_REDIRECT) DEF_ICON(FILE_PARENT) DEF_ICON(FILE_REFRESH) DEF_ICON_FOLDER(FILE_FOLDER) @@ -876,11 +876,11 @@ DEF_ICON(IMAGE_RGB) // XXX CHANGE TO STRAIGHT ALPHA, Z ETC DEF_ICON(IMAGE_RGB_ALPHA) DEF_ICON(IMAGE_ALPHA) DEF_ICON(IMAGE_ZDEPTH) -DEF_ICON_BLANK(877) -DEF_ICON_BLANK(878) -DEF_ICON_BLANK(879) -DEF_ICON_BLANK(880) -DEF_ICON_BLANK(881) +DEF_ICON(HANDLE_AUTOCLAMPED) +DEF_ICON(HANDLE_AUTO) +DEF_ICON(HANDLE_ALIGNED) +DEF_ICON(HANDLE_VECTOR) +DEF_ICON(HANDLE_FREE) DEF_ICON_BLANK(882) DEF_ICON_BLANK(883) DEF_ICON_BLANK(884) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index b81fa4ae483..3089d980f06 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1640,7 +1640,12 @@ struct Panel *UI_panel_begin(struct ScrArea *sa, struct PanelType *pt, struct Panel *pa, bool *r_open); -void UI_panel_end(uiBlock *block, int width, int height, bool open); +void UI_panel_end(const struct ScrArea *sa, + const struct ARegion *ar, + uiBlock *block, + int width, + int height, + bool open); void UI_panels_scale(struct ARegion *ar, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); int UI_panel_size_y(const struct Panel *pa); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index bd8eed4e4aa..1e6e46cbe71 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -143,6 +143,7 @@ typedef enum ThemeColorID { TH_BONE_SOLID, TH_BONE_POSE, TH_BONE_POSE_ACTIVE, + TH_BONE_LOCKED_WEIGHT, TH_STRIP, TH_STRIP_SELECT, @@ -320,6 +321,10 @@ typedef enum ThemeColorID { TH_INFO_INFO_TEXT, TH_INFO_DEBUG, TH_INFO_DEBUG_TEXT, + TH_INFO_PROPERTY, + TH_INFO_PROPERTY_TEXT, + TH_INFO_OPERATOR, + TH_INFO_OPERATOR_TEXT, TH_VIEW_OVERLAY, TH_V3D_CLIPPING_BORDER, diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index cc68e303e4a..c058fefb4fa 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -124,7 +124,7 @@ bool ui_but_can_align(const uiBut *but) int ui_but_align_opposite_to_area_align_get(const ARegion *ar) { - switch (ar->alignment) { + switch (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)) { case RGN_ALIGN_TOP: return UI_BUT_ALIGN_DOWN; case RGN_ALIGN_BOTTOM: diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 5dcfcbc88b3..7332f3ee776 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1889,11 +1889,13 @@ static bool ui_but_drag_init(bContext *C, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER)) { + const int ar_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment); int lock_axis = -1; - if (ELEM(data->region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { + + if (ELEM(ar_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { lock_axis = 0; } - else if (ELEM(data->region->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { + else if (ELEM(ar_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { lock_axis = 1; } if (lock_axis != -1) { @@ -2240,7 +2242,13 @@ static void ui_but_set_float_array( RNA_property_float_set_index(&but->rnapoin, but->rnaprop, i, values[i]); } if (data) { - data->value = values[but->rnaindex]; + if (but->type == UI_BTYPE_UNITVEC) { + BLI_assert(array_length == 3); + copy_v3_v3(data->vec, values); + } + else { + data->value = values[but->rnaindex]; + } } button_activate_state(C, but, BUTTON_STATE_EXIT); @@ -2349,7 +2357,10 @@ static void ui_but_paste_numeric_value(bContext *C, } } -static void ui_but_paste_normalized_vector(bContext *C, uiBut *but, char *buf_paste) +static void ui_but_paste_normalized_vector(bContext *C, + uiBut *but, + uiHandleButtonData *data, + char *buf_paste) { float xyz[3]; if (parse_float_array(buf_paste, xyz, 3)) { @@ -2357,7 +2368,7 @@ static void ui_but_paste_normalized_vector(bContext *C, uiBut *but, char *buf_pa /* better set Z up then have a zero vector */ xyz[2] = 1.0; } - ui_but_set_float_array(C, but, NULL, xyz, 3); + ui_but_set_float_array(C, but, data, xyz, 3); } else { WM_report(RPT_ERROR, "Paste expected 3 numbers, formatted: '[n, n, n]'"); @@ -2645,7 +2656,7 @@ static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, cons if (!has_required_data) { break; } - ui_but_paste_normalized_vector(C, but, buf_paste); + ui_but_paste_normalized_vector(C, but, data, buf_paste); break; case UI_BTYPE_COLOR: @@ -10602,15 +10613,11 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata)) * number sliding, text editing, or when a menu block is open */ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSED(userdata)) { - ARegion *ar; + ARegion *menu_region = CTX_wm_menu(C); + ARegion *ar = menu_region ? menu_region : CTX_wm_region(C); uiBut *but; int retval = WM_UI_HANDLER_CONTINUE; - ar = CTX_wm_menu(C); - if (!ar) { - ar = CTX_wm_region(C); - } - but = ui_region_find_active_but(ar); if (but) { @@ -10673,9 +10680,18 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE ui_blocks_set_tooltips(ar, true); } + if (but && but->active && but->active->menu) { + /* Set correct context menu-region. The handling button above breaks if we set the region + * first, so only set it for executing the after-funcs. */ + CTX_wm_menu_set(C, but->active->menu->region); + } + /* delayed apply callbacks */ ui_apply_but_funcs_after(C); + /* Reset to previous context region. */ + CTX_wm_menu_set(C, menu_region); + /* Don't handle double-click events, * these will be converted into regular clicks which we handle. */ if (retval == WM_UI_HANDLER_CONTINUE) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 4770a85460b..41606fce915 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -804,45 +804,6 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf, return result; } -/* Generate the mipmap levels for the icon textures - * During creation the source16 ImBuf will be freed to reduce memory overhead - * A new ImBuf will be returned that needs is owned by the caller. - * - * FIXME: Mipmap levels are generated until the width of the image is 1, which - * are too many levels than that are needed.*/ -static ImBuf *create_mono_icon_mipmaps(ImBuf *source32, ImBuf *source16, int level) -{ - if (level == 0) { - glTexImage2D(GL_TEXTURE_2D, - level, - GL_RGBA8, - source32->x, - source32->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - source32->rect); - return create_mono_icon_mipmaps(source32, source16, level + 1); - } - else { - glTexImage2D(GL_TEXTURE_2D, - level, - GL_RGBA8, - source16->x, - source16->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - source16->rect); - if (source16->x > 1) { - ImBuf *nbuf = IMB_onehalf(source16); - IMB_freeImBuf(source16); - source16 = create_mono_icon_mipmaps(source32, nbuf, level + 1); - } - return source16; - } -} - static void free_icons_textures(void) { if (icongltex.num_textures > 0) { @@ -900,6 +861,8 @@ void UI_icons_reload_internal_textures(void) icongltex.num_textures = need_icons_with_border ? 2 : 1; glGenTextures(icongltex.num_textures, icongltex.id); + /* Note the filter and LOD bias were tweaked to better preserve icon + * sharpness at different UI scales. */ if (icongltex.id[0]) { icongltex.w = b32buf->x; icongltex.h = b32buf->y; @@ -907,17 +870,57 @@ void UI_icons_reload_internal_textures(void) icongltex.invh = 1.0f / b32buf->y; glBindTexture(GL_TEXTURE_2D, icongltex.id[0]); - b16buf = create_mono_icon_mipmaps(b32buf, b16buf, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA8, + b32buf->x, + b32buf->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + b32buf->rect); + glTexImage2D(GL_TEXTURE_2D, + 1, + GL_RGBA8, + b16buf->x, + b16buf->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + b16buf->rect); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); glBindTexture(GL_TEXTURE_2D, 0); } if (need_icons_with_border && icongltex.id[1]) { glBindTexture(GL_TEXTURE_2D, icongltex.id[1]); - b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA8, + b32buf_border->x, + b32buf_border->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + b32buf_border->rect); + glTexImage2D(GL_TEXTURE_2D, + 1, + GL_RGBA8, + b16buf_border->x, + b16buf_border->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + b16buf_border->rect); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); glBindTexture(GL_TEXTURE_2D, 0); } } diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index b7fd953ed63..9a967c3b8f3 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -74,79 +74,37 @@ #include "interface_intern.h" -static void icon_draw_rect_input_small_text_ex( - const rctf *rect, const float color[4], const float margin[2], const char *str, int font_size) +static void icon_draw_rect_input_text(const rctf *rect, + const float color[4], + const char *str, + int font_size) { BLF_batch_draw_flush(); const int font_id = BLF_default(); BLF_color4fv(font_id, color); BLF_size(font_id, font_size * U.pixelsize, U.dpi); - BLF_position(font_id, rect->xmin + margin[0] * 2, rect->ymin + margin[1] * 5, 0.0f); + float width, height; + BLF_width_and_height(font_id, str, BLF_DRAW_STR_DUMMY_MAX, &width, &height); + float x = rect->xmin + (((rect->xmax - rect->xmin) - width) / 2.0f); + float y = rect->ymin + (((rect->ymax - rect->ymin) - height) / 2.0f); + BLF_position(font_id, x, y, 0.0f); BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX); BLF_batch_draw_flush(); } -static void icon_draw_rect_input_small_text(const rctf *rect, - const float color[4], - const float margin[2], - const char *str) -{ - icon_draw_rect_input_small_text_ex(rect, color, margin, str, 8); -} - -static void icon_draw_rect_input_default_text(const rctf *rect, - const float color[4], - const float margin[2], - const char *str) -{ - BLF_batch_draw_flush(); - const int font_id = BLF_default(); - BLF_color4fv(font_id, color); - BLF_position( - font_id, (int)(rect->xmin + margin[0] * 5), (int)(rect->ymin + margin[1] * 5), 0.0f); - BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX); - BLF_batch_draw_flush(); -} - -static void icon_draw_rect_input_mono_text(const rctf *rect, - const float color[4], - const float margin[2], - const char *str) +static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4], const char *str) { BLF_batch_draw_flush(); const int font_id = blf_mono_font; BLF_color4fv(font_id, color); - BLF_size(font_id, 20 * U.pixelsize, U.dpi); - BLF_position( - font_id, (int)(rect->xmin + margin[0] * 5), (int)(rect->ymin + margin[1] * 5), 0.0f); + BLF_size(font_id, 19 * U.pixelsize, U.dpi); + float x = rect->xmin + (2.0f * U.pixelsize); + float y = rect->ymin + (1.0f * U.pixelsize); + BLF_position(font_id, x, y, 0.0f); BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX); BLF_batch_draw_flush(); } -static void icon_draw_rect_input_line_prim( - const rctf *rect, const float color[4], const int prim, const char lines[][2], int lines_len) -{ - GPU_line_smooth(true); - GPU_blend(true); - BLI_assert(ELEM(prim, GPU_PRIM_LINE_LOOP, GPU_PRIM_LINE_STRIP)); - const uint pos_id = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4fv(color); - immBegin(prim, lines_len); - float w_inv = BLI_rctf_size_x(rect) / 255.0f; - float h_inv = BLI_rctf_size_y(rect) / 255.0f; - for (int i = 0; i < lines_len; i++) { - immVertex2f(pos_id, - round_fl_to_int(rect->xmin + ((float)lines[i][0] * w_inv)), - round_fl_to_int(rect->ymin + ((float)lines[i][1] * h_inv))); - } - immEnd(); - immUnbindProgram(); - GPU_line_smooth(false); - GPU_blend(false); -} - void icon_draw_rect_input(float x, float y, int w, @@ -156,11 +114,26 @@ void icon_draw_rect_input(float x, short UNUSED(event_value)) { float color[4]; - const float margin[2] = {w / 20.0f, h / 20.0f}; GPU_line_width(1.0f); UI_GetThemeColor4fv(TH_TEXT, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(false, (int)x, (int)y, (int)(x + w), (int)(y + h), 4.0f, color); + UI_draw_roundbox_aa( + false, (int)x - U.pixelsize, (int)y, (int)(x + w), (int)(y + h), 3.0f * U.pixelsize, color); + + const enum { + UNIX, + MACOS, + MSWIN, + } platform = + +#if defined(__APPLE__) + MACOS +#elif defined(_WIN32) + MSWIN +#else + UNIX +#endif + ; const rctf rect = { .xmin = x, @@ -169,125 +142,87 @@ void icon_draw_rect_input(float x, .ymax = y + h, }; - const bool simple_text = false; - if ((event_type >= AKEY) && (event_type <= ZKEY)) { char str[2] = {'A' + (event_type - AKEY), '\0'}; - icon_draw_rect_input_default_text(&rect, color, margin, str); + icon_draw_rect_input_text(&rect, color, str, 13); } else if ((event_type >= F1KEY) && (event_type <= F12KEY)) { char str[4]; SNPRINTF(str, "F%d", 1 + (event_type - F1KEY)); - icon_draw_rect_input_default_text(&rect, color, margin, str); + icon_draw_rect_input_text(&rect, color, str, event_type > F9KEY ? 8 : 10); } else if (event_type == LEFTSHIFTKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "Shift"); - } - else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -14.0f), (w / -14.0f)); - icon_draw_rect_input_mono_text( - &rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa7, 0x0}); - } + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0}); } else if (event_type == LEFTCTRLKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "Ctrl"); + if (platform == MACOS) { + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0}); } else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -16.0f), 0.0f); - icon_draw_rect_input_default_text(&rect_ofs, color, margin, "^"); + icon_draw_rect_input_text(&rect, color, "Ctrl", 9); } } else if (event_type == LEFTALTKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "Alt"); + if (platform == MACOS) { + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0}); } else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -8.0f), 0.0f); - icon_draw_rect_input_default_text( - &rect_ofs, color, margin, (const char[]){0xe2, 0x8c, 0xa5, 0x0}); + icon_draw_rect_input_text(&rect, color, "Alt", 10); } } else if (event_type == OSKEY) { - icon_draw_rect_input_small_text(&rect, color, margin, "OS"); + if (platform == MACOS) { + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x98, 0x0}); + } + else if (platform == MSWIN) { + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0}); + } + else { + icon_draw_rect_input_text(&rect, color, "OS", 10); + } } else if (event_type == DELKEY) { - icon_draw_rect_input_small_text(&rect, color, margin, "Del"); + icon_draw_rect_input_text(&rect, color, "Del", 9); } else if (event_type == TABKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "Tab"); - } - else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f)); - icon_draw_rect_input_mono_text( - &rect_ofs, color, margin, (const char[]){0xe2, 0x86, 0xb9, 0x0}); - } + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0}); } else if (event_type == HOMEKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "Home"); - } - else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f)); - icon_draw_rect_input_mono_text( - &rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa4, 0x0}); - } + icon_draw_rect_input_text(&rect, color, "Home", 6); } else if (event_type == ENDKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "End"); - } - else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f)); - icon_draw_rect_input_mono_text( - &rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa5, 0x0}); - } + icon_draw_rect_input_text(&rect, color, "End", 8); } else if (event_type == RETKEY) { - if (simple_text) { - icon_draw_rect_input_small_text(&rect, color, margin, "Ret"); + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0}); + } + else if (event_type == ESCKEY) { + if (platform == MACOS) { + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0}); } else { - rctf rect_ofs = rect; - BLI_rctf_translate(&rect_ofs, (w / -8.0f), (w / -6.0f)); - icon_draw_rect_input_mono_text( - &rect_ofs, color, margin, (const char[]){0xe2, 0x8f, 0x8e, 0x0}); + icon_draw_rect_input_text(&rect, color, "Esc", 8); } } - else if (event_type == ESCKEY) { - icon_draw_rect_input_small_text(&rect, color, margin, "Esc"); - } else if (event_type == PAGEUPKEY) { - icon_draw_rect_input_small_text_ex( - &rect, color, margin, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 10); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8); } else if (event_type == PAGEDOWNKEY) { - icon_draw_rect_input_small_text_ex( - &rect, color, margin, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 10); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8); } else if (event_type == LEFTARROWKEY) { - icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x90, 0x0}); + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0}); } else if (event_type == UPARROWKEY) { - icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x91, 0x0}); + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x91, 0x0}); } else if (event_type == RIGHTARROWKEY) { - icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x92, 0x0}); + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x92, 0x0}); } else if (event_type == DOWNARROWKEY) { - icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x93, 0x0}); + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x93, 0x0}); } else if (event_type == SPACEKEY) { - const uchar lines[] = {60, 118, 60, 60, 195, 60, 195, 118}; - icon_draw_rect_input_line_prim( - &rect, color, GPU_PRIM_LINE_STRIP, (const void *)lines, ARRAY_SIZE(lines) / 2); + icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x90, 0xa3, 0x0}); } } diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 52696475c20..64c0e11976b 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1067,7 +1067,7 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C, PropertyRNA **r_prop, bool *r_is_undo) { - ARegion *ar = CTX_wm_region(C); + ARegion *ar = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C); uiBlock *block; uiBut *but, *prevbut = NULL; @@ -1241,17 +1241,19 @@ static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but char direction = UI_DIR_DOWN; if (!but->drawstr[0]) { - if (butregion->alignment == RGN_ALIGN_LEFT) { - direction = UI_DIR_RIGHT; - } - else if (butregion->alignment == RGN_ALIGN_RIGHT) { - direction = UI_DIR_LEFT; - } - else if (butregion->alignment == RGN_ALIGN_BOTTOM) { - direction = UI_DIR_UP; - } - else { - direction = UI_DIR_DOWN; + switch (RGN_ALIGN_ENUM_FROM_MASK(butregion->alignment)) { + case RGN_ALIGN_LEFT: + direction = UI_DIR_RIGHT; + break; + case RGN_ALIGN_RIGHT: + direction = UI_DIR_LEFT; + break; + case RGN_ALIGN_BOTTOM: + direction = UI_DIR_UP; + break; + default: + direction = UI_DIR_DOWN; + break; } } UI_block_direction_set(block, direction); @@ -2436,6 +2438,10 @@ void uiItemEnumR_string_prop(uiLayout *layout, } for (a = 0; item[a].identifier; a++) { + if (item[a].identifier[0] == '\0') { + /* Skip enum item separators. */ + continue; + } if (item[a].value == ivalue) { const char *item_name = name ? name : diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 8adb82a22c8..cc1b7187e45 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -131,7 +131,7 @@ typedef enum eSpaceButtons_Align { BUT_AUTO = 2, } eSpaceButtons_Align; -static int panel_aligned(ScrArea *sa, ARegion *ar) +static int panel_aligned(const ScrArea *sa, const ARegion *ar) { if (sa->spacetype == SPACE_PROPERTIES && ar->regiontype == RGN_TYPE_WINDOW) { return BUT_VERTICAL; @@ -367,7 +367,19 @@ Panel *UI_panel_begin( return pa; } -void UI_panel_end(uiBlock *block, int width, int height, bool open) +static float panel_region_offset_x_get(const ARegion *ar, int align) +{ + if (UI_panel_category_is_visible(ar)) { + if (align == BUT_VERTICAL && (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) != RGN_ALIGN_RIGHT)) { + return UI_PANEL_CATEGORY_MARGIN_WIDTH; + } + } + + return 0; +} + +void UI_panel_end( + const ScrArea *sa, const ARegion *ar, uiBlock *block, int width, int height, bool open) { Panel *pa = block->panel; @@ -391,6 +403,7 @@ void UI_panel_end(uiBlock *block, int width, int height, bool open) } else { int old_sizex = pa->sizex, old_sizey = pa->sizey; + int old_region_ofsx = pa->runtime.region_ofsx; /* update width/height if non-zero */ if (width != 0) { @@ -405,6 +418,11 @@ void UI_panel_end(uiBlock *block, int width, int height, bool open) pa->runtime_flag |= PNL_ANIM_ALIGN; pa->ofsy += old_sizey - pa->sizey; } + + int align = panel_aligned(sa, ar); + if (old_region_ofsx != panel_region_offset_x_get(ar, align)) { + pa->runtime_flag |= PNL_ANIM_ALIGN; + } } } @@ -1004,7 +1022,6 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo int a, tot = 0; bool done; int align = panel_aligned(sa, ar); - bool has_category_tabs = UI_panel_category_is_visible(ar); /* count active, not tabbed panels */ for (pa = ar->panels.first; pa; pa = pa->next) { @@ -1061,14 +1078,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* no smart other default start loc! this keeps switching f5/f6/etc compatible */ ps = panelsort; + ps->pa->runtime.region_ofsx = panel_region_offset_x_get(ar, align); ps->pa->ofsx = 0; ps->pa->ofsy = -get_panel_size_y(ps->pa); - - if (has_category_tabs) { - if (align == BUT_VERTICAL && (ar->alignment != RGN_ALIGN_RIGHT)) { - ps->pa->ofsx += UI_PANEL_CATEGORY_MARGIN_WIDTH; - } - } + ps->pa->ofsx += ps->pa->runtime.region_ofsx; for (a = 0; a < tot - 1; a++, ps++) { psnext = ps + 1; @@ -1913,7 +1926,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) { /* no tab outlines for */ // #define USE_FLAT_INACTIVE - const bool is_left = (ar->alignment != RGN_ALIGN_RIGHT); + const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment != RGN_ALIGN_RIGHT); View2D *v2d = &ar->v2d; uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; @@ -2201,7 +2214,7 @@ static int ui_handle_panel_category_cycling(const wmEvent *event, { const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE); const bool inside_tabregion = - ((ar->alignment != RGN_ALIGN_RIGHT) ? + ((RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) != RGN_ALIGN_RIGHT) ? (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax) : (event->mval[0] > ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmin)); diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c index fa471441cc9..d32cd5c17e2 100644 --- a/source/blender/editors/interface/interface_region_hud.c +++ b/source/blender/editors/interface/interface_region_hud.c @@ -364,7 +364,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa) ED_area_update_region_sizes(wm, win, sa); } - ED_region_init(ar); + ED_region_floating_initialize(ar); ED_region_tag_redraw(ar); /* Reset zoom level (not well supported). */ diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index fed3c0b3d11..560c6146afe 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -280,13 +280,13 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi ARegion *ar = CTX_wm_region(C); if (sa && ar) { if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { - if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) { + if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) { UI_block_direction_set(block, UI_DIR_UP); UI_block_order_flip(block); } } if (ar->regiontype == RGN_TYPE_FOOTER) { - if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) { + if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) { UI_block_direction_set(block, UI_DIR_UP); UI_block_order_flip(block); } diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index cd0421dde09..2042c15ed96 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -189,12 +189,12 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v /* Prefer popover from header to be positioned into the editor. */ else if (sa && ar) { if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { - if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) { + if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) { UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X); } } if (ar->regiontype == RGN_TYPE_FOOTER) { - if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) { + if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) { UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X); } } diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 63dee77e90e..867ac652505 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -524,20 +524,44 @@ void ui_popup_block_scrolltest(uiBlock *block) static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle) { - wmWindow *win = CTX_wm_window(C); + wmWindow *ctx_win = CTX_wm_window(C); + ScrArea *ctx_sa = CTX_wm_area(C); + ARegion *ctx_ar = CTX_wm_region(C); + + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = ctx_win; bScreen *sc = CTX_wm_screen(C); + /* There may actually be a different window active than the one showing the popup, so lookup real + * one. */ + if (BLI_findindex(&sc->regionbase, handle->region) == -1) { + for (win = wm->windows.first; win; win = win->next) { + sc = WM_window_get_active_screen(win); + if (BLI_findindex(&sc->regionbase, handle->region) != -1) { + break; + } + } + } + + BLI_assert(win && sc); + + CTX_wm_window_set(C, win); ui_region_temp_remove(C, sc, handle->region); + /* Reset context (area and region were NULL'ed when chaning context window). */ + CTX_wm_window_set(C, ctx_win); + CTX_wm_area_set(C, ctx_sa); + CTX_wm_region_set(C, ctx_ar); + /* reset to region cursor (only if there's not another menu open) */ if (BLI_listbase_is_empty(&sc->regionbase)) { - ED_region_cursor_set(win, CTX_wm_area(C), CTX_wm_region(C)); + ED_region_cursor_set(win, ctx_sa, ctx_ar); /* in case cursor needs to be changed again */ WM_event_add_mousemove(C); } if (handle->scrolltimer) { - WM_event_remove_timer(CTX_wm_manager(C), win, handle->scrolltimer); + WM_event_remove_timer(wm, win, handle->scrolltimer); } } @@ -728,7 +752,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, ui_popup_block_scrolltest(block); /* adds subwindow */ - ED_region_init(ar); + ED_region_floating_initialize(ar); /* get winmat now that we actually have the subwindow */ wmGetProjectionMatrix(block->winmat, &ar->winrct); diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 251bc86a3f5..94bcd6ab37d 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -639,7 +639,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but } /* adds subwindow */ - ED_region_init(ar); + ED_region_floating_initialize(ar); /* notify change and redraw */ ED_region_tag_redraw(ar); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 38c17f3c395..7a0c04be356 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -1391,7 +1391,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, } /* adds subwindow */ - ED_region_init(ar); + ED_region_floating_initialize(ar); /* notify change and redraw */ ED_region_tag_redraw(ar); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index be9071e75a1..4c86e3252ed 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6871,7 +6871,6 @@ static char *progress_tooltip_func(bContext *UNUSED(C), void *argN, const char * void uiTemplateRunningJobs(uiLayout *layout, bContext *C) { - bScreen *screen = CTX_wm_screen(C); wmWindowManager *wm = CTX_wm_manager(C); ScrArea *sa = CTX_wm_area(C); uiBlock *block; @@ -7053,7 +7052,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C) } } - if (screen->animtimer) { + if (ED_screen_animation_no_scrub(wm)) { uiDefIconTextBut(block, UI_BTYPE_BUT, B_STOPANIM, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index d313310bfa1..92032c3b18c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1742,9 +1742,8 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, strwidth = BLF_width(fstyle->uifont_id, str, max_len); if ((okwidth > 0.0f) && (strwidth > okwidth)) { - /* utf8 two-dots leader '..' (shorter than ellipsis '...'), - * some compilers complain with real literal string. */ - const char sep[] = {0xe2, 0x80, 0xA5, 0x0}; + /* Ellipsis. Some compilers complain with real literal string. */ + const char sep[] = {0xe2, 0x80, 0xA6, 0x0}; const int sep_len = sizeof(sep) - 1; const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1); float parts_strwidth; @@ -2662,10 +2661,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag) if (color_blend != NULL) { color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend); } - } - if (state & UI_ACTIVE) { - widget_active_color(&wt->wcol); + /* Add "hover" highlight. Ideally this could apply in all cases, + * even if UI_SELECT. But currently this causes some flickering + * as buttons can be created and updated without respect to mouse + * position and so can draw without UI_ACTIVE set. See D6503. */ + if (state & UI_ACTIVE) { + widget_active_color(&wt->wcol); + } } if (state & UI_BUT_REDALERT) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index f8b4d85a212..3aede744115 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -443,6 +443,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_BONE_POSE_ACTIVE: cp = ts->bone_pose_active; break; + case TH_BONE_LOCKED_WEIGHT: + cp = ts->bone_locked_weight; + break; case TH_STRIP: cp = ts->strip; break; @@ -969,6 +972,18 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_INFO_DEBUG_TEXT: cp = ts->info_debug_text; break; + case TH_INFO_PROPERTY: + cp = ts->info_property; + break; + case TH_INFO_PROPERTY_TEXT: + cp = ts->info_property_text; + break; + case TH_INFO_OPERATOR: + cp = ts->info_operator; + break; + case TH_INFO_OPERATOR_TEXT: + cp = ts->info_operator_text; + break; case TH_V3D_CLIPPING_BORDER: cp = ts->clipping_border_3d; break; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index a3f84e7bdd0..a23bd7dad35 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -354,11 +354,6 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) /* note, scroll is being flipped in ED_region_panels() drawing */ v2d->scroll |= (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE); - /* initialize without scroll bars (interferes with zoom level see: T47047) */ - if (do_init) { - v2d->scroll |= (V2D_SCROLL_VERTICAL_FULLR | V2D_SCROLL_HORIZONTAL_FULLR); - } - if (do_init) { float panelzoom = (style) ? style->panelzoom : 1.0f; diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 7582ef3f41d..9f9e523b57b 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -316,7 +316,7 @@ void WM_OT_alembic_export(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC, FILE_BLENDER, FILE_SAVE, - WM_FILESEL_FILEPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); @@ -694,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC, FILE_BLENDER, FILE_SAVE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index dad84c87fd7..3f51504d6ac 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -541,7 +541,7 @@ void WM_OT_collada_export(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE, - WM_FILESEL_FILEPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); @@ -870,7 +870,7 @@ void WM_OT_collada_import(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_OPENFILE, - WM_FILESEL_FILEPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c index ffde9f338b4..f9910f01f47 100644 --- a/source/blender/editors/mesh/editmesh_automerge.c +++ b/source/blender/editors/mesh/editmesh_automerge.c @@ -123,62 +123,10 @@ void EDBM_automerge_and_split(Object *obedit, GHash *ghash_targetmap = BMO_SLOT_AS_GHASH(slot_targetmap); - ok = BM_mesh_intersect_edges(bm, hflag, dist, ghash_targetmap); + ok = BM_mesh_intersect_edges(bm, hflag, dist, split_faces, ghash_targetmap); if (ok) { - GHashIterator gh_iter; - BMVert **v_survivors, **v_iter; - uint v_survivors_len = 0; - if (split_faces) { - BMVert *v_src, *v_dst; - GHASH_ITER (gh_iter, ghash_targetmap) { - v_src = BLI_ghashIterator_getKey(&gh_iter); - v_dst = BLI_ghashIterator_getValue(&gh_iter); - BM_elem_flag_disable(v_src, BM_ELEM_TAG); - BM_elem_flag_disable(v_dst, BM_ELEM_TAG); - } - - int v_survivors_len_max = BLI_ghash_len(ghash_targetmap); - GHASH_ITER (gh_iter, ghash_targetmap) { - v_src = BLI_ghashIterator_getKey(&gh_iter); - v_dst = BLI_ghashIterator_getValue(&gh_iter); - if (!BM_elem_flag_test(v_src, BM_ELEM_TAG)) { - BM_elem_flag_enable(v_src, BM_ELEM_TAG); - } - if (BM_elem_flag_test(v_dst, BM_ELEM_TAG)) { - v_survivors_len_max--; - } - } - - v_survivors = MEM_mallocN(sizeof(*v_survivors) * v_survivors_len_max, __func__); - v_iter = &v_survivors[0]; - GHASH_ITER (gh_iter, ghash_targetmap) { - v_dst = BLI_ghashIterator_getValue(&gh_iter); - if (!BM_elem_flag_test(v_dst, BM_ELEM_TAG)) { - *v_iter = v_dst; - v_iter++; - v_survivors_len++; - } - } - } - BMO_op_exec(bm, &weldop); - - BMEdge **edgenet = NULL; - int edgenet_alloc_len = 0; - if (split_faces) { - v_iter = &v_survivors[0]; - for (int i = v_survivors_len; i--; v_iter++) { - BM_vert_weld_linked_wire_edges_into_linked_faces( - bm, *v_iter, dist, &edgenet, &edgenet_alloc_len); - } - - MEM_freeN(v_survivors); - } - - if (edgenet) { - MEM_freeN(edgenet); - } } BMO_op_finish(bm, &weldop); diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index f19a988809a..69274f77049 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -199,7 +199,7 @@ void MESH_OT_spin(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ - RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000); + RNA_def_int(ot->srna, "steps", 12, 0, 1000000, "Steps", "Steps", 0, 1000); prop = RNA_def_boolean(ot->srna, "dupli", 0, "Use Duplicates", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 6c65da3ee48..f55a4c7f5f9 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -603,27 +603,8 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op) copy_v3_fl(ob->scale, radius); probe = (LightProbe *)ob->data; - probe->type = type; - switch (type) { - case LIGHTPROBE_TYPE_GRID: - probe->distinf = 0.3f; - probe->falloff = 1.0f; - probe->clipsta = 0.01f; - break; - case LIGHTPROBE_TYPE_PLANAR: - probe->distinf = 0.1f; - probe->falloff = 0.5f; - probe->clipsta = 0.001f; - ob->empty_drawsize = 0.5f; - break; - case LIGHTPROBE_TYPE_CUBE: - probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID; - break; - default: - BLI_assert(!"LightProbe type not configured."); - break; - } + BKE_lightprobe_type_set(probe, type); DEG_relations_tag_update(CTX_data_main(C)); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 8012565ba2e..34e1b3b2b4b 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op) /* Hide selected or unselected objects. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) { + if (!(base->flag & BASE_VISIBLE_VIEWLAYER)) { continue; } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index b9c89b9944f..f9e2a2b8a1a 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1758,10 +1758,10 @@ static Collection *single_object_users_collection(Main *bmain, bmain, scene, child->collection, flag, copy_collections, false); if (is_master_collection && copy_collections && child->collection != collection_child_new) { - /* We do not want a collection sync here, our collections are in a complete unsetled state - * currently. With current code, that would lead to a memory leak - because of reasons. + /* We do not want a collection sync here, our collections are in a complete uninitialized + * state currently. With current code, that would lead to a memory leak - because of reasons. * It would be a useless loss of computing anyway, since caller has to fully refresh - * viewlayers/collections caching at the end. */ + * view-layers/collections caching at the end. */ BKE_collection_child_add_no_sync(collection, collection_child_new); BLI_remlink(&collection->children, child); MEM_freeN(child); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index e8e0569f15e..05fa78aab1c 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3179,6 +3179,8 @@ static int vertex_group_lock_exec(bContext *C, wmOperator *op) vgroup_lock_all(ob, action); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index ef201603b30..7db634660af 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1141,6 +1141,9 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar) } } + /* Guard against flags slipping through that would have to be masked out in usages below. */ + BLI_assert(align1 == RGN_ALIGN_ENUM_FROM_MASK(align1)); + /* translate or close */ if (ar1) { if (align1 == RGN_ALIGN_LEFT) { @@ -1244,6 +1247,20 @@ static void region_rect_recursive( alignment = RGN_ALIGN_NONE; } + /* If both the ARegion.sizex/y and the prefsize are 0, the region is tagged as too small, even + * before the layout for dynamic regions is created. #wm_draw_window_offscreen() allows the + * layout to be created despite the RGN_FLAG_TOO_SMALL flag being set. But there may still be + * regions that don't have a separate ARegionType.layout callback. For those, set a default + * prefsize so they can become visible. */ + if ((ar->flag & RGN_FLAG_DYNAMIC_SIZE) && !(ar->type->layout)) { + if ((ar->sizex == 0) && (ar->type->prefsizex == 0)) { + ar->type->prefsizex = AREAMINX; + } + if ((ar->sizey == 0) && (ar->type->prefsizey == 0)) { + ar->type->prefsizey = HEADERY; + } + } + /* prefsize, taking into account DPI */ int prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex); int prefsizey; @@ -1323,7 +1340,7 @@ static void region_rect_recursive( else if (alignment == RGN_ALIGN_TOP || alignment == RGN_ALIGN_BOTTOM) { rcti *winrct = (ar->overlap) ? overlap_remainder : remainder; - if (rct_fits(winrct, 'v', prefsizey) < 0) { + if ((prefsizey == 0) || (rct_fits(winrct, 'v', prefsizey) < 0)) { ar->flag |= RGN_FLAG_TOO_SMALL; } else { @@ -1348,7 +1365,7 @@ static void region_rect_recursive( else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { rcti *winrct = (ar->overlap) ? overlap_remainder : remainder; - if (rct_fits(winrct, 'h', prefsizex) < 0) { + if ((prefsizex == 0) || (rct_fits(winrct, 'h', prefsizex) < 0)) { ar->flag |= RGN_FLAG_TOO_SMALL; } else { @@ -1438,9 +1455,8 @@ static void region_rect_recursive( } /* Fix any negative dimensions. This can happen when a quad split 3d view gets to small. (see - * T72200). BLI_rcti_init() sanitizes, making sure min values are <= max values. */ - BLI_rcti_init( - &ar->winrct, ar->winrct.xmin, ar->winrct.xmax, ar->winrct.ymin, ar->winrct.ymax); + * T72200). */ + BLI_rcti_sanitize(&ar->winrct); quad++; } @@ -1479,11 +1495,16 @@ static void region_rect_recursive( ar->winrct.xmin = ar->winrct.xmax; break; case RGN_ALIGN_LEFT: + ar->winrct.xmax = ar->winrct.xmin; + break; default: /* prevent winrct to be valid */ ar->winrct.xmax = ar->winrct.xmin; break; } + + /* Size on one axis is now 0, the other axis may still be invalid (negative) though. */ + BLI_rcti_sanitize(&ar->winrct); } /* restore prev-split exception */ @@ -1501,6 +1522,8 @@ static void region_rect_recursive( *overlap_remainder = *remainder; } + BLI_assert(BLI_rcti_is_valid(&ar->winrct)); + region_rect_recursive(sa, ar->next, remainder, overlap_remainder, quad); /* Tag for redraw if size changes. */ @@ -1599,11 +1622,6 @@ static void ed_default_handlers( WM_gizmomap_add_handlers(ar, ar->gizmo_map); } } - if (flag & ED_KEYMAP_TOOL) { - WM_event_add_keymap_handler_dynamic( - &ar->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa); - WM_event_add_keymap_handler_dynamic(&ar->handlers, WM_event_get_keymap_from_toolsystem, sa); - } if (flag & ED_KEYMAP_VIEW2D) { /* 2d-viewport handling+manipulation */ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0); @@ -1624,6 +1642,11 @@ static void ed_default_handlers( keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } + if (flag & ED_KEYMAP_TOOL) { + WM_event_add_keymap_handler_dynamic( + &ar->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa); + WM_event_add_keymap_handler_dynamic(&ar->handlers, WM_event_get_keymap_from_toolsystem, sa); + } if (flag & ED_KEYMAP_FRAMES) { /* frame changing/jumping (for all spaces) */ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Frames", 0, 0); @@ -1818,8 +1841,10 @@ void ED_region_update_rect(ARegion *ar) } /* externally called for floating regions like menus */ -void ED_region_init(ARegion *ar) +void ED_region_floating_initialize(ARegion *ar) { + BLI_assert(ar->alignment == RGN_ALIGN_FLOAT); + /* refresh can be called before window opened */ region_subwindow(ar); @@ -2321,7 +2346,7 @@ static void ed_panel_draw(const bContext *C, } } - UI_panel_end(block, w, h, open); + UI_panel_end(sa, ar, block, w, h, open); } /** @@ -2565,7 +2590,7 @@ void ED_region_panels_draw(const bContext *C, ARegion *ar) /* scrollers */ const rcti *mask = NULL; rcti mask_buf; - if (ar->runtime.category && (ar->alignment == RGN_ALIGN_RIGHT)) { + if (ar->runtime.category && (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT)) { UI_view2d_mask_from_win(v2d, &mask_buf); mask_buf.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH; mask = &mask_buf; @@ -3327,7 +3352,9 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect) for (; arn; arn = arn->next) { if (ar != arn && arn->overlap) { if (BLI_rcti_isect(rect, &arn->winrct, NULL)) { - if (ELEM(arn->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { + int alignment = RGN_ALIGN_ENUM_FROM_MASK(arn->alignment); + + if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { /* Overlap left, also check 1 pixel offset (2 regions on one side). */ if (ABS(rect->xmin - arn->winrct.xmin) < 2) { rect->xmin = arn->winrct.xmax; @@ -3338,7 +3365,7 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect) rect->xmax = arn->winrct.xmin; } } - else if (ELEM(arn->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { + else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { /* Same logic as above for vertical regions. */ if (ABS(rect->ymin - arn->winrct.ymin) < 2) { rect->ymin = arn->winrct.ymax; @@ -3347,7 +3374,7 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect) rect->ymax = arn->winrct.ymin; } } - else if (arn->alignment == RGN_ALIGN_FLOAT) { + else if (alignment == RGN_ALIGN_FLOAT) { /* Skip floating. */ } else { diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c index 46559efc614..942050aaffd 100644 --- a/source/blender/editors/screen/area_query.c +++ b/source/blender/editors/screen/area_query.c @@ -67,10 +67,12 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *ar, rcti *r_ar_gut if (UI_panel_category_is_visible(ar)) { const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&ar->v2d) * UI_PANEL_CATEGORY_MARGIN_WIDTH); - if (ar->alignment == RGN_ALIGN_LEFT) { + const int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment); + + if (alignment == RGN_ALIGN_LEFT) { r_ar_gutter->xmax = r_ar_gutter->xmin + category_tabs_width; } - else if (ar->alignment == RGN_ALIGN_RIGHT) { + else if (alignment == RGN_ALIGN_RIGHT) { r_ar_gutter->xmin = r_ar_gutter->xmax - category_tabs_width; } else { @@ -141,14 +143,16 @@ bool ED_region_contains_xy(const ARegion *ar, const int event_xy[2]) else { /* Side-bar & any other kind of overlapping region. */ + const int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment); + /* Check alignment to avoid region tabs being clipped out * by only clipping a single axis for aligned regions. */ - if (ELEM(ar->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { + if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { if (!ED_region_overlap_isect_x_with_margin(ar, event_xy[0], overlap_margin)) { return false; } } - else if (ELEM(ar->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { + else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { if (ED_region_panel_category_gutter_isect_xy(ar, event_xy)) { /* pass */ } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index dd09def2df6..14ea3aca623 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3643,6 +3643,15 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot) /** \name Repeat Last Operator * \{ */ +static bool repeat_history_poll(bContext *C) +{ + if (!ED_operator_screenactive(C)) { + return false; + } + wmWindowManager *wm = CTX_wm_manager(C); + return !BLI_listbase_is_empty(&wm->operators); +} + static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op)) { wmWindowManager *wm = CTX_wm_manager(C); @@ -3676,7 +3685,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) /* api callbacks */ ot->exec = repeat_last_exec; - ot->poll = ED_operator_screenactive; + ot->poll = repeat_history_poll; } /** \} */ @@ -3743,8 +3752,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) /* api callbacks */ ot->invoke = repeat_history_invoke; ot->exec = repeat_history_exec; - - ot->poll = ED_operator_screenactive; + ot->poll = repeat_history_poll; RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); } @@ -3775,8 +3783,7 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot) /* api callbacks */ ot->invoke = redo_last_invoke; - - ot->poll = ED_operator_screenactive; + ot->poll = repeat_history_poll; } /** \} */ @@ -4114,8 +4121,9 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") : - IFACE_("Flip to Top"); + const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_TOP) ? + IFACE_("Flip to Bottom") : + IFACE_("Flip to Top"); { PointerRNA ptr; RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr); @@ -4160,8 +4168,9 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") : - IFACE_("Flip to Top"); + const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_TOP) ? + IFACE_("Flip to Bottom") : + IFACE_("Flip to Top"); { PointerRNA ptr; RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr); @@ -4186,8 +4195,9 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) { const ARegion *ar = CTX_wm_region(C); - const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") : - IFACE_("Flip to Left"); + const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_LEFT) ? + IFACE_("Flip to Right") : + IFACE_("Flip to Left"); /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); @@ -4840,7 +4850,10 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even * So hiding in the temp window makes sense. */ ScrArea *area = CTX_wm_area(C); ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HEADER); + region->flag |= RGN_FLAG_HIDDEN; + ED_region_visibility_change_update(C, area, region); + return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index cafdd72c7cd..7372ea6d44a 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1512,14 +1512,9 @@ static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, P /* Truly temporary data that isn't stored in properties */ if (cache->first_time) { - if (!BKE_brush_use_locked_size(scene, brush)) { - cache->initial_radius = paint_calc_object_space_radius( - cache->vc, cache->true_location, BKE_brush_size_get(scene, brush)); - BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius); - } - else { - cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush); - } + cache->initial_radius = paint_calc_object_space_radius( + cache->vc, cache->true_location, BKE_brush_size_get(scene, brush)); + BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius); } if (BKE_brush_use_size_pressure(brush) && diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5f3992852f0..2bc36be42ab 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -3725,7 +3725,7 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) float ik_target[3]; const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - /* The pose brush applies all enabled symmetry axis in a sigle iteration, so the rest can be + /* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be * ignored. */ if (ss->cache->mirror_symmetry_pass != 0) { return; @@ -3902,7 +3902,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd, if (pose_origin) { /* Test with pose origin. Used when growing the factors to compensate the Origin Offset. */ /* Stop when the factor's avg_pos starts moving away from the origin instead of getting - * closert to it. */ + * closer to it. */ float len = len_v3v3(gftd.pos_avg, pose_origin); if (len < prev_len) { prev_len = len; @@ -8308,13 +8308,13 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C) static void SCULPT_OT_optimize(wmOperatorType *ot) { /* identifiers */ - ot->name = "Optimize"; + ot->name = "Rebuild BVH"; ot->idname = "SCULPT_OT_optimize"; ot->description = "Recalculate the sculpt BVH to improve performance"; /* api callbacks */ ot->exec = sculpt_optimize_exec; - ot->poll = sculpt_and_dynamic_topology_poll; + ot->poll = sculpt_mode_poll; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index 5ceaefd6309..5fdabea62c1 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -211,12 +211,13 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) PointerRNA ptr, idptr; PropertyRNA *prop; + bAction *oldact = NULL; + AnimData *adt = NULL; /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); if (prop) { - bAction *action = NULL, *oldact = NULL; - AnimData *adt = NULL; + /* The operator was called from a button. */ PointerRNA oldptr; oldptr = RNA_property_pointer_get(&ptr, prop); @@ -229,6 +230,13 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) else if (ptr.type == &RNA_SpaceDopeSheetEditor) { adt = ED_actedit_animdata_from_context(C); } + } + else { + adt = ED_actedit_animdata_from_context(C); + oldact = adt->action; + } + { + bAction *action = NULL; /* Perform stashing operation - But only if there is an action */ if (adt && oldact) { @@ -257,12 +265,14 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) /* create action */ action = action_create_new(C, oldact); - /* set this new action - * NOTE: we can't use actedit_change_action, as this function is also called from the NLA - */ - RNA_id_pointer_create(&action->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); - RNA_property_update(C, &ptr, prop); + if (prop) { + /* set this new action + * NOTE: we can't use actedit_change_action, as this function is also called from the NLA + */ + RNA_id_pointer_create(&action->id, &idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_update(C, &ptr, prop); + } } /* set notifier that keyframes have changed */ diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 5eac041b217..6e44992ea6e 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -488,9 +488,9 @@ static int actkeys_view_frame_exec(bContext *C, wmOperator *op) void ACTION_OT_view_frame(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Frame"; + ot->name = "Go to Current Frame"; ot->idname = "ACTION_OT_view_frame"; - ot->description = "Reset viewable area to show range around current frame"; + ot->description = "Move the view to the playhead"; /* api callbacks */ ot->exec = actkeys_view_frame_exec; diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index ca6efb5f69e..095b30aa57b 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1718,7 +1718,9 @@ static int mouse_action_keys(bAnimContext *ac, /* reset selection mode for next steps */ select_mode = SELECT_ADD; - if (wait_to_deselect_others && is_selected) { + /* Rather than deselecting others, users may want to drag to box-select (drag from empty space) + * or tweak-translate an already selected item. If these cases may apply, delay deselection. */ + if (wait_to_deselect_others && (!found || is_selected)) { ret_value = OPERATOR_RUNNING_MODAL; } else { diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 16305a9b17b..04c939ec41b 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -1083,11 +1083,7 @@ static void graph_region_draw(const bContext *C, ARegion *ar) /* scale indicators */ { rcti rect; - BLI_rcti_init(&rect, - 0, - 15 * UI_DPI_FAC, - 15 * UI_DPI_FAC, - UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y); + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT); } } diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index bf6683ffc33..ac54b1177ba 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -42,22 +42,33 @@ #include "../space_info/textview.h" -static void console_line_color(unsigned char fg[3], int type) +static int console_line_data(struct TextViewContext *tvc, + unsigned char fg[4], + unsigned char UNUSED(bg[4]), + int *UNUSED(icon), + unsigned char UNUSED(icon_fg[4]), + unsigned char UNUSED(icon_bg[4])) { - switch (type) { + ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter; + int fg_id = TH_TEXT; + + switch (cl_iter->type) { case CONSOLE_LINE_OUTPUT: - UI_GetThemeColor3ubv(TH_CONSOLE_OUTPUT, fg); + fg_id = TH_CONSOLE_OUTPUT; break; case CONSOLE_LINE_INPUT: - UI_GetThemeColor3ubv(TH_CONSOLE_INPUT, fg); + fg_id = TH_CONSOLE_INPUT; break; case CONSOLE_LINE_INFO: - UI_GetThemeColor3ubv(TH_CONSOLE_INFO, fg); + fg_id = TH_CONSOLE_INFO; break; case CONSOLE_LINE_ERROR: - UI_GetThemeColor3ubv(TH_CONSOLE_ERROR, fg); + fg_id = TH_CONSOLE_ERROR; break; } + + UI_GetThemeColor4ubv(fg_id, fg); + return TVC_LINE_FG; } void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy) @@ -137,47 +148,36 @@ static void console_cursor_wrap_offset( return; } -static int console_textview_line_color(struct TextViewContext *tvc, - unsigned char fg[3], - unsigned char UNUSED(bg[3])) +static void console_textview_draw_cursor(struct TextViewContext *tvc) { - ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter; - - /* annoying hack, to draw the prompt */ - if (tvc->iter_index == 0) { - const SpaceConsole *sc = (SpaceConsole *)tvc->arg1; - const ConsoleLine *cl = (ConsoleLine *)sc->history.last; - int offl = 0, offc = 0; - int xy[2] = {tvc->draw_rect.xmin, tvc->draw_rect.ymin}; - int pen[2]; - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - xy[1] += tvc->lheight / 6; - - console_cursor_wrap_offset(sc->prompt, tvc->columns, &offl, &offc, NULL); - console_cursor_wrap_offset(cl->line, tvc->columns, &offl, &offc, cl->line + cl->cursor); - pen[0] = tvc->cwidth * offc; - pen[1] = -2 - tvc->lheight * offl; - - console_cursor_wrap_offset(cl->line + cl->cursor, tvc->columns, &offl, &offc, NULL); - pen[1] += tvc->lheight * offl; - - /* cursor */ - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColor(TH_CONSOLE_CURSOR); - - immRectf(pos, - (xy[0] + pen[0]) - U.pixelsize, - (xy[1] + pen[1]), - (xy[0] + pen[0]) + U.pixelsize, - (xy[1] + pen[1] + tvc->lheight)); - - immUnbindProgram(); - } - - console_line_color(fg, cl_iter->type); - - return TVC_LINE_FG; + const SpaceConsole *sc = (SpaceConsole *)tvc->arg1; + const ConsoleLine *cl = (ConsoleLine *)sc->history.last; + int offl = 0, offc = 0; + int xy[2] = {tvc->draw_rect.xmin, tvc->draw_rect.ymin}; + int pen[2]; + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + xy[1] += tvc->lheight * 0.35f; + + console_cursor_wrap_offset(sc->prompt, tvc->columns, &offl, &offc, NULL); + console_cursor_wrap_offset(cl->line, tvc->columns, &offl, &offc, cl->line + cl->cursor); + pen[0] = tvc->cwidth * (offc + tvc->margin_left_chars); + pen[1] = -2 - tvc->lheight * offl; + + console_cursor_wrap_offset(cl->line + cl->cursor, tvc->columns, &offl, &offc, NULL); + pen[1] += tvc->lheight * offl; + + /* cursor */ + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CONSOLE_CURSOR); + + immRectf(pos, + (xy[0] + pen[0]) - U.pixelsize, + (xy[1] + pen[1]), + (xy[0] + pen[0]) + U.pixelsize, + (xy[1] + pen[1] + tvc->lheight)); + + immUnbindProgram(); } static void console_textview_const_colors(TextViewContext *UNUSED(tvc), unsigned char bg_sel[4]) @@ -187,11 +187,9 @@ static void console_textview_const_colors(TextViewContext *UNUSED(tvc), unsigned static void console_textview_draw_rect_calc(const ARegion *ar, rcti *draw_rect) { - const int margin = 4 * UI_DPI_FAC; - draw_rect->xmin = margin; - draw_rect->xmax = ar->winx - (margin + V2D_SCROLL_WIDTH); - draw_rect->ymin = margin; - /* No margin at the top (allow text to scroll off the window). */ + draw_rect->xmin = 0; + draw_rect->xmax = ar->winx; + draw_rect->ymin = 0; draw_rect->ymax = ar->winy; } @@ -214,7 +212,8 @@ static int console_textview_main__internal(struct SpaceConsole *sc, tvc.step = console_textview_step; tvc.line_get = console_textview_line_get; - tvc.line_color = console_textview_line_color; + tvc.line_data = console_line_data; + tvc.draw_cursor = console_textview_draw_cursor; tvc.const_colors = console_textview_const_colors; tvc.arg1 = sc; @@ -223,7 +222,9 @@ static int console_textview_main__internal(struct SpaceConsole *sc, /* view */ tvc.sel_start = sc->sel_start; tvc.sel_end = sc->sel_end; - tvc.lheight = sc->lheight * UI_DPI_FAC; + tvc.lheight = sc->lheight * 1.2f * UI_DPI_FAC; + tvc.margin_left_chars = 1; + tvc.margin_right_chars = 2; tvc.scroll_ymin = v2d->cur.ymin; tvc.scroll_ymax = v2d->cur.ymax; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index a567aeed826..800726c6fb0 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -947,15 +947,16 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index) return filelist_geticon_image_ex(file->typeflag, file->relpath); } -static int filelist_geticon_ex(const int typeflag, - const int blentype, - const char *relpath, +static int filelist_geticon_ex(FileDirEntry *file, + const char *root, const bool is_main, const bool ignore_libdir) { + const int typeflag = file->typeflag; + if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { - if (FILENAME_IS_PARENT(relpath)) { + if (FILENAME_IS_PARENT(file->relpath)) { return is_main ? ICON_FILE_PARENT : ICON_NONE; } else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) { @@ -969,6 +970,20 @@ static int filelist_geticon_ex(const int typeflag, * (e.g. when used over previews). */ return ICON_FILE_FOLDER; } + else { + /* If this path is in System list then use that icon. */ + struct FSMenu *fsmenu = ED_fsmenu_get(); + FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); + char fullpath[FILE_MAX_LIBEXTRA]; + BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); + BLI_add_slash(fullpath); + for (; tfsm; tfsm = tfsm->next) { + if (STREQ(tfsm->path, fullpath)) { + /* Never want a little folder inside a large one. */ + return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon; + } + } + } } if (typeflag & FILE_TYPE_BLENDER) { @@ -1014,7 +1029,7 @@ static int filelist_geticon_ex(const int typeflag, return ICON_FILE_ARCHIVE; } else if (typeflag & FILE_TYPE_BLENDERLIB) { - const int ret = UI_idcode_icon_get(blentype); + const int ret = UI_idcode_icon_get(file->blentype); if (ret != ICON_NONE) { return ret; } @@ -1026,7 +1041,7 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m { FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false); + return filelist_geticon_ex(file, filelist->filelist.root, is_main, false); } /* ********** Main ********** */ diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index fc03453a5cc..eaabd907f23 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -31,6 +31,8 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" +#include "BLT_translation.h" + #include "BKE_appdir.h" #include "ED_fileselect.h" @@ -270,7 +272,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, - const int icon, + int icon, FSMenuInsert flag) { FSMenuEntry *fsm_prev; @@ -311,19 +313,22 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, fsm_iter->path = BLI_strdup(path); fsm_iter->save = (flag & FS_INSERT_SAVE) != 0; - if ((category == FS_CATEGORY_RECENT) && (!name || !name[0])) { - /* Special handling when adding new recent entry - check if dir exists in - * some other categories, and try to use name from there if so. */ + /* If entry is also in another list, use that icon and maybe name. */ + if (ELEM(category, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT)) { + FSMenuCategory cats[] = { FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS}; int i = ARRAY_SIZE(cats); + if (category == FS_CATEGORY_BOOKMARKS) { + i--; + } while (i--) { FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]); - for (; tfsm; tfsm = tfsm->next) { if (STREQ(tfsm->path, fsm_iter->path)) { - if (tfsm->name[0]) { + icon = tfsm->icon; + if (tfsm->name[0] && (!name || !name[0])) { name = tfsm->name; } break; @@ -485,6 +490,25 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename) fclose(fp); } +#ifdef WIN32 +/* Add a Windows known folder path to the System list. */ +static void fsmenu_add_windows_folder(struct FSMenu *fsmenu, + REFKNOWNFOLDERID rfid, + const char *name, + const int icon, + FSMenuInsert flag) +{ + LPWSTR pPath; + char line[FILE_MAXDIR]; + if (SHGetKnownFolderPath(rfid, 0, NULL, &pPath) == S_OK) { + BLI_strncpy_wchar_as_utf8(line, pPath, FILE_MAXDIR); + CoTaskMemFree(pPath); + BLI_add_slash(line); + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, name, icon, flag); + } +} +#endif + void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) { char line[FILE_MAXDIR]; @@ -541,16 +565,24 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) } } - /* Adding Desktop and My Documents */ + /* Get Special Folder Locations. */ if (read_bookmarks) { - SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0); - BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR); - fsmenu_insert_entry( - fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DOCUMENTS, FS_INSERT_SORTED); - SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0); - BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR); - fsmenu_insert_entry( - fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DESKTOP, FS_INSERT_SORTED); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Profile, IFACE_("Home"), ICON_HOME, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Desktop, IFACE_("Desktop"), ICON_DESKTOP, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Documents, IFACE_("Documents"), ICON_DOCUMENTS, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Downloads, IFACE_("Downloads"), ICON_IMPORT, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Music, IFACE_("Music"), ICON_FILE_SOUND, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Pictures, IFACE_("Pictures"), ICON_FILE_IMAGE, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Videos, IFACE_("Videos"), ICON_FILE_MOVIE, FS_INSERT_LAST); + fsmenu_add_windows_folder( + fsmenu, &FOLDERID_Fonts, IFACE_("Fonts"), ICON_FONTPREVIEW, FS_INSERT_LAST); } } #else @@ -578,11 +610,41 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX); + /* Get name of the volume. */ + char name[FILE_MAXFILE] = ""; + CFStringRef nameString = NULL; + CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeLocalizedNameKey, &nameString, NULL); + if (nameString != NULL) { + CFStringGetCString(nameString, name, sizeof(name), kCFStringEncodingUTF8); + CFRelease(nameString); + } + + /* Set icon for regular, removable or network drive. */ + int icon = ICON_DISK_DRIVE; + CFBooleanRef localKey = NULL; + CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeIsLocalKey, &localKey, NULL); + if (localKey != NULL) { + if (!CFBooleanGetValue(localKey)) { + icon = ICON_NETWORK_DRIVE; + } + else { + CFBooleanRef ejectableKey = NULL; + CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeIsEjectableKey, &ejectableKey, NULL); + if (ejectableKey != NULL) { + if (CFBooleanGetValue(ejectableKey)) { + icon = ICON_EXTERNAL_DRIVE; + } + CFRelease(ejectableKey); + } + } + CFRelease(localKey); + } + /* Add end slash for consistency with other platforms */ BLI_add_slash(defPath); fsmenu_insert_entry( - fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED); + fsmenu, FS_CATEGORY_SYSTEM, defPath, name[0] ? name : NULL, icon, FS_INSERT_SORTED); } CFRelease(volEnum); @@ -640,13 +702,75 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) const char *home = BLI_getenv("HOME"); if (read_bookmarks && home) { + BLI_snprintf(line, sizeof(line), "%s/", home); - fsmenu_insert_entry( - fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_HOME, FS_INSERT_SORTED); - BLI_snprintf(line, sizeof(line), "%s/Desktop/", home); if (BLI_exists(line)) { fsmenu_insert_entry( - fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DESKTOP, FS_INSERT_SORTED); + fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, IFACE_("Home"), ICON_HOME, FS_INSERT_LAST); + } + + /* Follow the XDG spec, check if these are available. */ + + /* TODO: parse "$XDG_CONFIG_HOME/user-dirs.dirs" for localized paths. */ + + BLI_snprintf(line, sizeof(line), "%s/Desktop/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + line, + IFACE_("Desktop"), + ICON_DESKTOP, + FS_INSERT_LAST); + } + + BLI_snprintf(line, sizeof(line), "%s/Documents/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + line, + IFACE_("Documents"), + ICON_DOCUMENTS, + FS_INSERT_LAST); + } + + BLI_snprintf(line, sizeof(line), "%s/Downloads/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + line, + IFACE_("Downloads"), + ICON_IMPORT, + FS_INSERT_LAST); + } + + BLI_snprintf(line, sizeof(line), "%s/Videos/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + line, + IFACE_("Videos"), + ICON_FILE_MOVIE, + FS_INSERT_LAST); + } + + BLI_snprintf(line, sizeof(line), "%s/Pictures/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + line, + IFACE_("Pictures"), + ICON_FILE_IMAGE, + FS_INSERT_LAST); + } + + BLI_snprintf(line, sizeof(line), "%s/Music/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, + FS_CATEGORY_SYSTEM_BOOKMARKS, + line, + IFACE_("Music"), + ICON_FILE_SOUND, + FS_INSERT_LAST); } } diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h index a33783b1905..17cfdf1c7f0 100644 --- a/source/blender/editors/space_file/fsmenu.h +++ b/source/blender/editors/space_file/fsmenu.h @@ -42,7 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *path, const char *name, - const int icon, + int icon, const enum FSMenuInsert flag); /** Refresh 'valid' status of given menu entry */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 6c95e74e834..0a3663372be 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -156,7 +156,7 @@ static void graph_panel_properties(const bContext *C, Panel *pa) FCurve *fcu; PointerRNA fcu_ptr; uiLayout *layout = pa->layout; - uiLayout *col, *row, *sub; + uiLayout *col; char name[256]; int icon = 0; @@ -193,27 +193,26 @@ static void graph_panel_properties(const bContext *C, Panel *pa) } uiItemL(col, name, icon); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + /* RNA-Path Editing - only really should be enabled when things aren't working */ - col = uiLayoutColumn(layout, true); + col = uiLayoutColumn(layout, false); uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED) != 0); uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA); uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE); /* color settings */ col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Display Color:"), ICON_NONE); + uiItemR(col, &fcu_ptr, "color_mode", 0, "Display Color", ICON_NONE); - row = uiLayoutRow(col, true); - uiItemR(row, &fcu_ptr, "color_mode", 0, "", ICON_NONE); - - sub = uiLayoutRow(row, true); - uiLayoutSetEnabled(sub, (fcu->color_mode == FCURVE_COLOR_CUSTOM)); - uiItemR(sub, &fcu_ptr, "color", 0, "", ICON_NONE); + if (fcu->color_mode == FCURVE_COLOR_CUSTOM) { + uiItemR(col, &fcu_ptr, "color", 0, "Color", ICON_NONE); + } /* smoothing setting */ col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Auto Handle Smoothing:"), ICON_NONE); - uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "", ICON_NONE); + uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "Handle Smoothing", ICON_NONE); MEM_freeN(ale); } @@ -339,6 +338,9 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) BezTriple *bezt, *prevbezt; uiLayout *layout = pa->layout; + const ARegion *ar = CTX_wm_region(C); + /* Just a width big enough so buttons use entire layout width (will be clamped by it then). */ + const int but_max_width = ar->winx; uiLayout *col; uiBlock *block; @@ -348,6 +350,8 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) block = uiLayoutGetBlock(layout); /* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* only show this info if there are keyframes to edit */ if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) { @@ -404,57 +408,60 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) col = uiLayoutColumn(layout, true); /* keyframe itself */ { - uiItemL(col, IFACE_("Key:"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, - IFACE_("Frame:"), + "", 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "co", - 0, + 1, 0, 0, -1, -1, NULL); UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); + UI_but_unit_type_set(but, unit); + uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, - IFACE_("Value:"), + "", 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "co", - 1, + 0, 0, 0, -1, -1, NULL); UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); - UI_but_unit_type_set(but, unit); } /* previous handle - only if previous was Bezier interpolation */ if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) { - uiItemL(col, IFACE_("Left Handle:"), ICON_NONE); + col = uiLayoutColumn(layout, true); + + uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, - "X:", + "", 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "handle_left", @@ -466,13 +473,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) NULL); UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt); + uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, - "Y:", + "", 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "handle_left", @@ -485,14 +493,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt); UI_but_unit_type_set(but, unit); - /* XXX: with label? */ + uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, NULL, 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "handle_left_type", @@ -508,15 +516,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) /* next handle - only if current is Bezier interpolation */ if (bezt->ipo == BEZT_IPO_BEZ) { /* NOTE: special update callbacks are needed on the coords here due to T39911 */ - uiItemL(col, IFACE_("Right Handle:"), ICON_NONE); + col = uiLayoutColumn(layout, true); + uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, - "X:", + "", 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "handle_right", @@ -528,13 +537,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) NULL); UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt); + uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, - "Y:", + "", 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "handle_right", @@ -547,14 +557,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa) UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt); UI_but_unit_type_set(but, unit); - /* XXX: with label? */ + uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, NULL, 0, 0, - UI_UNIT_X, + but_max_width, UI_UNIT_Y, &bezt_ptr, "handle_right_type", diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 03df93e4c8a..2060288bb0e 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -292,13 +292,12 @@ static int graphkeys_viewall(bContext *C, /* Give some more space at the borders. */ BLI_rctf_scale(&cur_new, 1.1f); - /* Take regions into account, that could block the view. */ + /* Take regions into account, that could block the view. + * Marker region is supposed to be larger than the scroll-bar, so prioritize it.*/ float pad_top = UI_TIME_SCRUB_MARGIN_Y; - float pad_bottom = 0; - if (!BLI_listbase_is_empty(ED_context_get_markers(C))) { - pad_bottom = UI_MARKER_MARGIN_Y; - } - BLI_rctf_pad_y(&cur_new, ac.ar->sizey * UI_DPI_FAC, pad_bottom, pad_top); + float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ? V2D_SCROLL_HANDLE_HEIGHT : + UI_MARKER_MARGIN_Y; + BLI_rctf_pad_y(&cur_new, ac.ar->winy, pad_bottom, pad_top); UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; @@ -384,9 +383,9 @@ static int graphkeys_view_frame_exec(bContext *C, wmOperator *op) void GRAPH_OT_view_frame(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Frame"; + ot->name = "Go to Current Frame"; ot->idname = "GRAPH_OT_view_frame"; - ot->description = "Reset viewable area to show range around current frame"; + ot->description = "Move the view to the playhead"; /* api callbacks */ ot->exec = graphkeys_view_frame_exec; diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 7bc907bb3db..d01e4112fd0 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -326,11 +326,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) /* scale numbers */ { rcti rect; - BLI_rcti_init(&rect, - 0, - 15 * UI_DPI_FAC, - 15 * UI_DPI_FAC, - UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y); + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 64570459532..03ff680a93d 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -42,48 +42,78 @@ #include "textview.h" #include "GPU_framebuffer.h" -/* complicates things a bit, so leaving in old simple code */ -#define USE_INFO_NEWLINE - -static void info_report_color(unsigned char *fg, - unsigned char *bg, - Report *report, - const short do_tint) +static int report_line_data(struct TextViewContext *tvc, + unsigned char fg[4], + unsigned char bg[4], + int *icon, + unsigned char icon_fg[4], + unsigned char icon_bg[4]) { - int bg_id = TH_BACK, fg_id = TH_TEXT; - int shade = do_tint ? 0 : -6; + Report *report = (Report *)tvc->iter; - if (report->flag & SELECT) { - bg_id = TH_INFO_SELECTED; - fg_id = TH_INFO_SELECTED_TEXT; - } - else if (report->type & RPT_ERROR_ALL) { - bg_id = TH_INFO_ERROR; - fg_id = TH_INFO_ERROR_TEXT; + /* Same text color no matter what type of report. */ + UI_GetThemeColor4ubv((report->flag & SELECT) ? TH_INFO_SELECTED_TEXT : TH_TEXT, fg); + + /* Zebra striping for background. */ + int bg_id = (report->flag & SELECT) ? TH_INFO_SELECTED : TH_BACK; + int shade = tvc->iter_tmp % 2 ? 4 : -4; + UI_GetThemeColorShade4ubv(bg_id, shade, bg); + + /* Icon color and backgound depend of report type. */ + + int icon_fg_id; + int icon_bg_id; + + if (report->type & RPT_ERROR_ALL) { + icon_fg_id = TH_INFO_ERROR_TEXT; + icon_bg_id = TH_INFO_ERROR; + *icon = ICON_CANCEL; } else if (report->type & RPT_WARNING_ALL) { - bg_id = TH_INFO_WARNING; - fg_id = TH_INFO_WARNING_TEXT; + icon_fg_id = TH_INFO_WARNING_TEXT; + icon_bg_id = TH_INFO_WARNING; + *icon = ICON_ERROR; } else if (report->type & RPT_INFO_ALL) { - bg_id = TH_INFO_INFO; - fg_id = TH_INFO_INFO_TEXT; + icon_fg_id = TH_INFO_INFO_TEXT; + icon_bg_id = TH_INFO_INFO; + *icon = ICON_INFO; } else if (report->type & RPT_DEBUG_ALL) { - bg_id = TH_INFO_DEBUG; - fg_id = TH_INFO_DEBUG_TEXT; + icon_fg_id = TH_INFO_DEBUG_TEXT; + icon_bg_id = TH_INFO_DEBUG; + *icon = ICON_SYSTEM; + } + else if (report->type & RPT_PROPERTY) { + icon_fg_id = TH_INFO_PROPERTY_TEXT; + icon_bg_id = TH_INFO_PROPERTY; + *icon = ICON_OPTIONS; + } + else if (report->type & RPT_OPERATOR) { + icon_fg_id = TH_INFO_OPERATOR_TEXT; + icon_bg_id = TH_INFO_OPERATOR; + *icon = ICON_CHECKMARK; } else { - bg_id = TH_BACK; - fg_id = TH_TEXT; + *icon = ICON_NONE; } - UI_GetThemeColorShade3ubv(bg_id, shade, bg); - UI_GetThemeColor3ubv(fg_id, fg); + if (report->flag & SELECT) { + icon_fg_id = TH_INFO_SELECTED; + icon_bg_id = TH_INFO_SELECTED_TEXT; + } + + if (*icon != ICON_NONE) { + UI_GetThemeColor4ubv(icon_fg_id, icon_fg); + UI_GetThemeColor4ubv(icon_bg_id, icon_bg); + return TVC_LINE_FG | TVC_LINE_BG | TVC_LINE_ICON | TVC_LINE_ICON_FG | TVC_LINE_ICON_BG; + } + else { + return TVC_LINE_FG | TVC_LINE_BG; + } } /* reports! */ -#ifdef USE_INFO_NEWLINE static void report_textview_init__internal(TextViewContext *tvc) { Report *report = (Report *)tvc->iter; @@ -108,14 +138,11 @@ static int report_textview_skip__internal(TextViewContext *tvc) return (tvc->iter != NULL); } -#endif // USE_INFO_NEWLINE - static int report_textview_begin(TextViewContext *tvc) { - // SpaceConsole *sc = (SpaceConsole *)tvc->arg1; ReportList *reports = (ReportList *)tvc->arg2; - tvc->lheight = 14 * UI_DPI_FAC; // sc->lheight; + tvc->lheight = 14 * UI_DPI_FAC; tvc->sel_start = 0; tvc->sel_end = 0; @@ -125,7 +152,6 @@ static int report_textview_begin(TextViewContext *tvc) UI_ThemeClearColor(TH_BACK); GPU_clear(GPU_COLOR_BIT); -#ifdef USE_INFO_NEWLINE tvc->iter_tmp = 0; if (tvc->iter && report_textview_skip__internal(tvc)) { /* init the newline iterator */ @@ -137,9 +163,6 @@ static int report_textview_begin(TextViewContext *tvc) else { return false; } -#else - return (tvc->iter != NULL); -#endif } static void report_textview_end(TextViewContext *UNUSED(tvc)) @@ -147,7 +170,6 @@ static void report_textview_end(TextViewContext *UNUSED(tvc)) /* pass */ } -#ifdef USE_INFO_NEWLINE static int report_textview_step(TextViewContext *tvc) { /* simple case, but no newline support */ @@ -184,57 +206,11 @@ static int report_textview_line_get(struct TextViewContext *tvc, const char **li return 1; } -static int report_textview_line_color(struct TextViewContext *tvc, - unsigned char fg[3], - unsigned char bg[3]) -{ - Report *report = (Report *)tvc->iter; - info_report_color(fg, bg, report, tvc->iter_tmp % 2); - return TVC_LINE_FG | TVC_LINE_BG; -} - -#else // USE_INFO_NEWLINE - -static int report_textview_step(TextViewContext *tvc) -{ - SpaceInfo *sinfo = (SpaceInfo *)tvc->arg1; - const int report_mask = info_report_mask(sinfo); - do { - tvc->iter = (void *)((Link *)tvc->iter)->prev; - } while (tvc->iter && (((Report *)tvc->iter)->type & report_mask) == 0); - - return (tvc->iter != NULL); -} - -static int report_textview_line_get(struct TextViewContext *tvc, const char **line, int *len) -{ - Report *report = (Report *)tvc->iter; - *line = report->message; - *len = report->len; - - return 1; -} - -static int report_textview_line_color(struct TextViewContext *tvc, - unsigned char fg[3], - unsigned char bg[3]) -{ - Report *report = (Report *)tvc->iter; - info_report_color(fg, bg, report, tvc->iter_tmp % 2); - return TVC_LINE_FG | TVC_LINE_BG; -} - -#endif // USE_INFO_NEWLINE - -#undef USE_INFO_NEWLINE - static void info_textview_draw_rect_calc(const ARegion *ar, rcti *draw_rect) { - const int margin = 4 * UI_DPI_FAC; - draw_rect->xmin = margin; - draw_rect->xmax = ar->winx - (V2D_SCROLL_WIDTH + margin); - draw_rect->ymin = margin; - /* No margin at the top (allow text to scroll off the window). */ + draw_rect->xmin = 0; + draw_rect->xmax = ar->winx; + draw_rect->ymin = 0; draw_rect->ymax = ar->winy; } @@ -256,7 +232,7 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo, tvc.step = report_textview_step; tvc.line_get = report_textview_line_get; - tvc.line_color = report_textview_line_color; + tvc.line_data = report_line_data; tvc.const_colors = NULL; tvc.arg1 = sinfo; @@ -265,7 +241,10 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo, /* view */ tvc.sel_start = 0; tvc.sel_end = 0; - tvc.lheight = 14 * UI_DPI_FAC; // sc->lheight; + tvc.lheight = 17 * UI_DPI_FAC; + tvc.row_vpadding = 0.4 * tvc.lheight; + tvc.margin_left_chars = 5; + tvc.margin_right_chars = 2; tvc.scroll_ymin = v2d->cur.ymin; tvc.scroll_ymax = v2d->cur.ymax; diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 1bc583461a5..c145f5d333f 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -35,12 +35,16 @@ #include "GPU_immediate.h" #include "GPU_state.h" +#include "BKE_report.h" +#include "UI_interface.h" +#include "UI_interface_icons.h" + #include "textview.h" static void console_font_begin(const int font_id, const int lheight) { - /* 0.875 is based on: 16 pixels lines get 14 pixel text. */ - BLF_size(font_id, 0.875 * lheight, 72); + /* Font size in relation to line height. */ + BLF_size(font_id, 0.8f * lheight, 72); } typedef struct TextViewDrawState { @@ -49,6 +53,9 @@ typedef struct TextViewDrawState { int lheight; /** Text vertical offset per line. */ int lofs; + int margin_left_chars; + int margin_right_chars; + int row_vpadding; /** Number of characters that fit into the width of the console (fixed width). */ int columns; const rcti *draw_rect; @@ -68,16 +75,19 @@ BLI_INLINE void console_step_sel(TextViewDrawState *tds, const int step) } static void console_draw_sel(const char *str, - const int sel[2], const int xy[2], const int str_len_draw, - const int cwidth, - const int lheight, + TextViewDrawState *tds, const unsigned char bg_sel[4]) { + const int sel[2] = {tds->sel[0], tds->sel[1]}; + const int cwidth = tds->cwidth; + const int lheight = tds->lheight; + if (sel[0] <= str_len_draw && sel[1] >= 0) { - const int sta = BLI_str_utf8_offset_to_column(str, max_ii(sel[0], 0)); - const int end = BLI_str_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw)); + const int sta = BLI_str_utf8_offset_to_column(str, max_ii(sel[0], 0)) + tds->margin_left_chars; + const int end = BLI_str_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw)) + + tds->margin_left_chars; GPU_blend(true); GPU_blend_set_func_separate( @@ -134,20 +144,31 @@ static int console_wrap_offsets(const char *str, int len, int width, int *lines, static bool console_draw_string(TextViewDrawState *tds, const char *str, int str_len, - const unsigned char fg[3], - const unsigned char bg[3], + const unsigned char fg[4], + const unsigned char bg[4], + int icon, + const unsigned char icon_fg[4], + const unsigned char icon_bg[4], const unsigned char bg_sel[4]) { int tot_lines; /* Total number of lines for wrapping. */ int *offsets; /* Offsets of line beginnings for wrapping. */ - int y_next; - str_len = console_wrap_offsets(str, str_len, tds->columns, &tot_lines, &offsets); - y_next = tds->xy[1] + tds->lheight * tot_lines; + str_len = console_wrap_offsets(str, + str_len, + tds->columns - (tds->margin_left_chars + tds->margin_right_chars), + &tot_lines, + &offsets); + + int line_height = (tot_lines * tds->lheight) + (tds->row_vpadding * 2); + int line_bottom = tds->xy[1]; + int line_top = line_bottom + line_height; + + int y_next = line_top; /* Just advance the height. */ if (tds->do_draw == false) { - if (tds->mval_pick_offset && tds->mval[1] != INT_MAX && tds->xy[1] <= tds->mval[1]) { + if (tds->mval_pick_offset && tds->mval[1] != INT_MAX && line_bottom <= tds->mval[1]) { if (y_next >= tds->mval[1]) { int ofs = 0; @@ -186,107 +207,111 @@ static bool console_draw_string(TextViewDrawState *tds, return true; } - /* Check if we need to wrap lines. */ - if (tot_lines > 1) { - const int initial_offset = offsets[tot_lines - 1]; - size_t len = str_len - initial_offset; - const char *s = str + initial_offset; - int i; - - int sel_orig[2]; - copy_v2_v2_int(sel_orig, tds->sel); - - /* Invert and swap for wrapping. */ - tds->sel[0] = str_len - sel_orig[1]; - tds->sel[1] = str_len - sel_orig[0]; - - if (bg) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - immUniformColor3ubv(bg); - immRecti( - pos, 0, tds->xy[1], tds->draw_rect->xmax, (tds->xy[1] + (tds->lheight * tot_lines))); - - immUnbindProgram(); - } - - /* Last part needs no clipping. */ - BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0); - BLF_color3ubv(tds->font_id, fg); - BLF_draw_mono(tds->font_id, s, len, tds->cwidth); - - if (tds->sel[0] != tds->sel[1]) { - console_step_sel(tds, -initial_offset); - /* BLF_color3ub(tds->font_id, 255, 0, 0); // debug */ - console_draw_sel(s, tds->sel, tds->xy, len, tds->cwidth, tds->lheight, bg_sel); - } + size_t len; + const char *s; + int i; - tds->xy[1] += tds->lheight; + int sel_orig[2]; + copy_v2_v2_int(sel_orig, tds->sel); - for (i = tot_lines - 1; i > 0; i--) { - len = offsets[i] - offsets[i - 1]; - s = str + offsets[i - 1]; + /* Invert and swap for wrapping. */ + tds->sel[0] = str_len - sel_orig[1]; + tds->sel[1] = str_len - sel_orig[0]; - BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0); - BLF_draw_mono(tds->font_id, s, len, tds->cwidth); + if (bg) { + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(bg); + immRecti(pos, 0, line_bottom, tds->draw_rect->xmax, line_top); + immUnbindProgram(); + } - if (tds->sel[0] != tds->sel[1]) { - console_step_sel(tds, len); - /* BLF_color3ub(tds->font_id, 0, 255, 0); // debug */ - console_draw_sel(s, tds->sel, tds->xy, len, tds->cwidth, tds->lheight, bg_sel); - } + if (icon_bg) { + float col[4]; + int bg_size = 20 * UI_DPI_FAC; + float vpadding = (tds->lheight + (tds->row_vpadding * 2) - bg_size) / 2; + float hpadding = ((tds->margin_left_chars * tds->cwidth) - bg_size) / 2; + + rgba_uchar_to_float(col, icon_bg); + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa(true, + hpadding, + line_top - bg_size - vpadding, + bg_size + hpadding, + line_top - vpadding, + 4 * UI_DPI_FAC, + col); + } - tds->xy[1] += tds->lheight; + if (icon) { + int vpadding = (tds->lheight + (tds->row_vpadding * 2) - UI_DPI_ICON_SIZE) / 2; + int hpadding = ((tds->margin_left_chars * tds->cwidth) - UI_DPI_ICON_SIZE) / 2; - /* Check if were out of view bounds. */ - if (tds->xy[1] > tds->scroll_ymax) { - MEM_freeN(offsets); - return false; - } - } + GPU_blend(true); + UI_icon_draw_ex(hpadding, + line_top - UI_DPI_ICON_SIZE - vpadding, + icon, + (16 / UI_DPI_ICON_SIZE), + 1.0f, + 0.0f, + icon_fg, + false); + GPU_blend(false); + } - copy_v2_v2_int(tds->sel, sel_orig); - console_step_sel(tds, -(str_len + 1)); + tds->xy[1] += tds->row_vpadding; + + /* Last part needs no clipping. */ + const int final_offset = offsets[tot_lines - 1]; + len = str_len - final_offset; + s = str + final_offset; + BLF_position(tds->font_id, + tds->xy[0] + (tds->margin_left_chars * tds->cwidth), + tds->lofs + line_bottom + tds->row_vpadding, + 0); + BLF_color4ubv(tds->font_id, fg); + BLF_draw_mono(tds->font_id, s, len, tds->cwidth); + + if (tds->sel[0] != tds->sel[1]) { + console_step_sel(tds, -final_offset); + int pos[2] = {tds->xy[0], line_bottom}; + console_draw_sel(s, pos, len, tds, bg_sel); } - else { - /* Simple, no wrap. */ - if (bg) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + tds->xy[1] += tds->lheight; - immUniformColor3ubv(bg); - immRecti(pos, 0, tds->xy[1], tds->draw_rect->xmax, tds->xy[1] + tds->lheight); + BLF_color4ubv(tds->font_id, fg); - immUnbindProgram(); - } + for (i = tot_lines - 1; i > 0; i--) { + len = offsets[i] - offsets[i - 1]; + s = str + offsets[i - 1]; - BLF_color3ubv(tds->font_id, fg); - BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0); - BLF_draw_mono(tds->font_id, str, str_len, tds->cwidth); + BLF_position(tds->font_id, + tds->xy[0] + (tds->margin_left_chars * tds->cwidth), + tds->lofs + tds->xy[1], + 0); + BLF_draw_mono(tds->font_id, s, len, tds->cwidth); if (tds->sel[0] != tds->sel[1]) { - int isel[2]; - - isel[0] = str_len - tds->sel[1]; - isel[1] = str_len - tds->sel[0]; - - /* BLF_color3ub(tds->font_id, 255, 255, 0); // debug */ - console_draw_sel(str, isel, tds->xy, str_len, tds->cwidth, tds->lheight, bg_sel); - console_step_sel(tds, -(str_len + 1)); + console_step_sel(tds, len); + console_draw_sel(s, tds->xy, len, tds, bg_sel); } tds->xy[1] += tds->lheight; + /* Check if were out of view bounds. */ if (tds->xy[1] > tds->scroll_ymax) { MEM_freeN(offsets); return false; } } + tds->xy[1] = y_next; + + copy_v2_v2_int(tds->sel, sel_orig); + console_step_sel(tds, -(str_len + 1)); + MEM_freeN(offsets); return true; } @@ -310,7 +335,8 @@ int textview_draw(TextViewContext *tvc, int xy[2]; /* Disable selection by. */ int sel[2] = {-1, -1}; - unsigned char fg[3], bg[3]; + unsigned char fg[4], bg[4], icon_fg[4], icon_bg[4]; + int icon = 0; const int font_id = blf_mono_font; console_font_begin(font_id, tvc->lheight); @@ -338,6 +364,9 @@ int textview_draw(TextViewContext *tvc, tds.cwidth = (int)BLF_fixed_width(font_id); BLI_assert(tds.cwidth > 0); tds.lheight = tvc->lheight; + tds.margin_left_chars = tvc->margin_left_chars; + tds.margin_right_chars = tvc->margin_right_chars; + tds.row_vpadding = tvc->row_vpadding; tds.lofs = -BLF_descender(font_id); /* Note, scroll bar must be already subtracted. */ tds.columns = (tvc->draw_rect.xmax - tvc->draw_rect.xmin) / tds.cwidth; @@ -374,12 +403,12 @@ int textview_draw(TextViewContext *tvc, do { const char *ext_line; int ext_len; - int color_flag = 0; + int data_flag = 0; const int y_prev = xy[1]; if (do_draw) { - color_flag = tvc->line_color(tvc, fg, bg); + data_flag = tvc->line_data(tvc, fg, bg, &icon, icon_fg, icon_bg); } tvc->line_get(tvc, &ext_line, &ext_len); @@ -387,8 +416,11 @@ int textview_draw(TextViewContext *tvc, if (!console_draw_string(&tds, ext_line, ext_len, - (color_flag & TVC_LINE_FG) ? fg : NULL, - (color_flag & TVC_LINE_BG) ? bg : NULL, + (data_flag & TVC_LINE_FG) ? fg : NULL, + (data_flag & TVC_LINE_BG) ? bg : NULL, + (data_flag & TVC_LINE_ICON) ? icon : 0, + (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL, + (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL, bg_sel)) { /* When drawing, if we pass v2d->cur.ymax, then quit. */ if (do_draw) { @@ -397,6 +429,12 @@ int textview_draw(TextViewContext *tvc, } } + if (do_draw) { + if (tvc->draw_cursor && tvc->iter_index == 0) { + tvc->draw_cursor(tvc); + } + } + if ((mval[1] != INT_MAX) && (mval[1] >= y_prev && mval[1] <= xy[1])) { *r_mval_pick_item = (void *)tvc->iter; break; diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index 578236bbd13..3f7ba9739c4 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -31,6 +31,10 @@ typedef struct TextViewContext { int cwidth; /* shouldnt be needed! */ int columns; /* shouldnt be needed! */ + int row_vpadding; + int margin_left_chars; + int margin_right_chars; + /** Area to draw: (0, 0, winx, winy) with a margin applied and scroll-bar subtracted. */ rcti draw_rect; @@ -46,7 +50,13 @@ typedef struct TextViewContext { /* iterator */ int (*step)(struct TextViewContext *tvc); int (*line_get)(struct TextViewContext *tvc, const char **, int *); - int (*line_color)(struct TextViewContext *tvc, unsigned char fg[3], unsigned char bg[3]); + int (*line_data)(struct TextViewContext *tvc, + unsigned char fg[4], + unsigned char bg[4], + int *icon, + unsigned char icon_fg[4], + unsigned char icon_bg[4]); + void (*draw_cursor)(struct TextViewContext *tvc); /* constant theme colors */ void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]); void *iter; @@ -66,7 +76,12 @@ int textview_draw(struct TextViewContext *tvc, void **r_mval_pick_item, int *r_mval_pick_offset); -#define TVC_LINE_FG (1 << 0) -#define TVC_LINE_BG (1 << 1) +enum { + TVC_LINE_FG = (1 << 0), + TVC_LINE_BG = (1 << 1), + TVC_LINE_ICON = (1 << 2), + TVC_LINE_ICON_FG = (1 << 3), + TVC_LINE_ICON_BG = (1 << 4) +}; #endif /* __TEXTVIEW_H__ */ diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index b908ed2b7ee..4277e579274 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -193,12 +193,6 @@ static bool nla_animdata_panel_poll(const bContext *C, PanelType *UNUSED(pt)) return (nla_panel_context(C, &ptr, NULL, NULL) && (ptr.data != NULL)); } -static bool nla_track_panel_poll(const bContext *C, PanelType *UNUSED(pt)) -{ - PointerRNA ptr; - return (nla_panel_context(C, NULL, &ptr, NULL) && (ptr.data != NULL)); -} - static bool nla_strip_panel_poll(const bContext *C, PanelType *UNUSED(pt)) { PointerRNA ptr; @@ -262,6 +256,8 @@ static void nla_panel_animdata(const bContext *C, Panel *pa) block = uiLayoutGetBlock(layout); UI_block_func_handle_set(block, do_nla_region_buttons, NULL); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* AnimData Source Properties ----------------------------------- */ @@ -301,36 +297,53 @@ static void nla_panel_animdata(const bContext *C, Panel *pa) /* extrapolation */ row = uiLayoutRow(layout, true); - uiItemR(row, &adt_ptr, "action_extrapolation", 0, NULL, ICON_NONE); + uiItemR(row, &adt_ptr, "action_extrapolation", 0, IFACE_("Extrapolation"), ICON_NONE); /* blending */ row = uiLayoutRow(layout, true); - uiItemR(row, &adt_ptr, "action_blend_type", 0, NULL, ICON_NONE); + uiItemR(row, &adt_ptr, "action_blend_type", 0, IFACE_("Blending"), ICON_NONE); /* influence */ row = uiLayoutRow(layout, true); - uiItemR(row, &adt_ptr, "action_influence", 0, NULL, ICON_NONE); + uiItemR(row, &adt_ptr, "action_influence", 0, IFACE_("Influence"), ICON_NONE); } -/* active NLA-Track */ -static void nla_panel_track(const bContext *C, Panel *pa) +/* generic settings for active NLA-Strip */ +static void nla_panel_stripname(const bContext *C, Panel *pa) { - PointerRNA nlt_ptr; + PointerRNA strip_ptr; uiLayout *layout = pa->layout; uiLayout *row; uiBlock *block; - /* check context and also validity of pointer */ - if (!nla_panel_context(C, NULL, &nlt_ptr, NULL)) { + if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) { return; } block = uiLayoutGetBlock(layout); UI_block_func_handle_set(block, do_nla_region_buttons, NULL); - /* Info - Active NLA-Context:Track ---------------------- */ - row = uiLayoutRow(layout, true); - uiItemR(row, &nlt_ptr, "name", 0, NULL, ICON_NLA); + /* Strip Properties ------------------------------------- */ + /* strip type */ + row = uiLayoutRow(layout, false); + if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_CLIP) { + uiItemL(row, "", ICON_ANIM); + } + else if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_TRANSITION) { + uiItemL(row, "", ICON_ARROW_LEFTRIGHT); + } + else if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_META) { + uiItemL(row, "", ICON_SEQ_STRIP_META); + } + else if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_SOUND) { + uiItemL(row, "", ICON_SOUND); + } + + uiItemR(row, &strip_ptr, "name", 0, "", ICON_NLA); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiItemR(row, &strip_ptr, "mute", 0, "", ICON_NONE); + UI_block_emboss_set(block, UI_EMBOSS); } /* generic settings for active NLA-Strip */ @@ -338,7 +351,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa) { PointerRNA strip_ptr; uiLayout *layout = pa->layout; - uiLayout *column, *row, *sub; + uiLayout *column; uiBlock *block; short showEvalProps = 1; @@ -351,15 +364,14 @@ static void nla_panel_properties(const bContext *C, Panel *pa) /* Strip Properties ------------------------------------- */ /* strip type */ - row = uiLayoutColumn(layout, true); - uiItemR(row, &strip_ptr, "name", 0, NULL, ICON_NLA); // XXX icon? - uiItemR(row, &strip_ptr, "type", 0, NULL, ICON_NONE); + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* strip extents */ column = uiLayoutColumn(layout, true); - uiItemL(column, IFACE_("Strip Extents:"), ICON_NONE); - uiItemR(column, &strip_ptr, "frame_start", 0, NULL, ICON_NONE); - uiItemR(column, &strip_ptr, "frame_end", 0, NULL, ICON_NONE); + uiItemR(column, &strip_ptr, "frame_start", 0, IFACE_("Frame Start"), ICON_NONE); + uiItemR(column, &strip_ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); /* Evaluation-Related Strip Properties ------------------ */ @@ -371,33 +383,35 @@ static void nla_panel_properties(const bContext *C, Panel *pa) /* only show if allowed to... */ if (showEvalProps) { /* extrapolation */ - row = uiLayoutRow(layout, true); - uiItemR(row, &strip_ptr, "extrapolation", 0, NULL, ICON_NONE); - - /* blending */ - row = uiLayoutRow(layout, true); - uiItemR(row, &strip_ptr, "blend_type", 0, NULL, ICON_NONE); + column = uiLayoutColumn(layout, false); + uiItemR(column, &strip_ptr, "extrapolation", 0, NULL, ICON_NONE); + uiItemR(column, &strip_ptr, "blend_type", 0, NULL, ICON_NONE); /* Blend in/out + auto-blending: * - blend in/out can only be set when autoblending is off */ + + uiItemS(layout); + + column = uiLayoutColumn(layout, true); + uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_auto_blend") == false); + uiItemR(column, &strip_ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE); + uiItemR(column, &strip_ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); + column = uiLayoutColumn(layout, true); uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false); uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle? - sub = uiLayoutColumn(column, true); - uiLayoutSetActive(sub, RNA_boolean_get(&strip_ptr, "use_auto_blend") == false); - uiItemR(sub, &strip_ptr, "blend_in", 0, NULL, ICON_NONE); - uiItemR(sub, &strip_ptr, "blend_out", 0, NULL, ICON_NONE); + uiItemS(layout); /* settings */ column = uiLayoutColumn(layout, true); uiLayoutSetActive(column, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || RNA_boolean_get(&strip_ptr, "use_animated_time"))); - uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE); - uiItemR(column, &strip_ptr, "mute", 0, NULL, ICON_NONE); uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE); + + uiItemR(layout, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE); } } @@ -416,6 +430,8 @@ static void nla_panel_actclip(const bContext *C, Panel *pa) block = uiLayoutGetBlock(layout); UI_block_func_handle_set(block, do_nla_region_buttons, NULL); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* Strip Properties ------------------------------------- */ /* action pointer */ @@ -425,9 +441,8 @@ static void nla_panel_actclip(const bContext *C, Panel *pa) /* action extents */ // XXX custom names were used here (to avoid the prefixes)... probably not necessary in future? column = uiLayoutColumn(layout, true); - uiItemL(column, IFACE_("Action Extents:"), ICON_NONE); - uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Start Frame"), ICON_NONE); - uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End Frame"), ICON_NONE); + uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Frame Start"), ICON_NONE); + uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End"), ICON_NONE); /* XXX: this layout may actually be too abstract and confusing, * and may be better using standard column layout. */ @@ -438,17 +453,16 @@ static void nla_panel_actclip(const bContext *C, Panel *pa) /* action usage */ column = uiLayoutColumn(layout, true); uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_time") == false); - uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE); - uiItemR(column, &strip_ptr, "scale", 0, NULL, ICON_NONE); + uiItemR(column, &strip_ptr, "scale", 0, IFACE_("Playback Scale"), ICON_NONE); uiItemR(column, &strip_ptr, "repeat", 0, NULL, ICON_NONE); } /* evaluation settings for active NLA-Strip */ -static void nla_panel_evaluation(const bContext *C, Panel *pa) +static void nla_panel_animated_influence_header(const bContext *C, Panel *pa) { PointerRNA strip_ptr; uiLayout *layout = pa->layout; - uiLayout *col, *sub; + uiLayout *col; uiBlock *block; /* check context and also validity of pointer */ @@ -460,20 +474,65 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa) UI_block_func_handle_set(block, do_nla_region_buttons, NULL); col = uiLayoutColumn(layout, true); - uiItemR(col, &strip_ptr, "use_animated_influence", 0, NULL, ICON_NONE); + uiItemR(col, &strip_ptr, "use_animated_influence", 0, "", ICON_NONE); +} - sub = uiLayoutColumn(col, true); - uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_influence")); - uiItemR(sub, &strip_ptr, "influence", 0, NULL, ICON_NONE); +/* evaluation settings for active NLA-Strip */ +static void nla_panel_evaluation(const bContext *C, Panel *pa) +{ + PointerRNA strip_ptr; + uiLayout *layout = pa->layout; + uiBlock *block; + + /* check context and also validity of pointer */ + if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) { + return; + } + + block = uiLayoutGetBlock(layout); + UI_block_func_handle_set(block, do_nla_region_buttons, NULL); + uiLayoutSetPropSep(layout, true); + + uiLayoutSetEnabled(layout, RNA_boolean_get(&strip_ptr, "use_animated_influence")); + uiItemR(layout, &strip_ptr, "influence", 0, NULL, ICON_NONE); +} + +static void nla_panel_animated_strip_time_header(const bContext *C, Panel *pa) +{ + PointerRNA strip_ptr; + uiLayout *layout = pa->layout; + uiLayout *col; + uiBlock *block; + + /* check context and also validity of pointer */ + if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) { + return; + } + + block = uiLayoutGetBlock(layout); + UI_block_func_handle_set(block, do_nla_region_buttons, NULL); col = uiLayoutColumn(layout, true); - sub = uiLayoutRow(col, false); - uiItemR(sub, &strip_ptr, "use_animated_time", 0, NULL, ICON_NONE); - uiItemR(sub, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE); + uiItemR(col, &strip_ptr, "use_animated_time", 0, "", ICON_NONE); +} + +static void nla_panel_animated_strip_time(const bContext *C, Panel *pa) +{ + PointerRNA strip_ptr; + uiLayout *layout = pa->layout; + uiBlock *block; - sub = uiLayoutRow(col, false); - uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_time")); - uiItemR(sub, &strip_ptr, "strip_time", 0, NULL, ICON_NONE); + /* check context and also validity of pointer */ + if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) { + return; + } + + block = uiLayoutGetBlock(layout); + UI_block_func_handle_set(block, do_nla_region_buttons, NULL); + uiLayoutSetPropSep(layout, true); + + uiLayoutSetEnabled(layout, RNA_boolean_get(&strip_ptr, "use_animated_time")); + uiItemR(layout, &strip_ptr, "strip_time", 0, NULL, ICON_NONE); } /* F-Modifiers for active NLA-Strip */ @@ -527,26 +586,27 @@ void nla_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata"); strcpy(pt->idname, "NLA_PT_animdata"); strcpy(pt->label, N_("Animation Data")); - strcpy(pt->category, "Animations"); + strcpy(pt->category, "Edited Action"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->flag = PNL_NO_HEADER; pt->draw = nla_panel_animdata; pt->poll = nla_animdata_panel_poll; - pt->flag = PNL_DEFAULT_CLOSED; BLI_addtail(&art->paneltypes, pt); - pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track"); - strcpy(pt->idname, "NLA_PT_track"); - strcpy(pt->label, N_("Active Track")); - strcpy(pt->category, "Animations"); + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); + strcpy(pt->idname, "NLA_PT_stripname"); + strcpy(pt->label, N_("Active Strip Name")); + strcpy(pt->category, "Strip"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = nla_panel_track; - pt->poll = nla_track_panel_poll; + pt->flag = PNL_NO_HEADER; + pt->draw = nla_panel_stripname; + pt->poll = nla_strip_panel_poll; BLI_addtail(&art->paneltypes, pt); - pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); + PanelType *pt_properties = pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_properties"); strcpy(pt->label, N_("Active Strip")); - strcpy(pt->category, "Animations"); + strcpy(pt->category, "Strip"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_properties; pt->poll = nla_strip_panel_poll; @@ -555,19 +615,39 @@ void nla_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_actionclip"); strcpy(pt->label, N_("Action Clip")); - strcpy(pt->category, "Animations"); + strcpy(pt->category, "Strip"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_actclip; + pt->flag = PNL_DEFAULT_CLOSED; pt->poll = nla_strip_actclip_panel_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation"); strcpy(pt->idname, "NLA_PT_evaluation"); - strcpy(pt->label, N_("Evaluation")); - strcpy(pt->category, "Animations"); + strcpy(pt->parent_id, "NLA_PT_properties"); + strcpy(pt->label, N_("Animated Influence")); + strcpy(pt->category, "Strip"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_evaluation; + pt->draw_header = nla_panel_animated_influence_header; + pt->parent = pt_properties; + pt->flag = PNL_DEFAULT_CLOSED; + pt->poll = nla_strip_eval_panel_poll; + BLI_addtail(&pt_properties->children, BLI_genericNodeN(pt)); + BLI_addtail(&art->paneltypes, pt); + + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animated strip time"); + strcpy(pt->idname, "NLA_PT_animated_strip_time"); + strcpy(pt->parent_id, "NLA_PT_properties"); + strcpy(pt->label, N_("Animated Strip Time")); + strcpy(pt->category, "Strip"); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->draw = nla_panel_animated_strip_time; + pt->draw_header = nla_panel_animated_strip_time_header; + pt->parent = pt_properties; + pt->flag = PNL_DEFAULT_CLOSED; pt->poll = nla_strip_eval_panel_poll; + BLI_addtail(&pt_properties->children, BLI_genericNodeN(pt)); BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers"); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 04a20efe887..0f170b1f530 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -565,9 +565,9 @@ static int nlaedit_viewframe_exec(bContext *C, wmOperator *op) void NLA_OT_view_frame(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Frame"; + ot->name = "Go to Current Frame"; ot->idname = "NLA_OT_view_frame"; - ot->description = "Reset viewable area to show range around current frame"; + ot->description = "Move the view to the playhead"; /* api callbacks */ ot->exec = nlaedit_viewframe_exec; diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 589375530f5..9e8fa6475a0 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -96,8 +96,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) INT_MAX, "Start Frame", "Start frame of the sequence strip", - INT_MIN, - INT_MAX); + -MAXFRAME, + MAXFRAME); } if (flag & SEQPROP_ENDFRAME) { @@ -109,8 +109,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) INT_MAX, "End Frame", "End frame for the color strip", - INT_MIN, - INT_MAX); + -MAXFRAME, + MAXFRAME); } RNA_def_int( @@ -312,6 +312,26 @@ static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequenc } } +static bool seq_effect_add_properties_poll(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + int type = RNA_enum_get(op->ptr, "type"); + + /* Hide start/end frames for effect strips that are locked to their parents' location. */ + if (BKE_sequence_effect_get_num_inputs(type) != 0) { + if ((STREQ(prop_id, "frame_start")) || (STREQ(prop_id, "frame_end"))) { + return false; + } + } + if ((type != SEQ_TYPE_COLOR) && (STREQ(prop_id, "color"))) { + return false; + } + + return true; +} + /* add scene operator */ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) { @@ -1066,8 +1086,8 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) /* If seq1 is NULL and no error was raised it means the seq is standalone * (like color strips) and we need to check its start and end frames are valid */ if (seq1 == NULL && end_frame <= start_frame) { - BKE_report(op->reports, RPT_ERROR, "Start and end frame are not set"); - return OPERATOR_CANCELLED; + end_frame = start_frame + 1; + RNA_int_set(op->ptr, "frame_end", end_frame); } seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type); @@ -1161,6 +1181,8 @@ static int sequencer_add_effect_strip_invoke(bContext *C, void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Effect Strip"; ot->idname = "SEQUENCER_OT_effect_strip_add"; @@ -1171,25 +1193,27 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) ot->exec = sequencer_add_effect_strip_exec; ot->poll = ED_operator_sequencer_active_editable; + ot->poll_property = seq_effect_add_properties_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type"); - RNA_def_float_vector(ot->srna, - "color", - 3, - NULL, - 0.0f, - 1.0f, - "Color", - "Initialize the strip with this color (only used when type='COLOR')", - 0.0f, - 1.0f); + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); + prop = RNA_def_float_color(ot->srna, + "color", + 3, + NULL, + 0.0f, + 1.0f, + "Color", + "Initialize the strip with this color (only used when type='COLOR')", + 0.0f, + 1.0f); + RNA_def_property_subtype(prop, PROP_COLOR_GAMMA); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 20fba7aa919..bef4a7cdd22 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2113,11 +2113,7 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) /* channel numbers */ { rcti rect; - BLI_rcti_init(&rect, - 0, - 15 * UI_DPI_FAC, - 15 * UI_DPI_FAC, - UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y); + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__block(ar, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 57a0d63c35e..a1177454acd 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -103,6 +103,7 @@ EnumPropertyItem prop_side_types[] = { {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""}, {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""}, {SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""}, + {SEQ_SIDE_NO_CHANGE, "NO_CHANGE", 0, "No change", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -958,6 +959,8 @@ static bool cut_seq_list(Main *bmain, Scene *scene, ListBase *slist, int cutframe, + int channel, + bool use_cursor_position, Sequence *(*cut_seq)(Main *bmain, Scene *, Sequence *, ListBase *, int)) { Sequence *seq, *seq_next_iter; @@ -968,8 +971,8 @@ static bool cut_seq_list(Main *bmain, while (seq && seq != seq_first_new) { seq_next_iter = seq->next; /* we need this because we may remove seq */ seq->tmp = NULL; - if (seq->flag & SELECT) { - if (cutframe > seq->startdisp && cutframe < seq->enddisp) { + if (use_cursor_position) { + if (seq->machine == channel && seq->startdisp < cutframe && seq->enddisp > cutframe) { Sequence *seqn = cut_seq(bmain, scene, seq, slist, cutframe); if (seqn) { if (seq_first_new == NULL) { @@ -977,16 +980,28 @@ static bool cut_seq_list(Main *bmain, } } } - else if (seq->enddisp <= cutframe) { - /* do nothing */ - } - else if (seq->startdisp >= cutframe) { - /* move to tail */ - BLI_remlink(slist, seq); - BLI_addtail(slist, seq); + } + else { + if (seq->flag & SELECT) { + if (cutframe > seq->startdisp && cutframe < seq->enddisp) { + Sequence *seqn = cut_seq(bmain, scene, seq, slist, cutframe); + if (seqn) { + if (seq_first_new == NULL) { + seq_first_new = seqn; + } + } + } + else if (seq->enddisp <= cutframe) { + /* do nothing */ + } + else if (seq->startdisp >= cutframe) { + /* move to tail */ + BLI_remlink(slist, seq); + BLI_addtail(slist, seq); - if (seq_first_new == NULL) { - seq_first_new = seq; + if (seq_first_new == NULL) { + seq_first_new = seq; + } } } } @@ -2154,40 +2169,64 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, false); - int cut_side, cut_hard, cut_frame; - - bool changed; + int cut_side, cut_hard, cut_frame, cut_channel; + bool changed, use_cursor_position, ignore_selection; + bool seq_selected = false; cut_frame = RNA_int_get(op->ptr, "frame"); + cut_channel = RNA_int_get(op->ptr, "channel"); + use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position"); cut_hard = RNA_enum_get(op->ptr, "type"); cut_side = RNA_enum_get(op->ptr, "side"); + ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection"); if (cut_hard == SEQ_CUT_HARD) { - changed = cut_seq_list(bmain, scene, ed->seqbasep, cut_frame, cut_seq_hard); + changed = cut_seq_list( + bmain, scene, ed->seqbasep, cut_frame, cut_channel, use_cursor_position, cut_seq_hard); } else { - changed = cut_seq_list(bmain, scene, ed->seqbasep, cut_frame, cut_seq_soft); + changed = cut_seq_list( + bmain, scene, ed->seqbasep, cut_frame, cut_channel, use_cursor_position, cut_seq_soft); } if (changed) { /* got new strips ? */ Sequence *seq; - if (cut_side != SEQ_SIDE_BOTH) { - SEQP_BEGIN (ed, seq) { - if (cut_side == SEQ_SIDE_LEFT) { - if (seq->startdisp >= cut_frame) { - seq->flag &= ~SEQ_ALLSEL; + if (ignore_selection) { + if (use_cursor_position) { + SEQP_BEGIN (ed, seq) { + if (seq->enddisp == cut_frame && seq->machine == cut_channel) { + seq_selected = seq->flag & SEQ_ALLSEL; } } - else { - if (seq->enddisp <= cut_frame) { - seq->flag &= ~SEQ_ALLSEL; + SEQ_END; + if (!seq_selected) { + SEQP_BEGIN (ed, seq) { + if (seq->startdisp == cut_frame && seq->machine == cut_channel) { + seq->flag &= ~SEQ_ALLSEL; + } } + SEQ_END; } } - SEQ_END; } - + else { + if (cut_side != SEQ_SIDE_BOTH) { + SEQP_BEGIN (ed, seq) { + if (cut_side == SEQ_SIDE_LEFT) { + if (seq->startdisp >= cut_frame) { + seq->flag &= ~SEQ_ALLSEL; + } + } + else { + if (seq->enddisp <= cut_frame) { + seq->flag &= ~SEQ_ALLSEL; + } + } + } + SEQ_END; + } + } SEQP_BEGIN (ed, seq) { if (seq->seq1 || seq->seq2 || seq->seq3) { BKE_sequence_calc(scene, seq); @@ -2204,7 +2243,8 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } else { - return OPERATOR_CANCELLED; + /* Passthrough to selection if used as tool. */ + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } } @@ -2224,7 +2264,17 @@ static int sequencer_cut_invoke(bContext *C, wmOperator *op, const wmEvent *even cut_side = SEQ_SIDE_BOTH; } } - RNA_int_set(op->ptr, "frame", cut_frame); + + float mouseloc[2]; + UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]); + + if (RNA_boolean_get(op->ptr, "use_cursor_position")) { + RNA_int_set(op->ptr, "frame", mouseloc[0]); + } + else { + RNA_int_set(op->ptr, "frame", cut_frame); + } + RNA_int_set(op->ptr, "channel", mouseloc[1]); RNA_enum_set(op->ptr, "side", cut_side); /*RNA_enum_set(op->ptr, "type", cut_hard); */ /*This type is set from the key shortcut */ return sequencer_cut_exec(C, op); @@ -2255,19 +2305,43 @@ void SEQUENCER_OT_cut(struct wmOperatorType *ot) "Frame where selected strips will be cut", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, + "channel", + 0, + INT_MIN, + INT_MAX, + "Channel", + "Channel in which strip will be cut", + INT_MIN, + INT_MAX); RNA_def_enum(ot->srna, "type", prop_cut_types, SEQ_CUT_SOFT, "Type", "The type of cut operation to perform on strips"); + RNA_def_boolean(ot->srna, + "use_cursor_position", + 0, + "Use Cursor Position", + "Cut at position of the cursor instead of playhead"); prop = RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_MOUSE, "Side", "The side that remains selected after cutting"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean( + ot->srna, + "ignore_selection", + false, + "Ignore Selection", + "Make cut event if strip is not selected preserving selection state after cut"); + + RNA_def_property_flag(prop, PROP_HIDDEN); } #undef SEQ_SIDE_MOUSE @@ -2326,9 +2400,6 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* to give to transform */ - RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); } /* delete operator */ @@ -3153,7 +3224,7 @@ void SEQUENCER_OT_strip_jump(wmOperatorType *ot) ot->poll = sequencer_strip_jump_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* properties */ RNA_def_boolean(ot->srna, "next", true, "Next Strip", ""); @@ -4246,5 +4317,5 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c index f262c6518aa..b90dc5e10ff 100644 --- a/source/blender/editors/space_sequencer/sequencer_modifier.c +++ b/source/blender/editors/space_sequencer/sequencer_modifier.c @@ -123,6 +123,8 @@ static int strip_modifier_remove_exec(bContext *C, wmOperator *op) void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Remove Strip Modifier"; ot->idname = "SEQUENCER_OT_strip_modifier_remove"; @@ -136,7 +138,8 @@ void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove"); + prop = RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /*********************** Move operator *************************/ @@ -183,6 +186,8 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op) void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot) { + PropertyRNA *prop; + static const EnumPropertyItem direction_items[] = { {SEQ_MODIFIER_MOVE_UP, "UP", 0, "Up", "Move modifier up in the stack"}, {SEQ_MODIFIER_MOVE_DOWN, "DOWN", 0, "Down", "Move modifier down in the stack"}, @@ -202,8 +207,10 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove"); - RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", ""); + prop = RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove"); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); } /*********************** Copy to selected operator *************************/ diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index ea93ef2e040..a5bb66ca65f 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -312,7 +312,7 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot) ot->poll = sequencer_edit_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; WM_operator_properties_select_all(ot); } @@ -353,7 +353,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot) ot->poll = sequencer_edit_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; } static int sequencer_select_exec(bContext *C, wmOperator *op) @@ -647,7 +647,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot) ot->poll = ED_operator_sequencer_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* properties */ WM_operator_properties_generic_select(ot); @@ -1086,7 +1086,7 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot) ot->poll = ED_operator_sequencer_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* properties */ WM_operator_properties_gesture_box(ot); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 6e1b9d62f0e..53202b65838 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -95,6 +95,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene) sseq->mainb = SEQ_DRAW_IMG_IMBUF; sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS; + /* tool header */ + ar = MEM_callocN(sizeof(ARegion), "tool header for sequencer"); + + BLI_addtail(&sseq->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOL_HEADER; + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + ar->flag = RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER; + /* header */ ar = MEM_callocN(sizeof(ARegion), "header for sequencer"); @@ -110,6 +118,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene) ar->alignment = RGN_ALIGN_RIGHT; ar->flag = RGN_FLAG_HIDDEN; + /* toolbar */ + ar = MEM_callocN(sizeof(ARegion), "tools for sequencer"); + + BLI_addtail(&sseq->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_LEFT; + ar->flag = RGN_FLAG_HIDDEN; + /* preview region */ /* NOTE: if you change values here, also change them in sequencer_init_preview_region */ ar = MEM_callocN(sizeof(ARegion), "preview region for sequencer"); @@ -618,6 +634,23 @@ static void sequencer_header_region_draw(const bContext *C, ARegion *ar) ED_region_header(C, ar); } +/* *********************** toolbar region ************************ */ +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_tools_region_init(wmWindowManager *wm, ARegion *ar) +{ + wmKeyMap *keymap; + + ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE; + ED_region_panels_init(wm, ar); + + keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); + WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); +} + +static void sequencer_tools_region_draw(const bContext *C, ARegion *ar) +{ + ED_region_panels(C, ar); +} /* *********************** preview region ************************ */ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *ar) { @@ -832,7 +865,7 @@ void ED_spacetype_sequencer(void) art->draw = sequencer_main_region_draw; art->listener = sequencer_main_region_listener; art->message_subscribe = sequencer_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; + art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; BLI_addhead(&st->regiontypes, art); @@ -842,7 +875,8 @@ void ED_spacetype_sequencer(void) art->init = sequencer_preview_region_init; art->draw = sequencer_preview_region_draw; art->listener = sequencer_preview_region_listener; - art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; + art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | + ED_KEYMAP_GPENCIL; BLI_addhead(&st->regiontypes, art); /* regions: listview/buttons */ @@ -850,12 +884,35 @@ void ED_spacetype_sequencer(void) art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH * 1.3f; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->listener = sequencer_buttons_region_listener; art->init = sequencer_buttons_region_init; art->draw = sequencer_buttons_region_draw; BLI_addhead(&st->regiontypes, art); sequencer_buttons_register(art); + /* regions: tool(bar) */ + art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tools region"); + art->regionid = RGN_TYPE_TOOLS; + art->prefsizex = 58; /* XXX */ + art->prefsizey = 50; /* XXX */ + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; + art->message_subscribe = ED_region_generic_tools_region_message_subscribe; + art->snap_size = ED_region_generic_tools_region_snap_size; + art->init = sequencer_tools_region_init; + art->draw = sequencer_tools_region_draw; + BLI_addhead(&st->regiontypes, art); + + /* regions: tool header */ + art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tool header region"); + art->regionid = RGN_TYPE_TOOL_HEADER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; + art->listener = sequencer_main_region_listener; + art->init = sequencer_header_region_init; + art->draw = sequencer_header_region_draw; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header; + BLI_addhead(&st->regiontypes, art); /* regions: header */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); @@ -869,6 +926,10 @@ void ED_spacetype_sequencer(void) BLI_addhead(&st->regiontypes, art); + /* regions: hud */ + art = ED_area_type_hud(st->spaceid); + BLI_addhead(&st->regiontypes, art); + BKE_spacetype_register(st); /* set the sequencer callback when not in background mode */ diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c index 63f27b4d74a..69060daa171 100644 --- a/source/blender/editors/space_statusbar/space_statusbar.c +++ b/source/blender/editors/space_statusbar/space_statusbar.c @@ -81,7 +81,7 @@ static SpaceLink *statusbar_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void statusbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region) { - if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) { + if (ELEM(RGN_ALIGN_ENUM_FROM_MASK(region->alignment), RGN_ALIGN_RIGHT)) { region->flag |= RGN_FLAG_DYNAMIC_SIZE; } ED_region_header_init(region); diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 725a49e417e..d62fcf45d68 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -103,7 +103,7 @@ static void topbar_main_region_init(wmWindowManager *wm, ARegion *region) wmKeyMap *keymap; /* force delayed UI_view2d_region_reinit call */ - if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) { + if (ELEM(RGN_ALIGN_ENUM_FROM_MASK(region->alignment), RGN_ALIGN_RIGHT)) { region->flag |= RGN_FLAG_DYNAMIC_SIZE; } UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy); @@ -123,7 +123,7 @@ static void topbar_keymap(struct wmKeyConfig *UNUSED(keyconf)) /* add handlers, stuff you only do once or on area/region changes */ static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { - if ((ar->alignment & ~RGN_SPLIT_PREV) == RGN_ALIGN_RIGHT) { + if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT) { ar->flag |= RGN_FLAG_DYNAMIC_SIZE; } ED_region_header_init(ar); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7db1a6123e8..59697c00c9c 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1027,19 +1027,9 @@ static void view3d_main_region_message_subscribe(const struct bContext *C, } } -/* concept is to retrieve cursor type context-less */ static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) { - if (WM_cursor_set_from_tool(win, sa, ar)) { - return; - } - - ViewLayer *view_layer = WM_window_get_active_view_layer(win); - Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); - if (obedit) { - WM_cursor_set(win, WM_CURSOR_EDIT); - } - else { + if (!WM_cursor_set_from_tool(win, sa, ar)) { WM_cursor_set(win, WM_CURSOR_DEFAULT); } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index a4714249da2..83fb87264e3 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -158,6 +158,12 @@ typedef struct ViewOpsData { float trackvec[3]; /** Dolly only. */ float mousevec[3]; + + /** + * #RegionView3D.persp set after auto-perspective is applied. + * If we want the value before running the operator, add a separate member. + */ + char persp; } init; /** Previous state (previous modal event handled). */ @@ -413,6 +419,7 @@ static void viewops_data_create(bContext *C, * we may want to make this optional but for now its needed always */ ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d); + vod->init.persp = rv3d->persp; vod->init.dist = rv3d->dist; vod->init.camzoom = rv3d->camzoom; copy_qt_qt(vod->init.quat, rv3d->viewquat); @@ -613,6 +620,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) float zaxis_best[3]; int x, y, z; bool found = false; + bool is_axis_aligned = false; invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat); @@ -630,6 +638,10 @@ static void viewrotate_apply_snap(ViewOpsData *vod) if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) { copy_v3_v3(zaxis_best, zaxis_test); found = true; + + if (abs(x) + abs(y) + abs(z) == 1) { + is_axis_aligned = true; + } } } } @@ -700,6 +712,17 @@ static void viewrotate_apply_snap(ViewOpsData *vod) copy_qt_qt(rv3d->viewquat, quat_best); viewrotate_apply_dyn_ofs(vod, rv3d->viewquat); + + if (U.uiflag & USER_AUTOPERSP) { + if (is_axis_aligned) { + if (rv3d->persp == RV3D_PERSP) { + rv3d->persp = RV3D_ORTHO; + } + } + } + } + else if (U.uiflag & USER_AUTOPERSP) { + rv3d->persp = vod->init.persp; } } @@ -859,6 +882,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) event_code = VIEW_APPLY; break; case VIEWROT_MODAL_AXIS_SNAP_DISABLE: + vod->rv3d->persp = vod->init.persp; vod->axis_snap = false; event_code = VIEW_APPLY; break; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c index 504b10888e8..75ab6518a4f 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -515,12 +515,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv return -1; } -static int gizmo_axis_cursor_get(wmGizmo *gz) +static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz)) { - if (gz->highlight_part > 0) { - return WM_CURSOR_EDIT; - } - return WM_CURSOR_NSEW_SCROLL; + return WM_CURSOR_DEFAULT; } void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt) diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 494e7529975..34470896fb9 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -676,7 +676,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event) return; } - if ((walk->is_cursor_absolute == false) && event->is_motion_absolute) { + if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) { walk->is_cursor_absolute = true; copy_v2_v2_int(walk->prev_mval, event->mval); copy_v2_v2_int(walk->center_mval, event->mval); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 441a6eb0ea5..ec39b457082 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -856,7 +856,7 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) if (t->spacetype != SPACE_VIEW3D) { return false; } - else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) { + else if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) { return false; } else if (!validSnap(t)) { diff --git a/source/blender/editors/transform/transform_draw.c b/source/blender/editors/transform/transform_draw.c deleted file mode 100644 index e44442b7e49..00000000000 --- a/source/blender/editors/transform/transform_draw.c +++ /dev/null @@ -1,114 +0,0 @@ - -/* -------------------------------------------------------------------- */ -/** \name Auto-Key (Pixel Space) - * \{ */ - -/* just draw a little warning message in the top-right corner of the viewport - * to warn that autokeying is enabled */ -static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) -{ - const char *printable = IFACE_("Auto Keying On"); - float printable_size[2]; - int xco, yco; - - const rcti *rect = ED_region_visible_rect(ar); - - const int font_id = BLF_default(); - BLF_width_and_height( - font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - - xco = (rect->xmax - U.widget_unit) - (int)printable_size[0]; - yco = (rect->ymax - U.widget_unit); - - /* warning text (to clarify meaning of overlays) - * - original color was red to match the icon, but that clashes badly with a less nasty border - */ - unsigned char color[3]; - UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color); - BLF_color3ubv(font_id, color); -#ifdef WITH_INTERNATIONAL - BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); -#else - BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); -#endif - - /* autokey recording icon... */ - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); - - xco -= U.widget_unit; - yco -= (int)printable_size[1] / 2; - - UI_icon_draw(xco, yco, ICON_REC); - - GPU_blend(false); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Constraints (View Space) - * \{ */ - -/* called from drawview.c, as an extra per-window draw option */ -void drawPropCircle(const struct bContext *C, TransInfo *t) -{ - if (t->flag & T_PROP_EDIT) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - float tmat[4][4], imat[4][4]; - int depth_test_enabled; - - if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) { - copy_m4_m4(tmat, rv3d->viewmat); - invert_m4_m4(imat, tmat); - } - else { - unit_m4(tmat); - unit_m4(imat); - } - - GPU_matrix_push(); - - if (t->spacetype == SPACE_VIEW3D) { - /* pass */ - } - else if (t->spacetype == SPACE_IMAGE) { - GPU_matrix_scale_2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]); - } - else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) { - /* only scale y */ - rcti *mask = &t->ar->v2d.mask; - rctf *datamask = &t->ar->v2d.cur; - float xsize = BLI_rctf_size_x(datamask); - float ysize = BLI_rctf_size_y(datamask); - float xmask = BLI_rcti_size_x(mask); - float ymask = BLI_rcti_size_y(mask); - GPU_matrix_scale_2f(1.0f, (ysize / xsize) * (xmask / ymask)); - } - - depth_test_enabled = GPU_depth_test_enabled(); - if (depth_test_enabled) { - GPU_depth_test(false); - } - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColor(TH_GRID); - - GPU_logic_op_invert_set(true); - imm_drawcircball(t->center_global, t->prop_size, imat, pos); - GPU_logic_op_invert_set(false); - - immUnbindProgram(); - - if (depth_test_enabled) { - GPU_depth_test(true); - } - - GPU_matrix_pop(); - } -} - -/** \} */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index b2d8671fbce..09992e8be0e 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -720,7 +720,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; ot->poll_property = transform_poll_property; - RNA_def_float_vector_xyz( + RNA_def_float_translation( ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Move", "", -FLT_MAX, FLT_MAX); WM_operatortype_props_advanced_begin(ot); diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 9770b52158a..8e190ed9c73 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -464,6 +464,15 @@ static bool ed_undo_redo_poll(bContext *C) WM_operator_check_ui_enabled(C, last_op->type->name)); } +static bool ed_undo_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL); +} + void ED_OT_undo(wmOperatorType *ot) { /* identifiers */ @@ -473,7 +482,7 @@ void ED_OT_undo(wmOperatorType *ot) /* api callbacks */ ot->exec = ed_undo_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = ed_undo_poll; } void ED_OT_undo_push(wmOperatorType *ot) @@ -498,6 +507,15 @@ void ED_OT_undo_push(wmOperatorType *ot) ""); } +static bool ed_redo_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL); +} + void ED_OT_redo(wmOperatorType *ot) { /* identifiers */ @@ -507,7 +525,7 @@ void ED_OT_redo(wmOperatorType *ot) /* api callbacks */ ot->exec = ed_redo_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = ed_redo_poll; } void ED_OT_undo_redo(wmOperatorType *ot) @@ -697,6 +715,16 @@ static int undo_history_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +static bool undo_history_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + /* More than just original state entry. */ + return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1; +} + void ED_OT_undo_history(wmOperatorType *ot) { /* identifiers */ @@ -707,7 +735,7 @@ void ED_OT_undo_history(wmOperatorType *ot) /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = undo_history_poll; RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp index 3e3a939a8fe..a2f0a3395af 100644 --- a/source/blender/freestyle/intern/application/AppConfig.cpp +++ b/source/blender/freestyle/intern/application/AppConfig.cpp @@ -53,10 +53,6 @@ void Path::setRootDir(const string &iRootDir) string(DIR_SEP.c_str()); _BrushesPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "textures" + string(DIR_SEP.c_str()) + "brushes" + string(DIR_SEP.c_str()); - _PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "modules" + string(DIR_SEP.c_str()); - if (getenv("PYTHONPATH")) { - _PythonPath += string(PATH_SEP.c_str()) + string(getenv("PYTHONPATH")); - } _EnvMapDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "env_map" + string(DIR_SEP.c_str()); _MapsDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "maps" + diff --git a/source/blender/freestyle/intern/application/AppConfig.h b/source/blender/freestyle/intern/application/AppConfig.h index cc2a3962ecd..9369ed81d50 100644 --- a/source/blender/freestyle/intern/application/AppConfig.h +++ b/source/blender/freestyle/intern/application/AppConfig.h @@ -43,7 +43,6 @@ class Path { string _ModelsPath; string _PatternsPath; string _BrushesPath; - string _PythonPath; string _EnvMapDir; string _MapsDir; string _HomeDir; @@ -72,10 +71,6 @@ class Path { { return _BrushesPath; } - const string &getPythonPath() const - { - return _PythonPath; - } const string &getEnvMapDir() const { return _EnvMapDir; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h index dc6677bdcf4..8b125828fdc 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h @@ -35,9 +35,9 @@ #include "../system/FreestyleConfig.h" #include "../system/RenderMonitor.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 4f88578596f..f96f5f119c0 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -23,9 +23,9 @@ #include "../application/AppConfig.h" #include "../stroke/Canvas.h" -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "RNA_access.h" #include "RNA_types.h" diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 07839ac6e61..0567bd0df06 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -32,10 +32,10 @@ using namespace std; using namespace Freestyle; -extern "C" { - #include "MEM_guardedalloc.h" +extern "C" { + #include "DNA_camera_types.h" #include "DNA_collection_types.h" #include "DNA_freestyle_types.h" diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h index 1fed6a00463..255a1b2a152 100644 --- a/source/blender/freestyle/intern/system/PythonInterpreter.h +++ b/source/blender/freestyle/intern/system/PythonInterpreter.h @@ -31,10 +31,10 @@ extern "C" { #include "StringUtils.h" #include "Interpreter.h" -// soc -extern "C" { #include "MEM_guardedalloc.h" +// soc +extern "C" { #include "DNA_text_types.h" #include "BKE_context.h" diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 2c74afd2d8e..bf7b1908321 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -116,7 +116,7 @@ void gpu_pbvh_init() g_vbo_id.msk = GPU_vertformat_attr_add( &g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); g_vbo_id.col = GPU_vertformat_attr_add( - &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); } } @@ -240,8 +240,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, for (int j = 0; j < 3; j++) { const int loop_index = lt->tri[j]; const int vidx = face_vert_indices[i][j]; - const uchar *elem = &vcol[loop_index].r; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, elem); + const MLoopCol *mcol = &vcol[loop_index]; + ushort scol[4]; + scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); + scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); + scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); + scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, scol); } } } @@ -289,8 +294,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, if (show_vcol) { const uint loop_index = lt->tri[j]; - const uchar *elem = &vcol[loop_index].r; - memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4); + const MLoopCol *mcol = &vcol[loop_index]; + ushort scol[4]; + scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); + scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); + scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); + scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); } } } @@ -654,7 +664,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, } if (show_vcol) { - char vcol[4] = {255, 255, 255, 255}; + ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol); } @@ -705,7 +715,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, empty_mask = empty_mask && (fmask == 0.0f); } - char vcol[4] = {255, 255, 255, 255}; + ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol); GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol); GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol); @@ -781,7 +791,7 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, } if (show_vcol) { - static char vcol[4] = {255, 255, 255, 255}; + ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol); } } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 5a5c3ace552..a7dd34a5f96 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1042,12 +1042,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u input->attr_id, attr_prefix_get(input->attr_type), attr_safe_name); - /* Auto attribute can be vertex color byte buffer. - * We need to know and convert them to linear space in VS. */ - if (input->attr_type == CD_AUTO_FROM_NAME) { - BLI_dynstr_appendf(ds, "uniform bool ba%s;\n", attr_safe_name); - BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%s\n", input->attr_id, attr_safe_name); - } } BLI_dynstr_appendf(ds, "out %s var%d%s;\n", @@ -1101,24 +1095,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n"); - BLI_dynstr_append(ds, - "#define USE_ATTR\n" - "vec3 srgb_to_linear_attr(vec3 c) {\n" - "\tc = max(c, vec3(0.0));\n" - "\tvec3 c1 = c * (1.0 / 12.92);\n" - "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n" - "\treturn mix(c1, c2, step(vec3(0.04045), c));\n" - "}\n\n"); - - BLI_dynstr_append(ds, - "vec4 srgba_to_linear_attr(vec4 c) {\n" - "\tc = max(c, vec4(0.0));\n" - "\tvec4 c1 = c * (1.0 / 12.92);\n" - "\tvec4 c2 = pow((c + 0.055) * (1.0 / 1.055), vec4(2.4));\n" - "\tvec4 final = mix(c1, c2, step(vec4(0.04045), c));" - "\treturn vec4(final.xyz, c.a);\n" - "}\n\n"); - /* Prototype because defined later. */ BLI_dynstr_append(ds, "vec2 hair_get_customdata_vec2(const samplerBuffer);\n" @@ -1224,22 +1200,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u input->attr_id, use_geom ? "g" : ""); } - else if (input->attr_type == CD_MCOL) { - BLI_dynstr_appendf(ds, - "\tvar%d%s = srgba_to_linear_attr(att%d);\n", - input->attr_id, - use_geom ? "g" : "", - input->attr_id); - } - else if (input->attr_type == CD_AUTO_FROM_NAME) { - BLI_dynstr_appendf(ds, - "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attr(att%d) : att%d;\n", - input->attr_id, - use_geom ? "g" : "", - input->attr_id, - input->attr_id, - input->attr_id); - } else { BLI_dynstr_appendf( ds, "\tvar%d%s = att%d;\n", input->attr_id, use_geom ? "g" : "", input->attr_id); diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 201194232db..84328b8dfd4 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -1064,56 +1064,6 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) return tex; } -GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) -{ - GPUTexture *tex = prv->gputexture[0]; - GLuint bindcode = 0; - - if (tex) { - bindcode = tex->bindcode; - } - - /* this binds a texture, so that's why we restore it to 0 */ - if (bindcode == 0) { - GPU_create_gl_tex( - &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, false, NULL); - } - if (tex) { - tex->bindcode = bindcode; - glBindTexture(GL_TEXTURE_2D, 0); - return tex; - } - - tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->bindcode = bindcode; - tex->number = -1; - tex->refcount = 1; - tex->target = GL_TEXTURE_2D; - tex->target_base = GL_TEXTURE_2D; - tex->format = -1; - tex->components = -1; - - prv->gputexture[0] = tex; - - if (!glIsTexture(tex->bindcode)) { - GPU_print_error_debug("Blender Texture Not Loaded"); - } - else { - GLint w, h; - - glBindTexture(GL_TEXTURE_2D, tex->bindcode); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - - tex->w = w; - tex->h = h; - } - - glBindTexture(GL_TEXTURE_2D, 0); - - return tex; -} - GPUTexture *GPU_texture_create_1d(int w, eGPUTextureFormat tex_format, const float *pixels, diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl index de3be98b715..94f69d35b7e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl @@ -106,7 +106,7 @@ void math_fraction(float a, float b, float c, out float result) void math_modulo(float a, float b, float c, out float result) { - result = c_mod(a, b); + result = compatible_fmod(a, b); } void math_trunc(float a, float b, float c, out float result) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl index e8487fb5d42..df1c0479159 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl @@ -5,10 +5,11 @@ float safe_divide(float a, float b) return (b != 0.0) ? a / b : 0.0; } -/* Modulo with C sign convention. mod in GLSL will take absolute for negative numbers. */ -float c_mod(float a, float b) +/* fmod function compatible with OSL using nvidia reference example. */ +float compatible_fmod(float a, float b) { - return (b != 0.0 && a != b) ? sign(a) * mod(abs(a), b) : 0.0; + float c = (b != 0.0) ? fract(abs(a / b)) * abs(b) : 0.0; + return (a < 0.0) ? -c : c; } float compatible_pow(float x, float y) @@ -88,9 +89,9 @@ vec4 safe_divide(vec4 a, float b) return (b != 0.0) ? a / b : vec4(0.0); } -vec3 c_mod(vec3 a, vec3 b) +vec3 compatible_fmod(vec3 a, vec3 b) { - return vec3(c_mod(a.x, b.x), c_mod(a.y, b.y), c_mod(a.z, b.z)); + return vec3(compatible_fmod(a.x, b.x), compatible_fmod(a.y, b.y), compatible_fmod(a.z, b.z)); } void invert_z(vec3 v, out vec3 outv) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl index fce511deb79..b11d13a0413 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl @@ -1,21 +1,25 @@ /* White Noise */ -void node_white_noise_1d(vec3 vector, float w, out float value) +void node_white_noise_1d(vec3 vector, float w, out float value, out vec4 color) { value = hash_float_to_float(w); + color.xyz = hash_float_to_vec3(w); } -void node_white_noise_2d(vec3 vector, float w, out float value) +void node_white_noise_2d(vec3 vector, float w, out float value, out vec4 color) { value = hash_vec2_to_float(vector.xy); + color.xyz = hash_vec2_to_vec3(vector.xy); } -void node_white_noise_3d(vec3 vector, float w, out float value) +void node_white_noise_3d(vec3 vector, float w, out float value, out vec4 color) { value = hash_vec3_to_float(vector); + color.xyz = hash_vec3_to_vec3(vector); } -void node_white_noise_4d(vec3 vector, float w, out float value) +void node_white_noise_4d(vec3 vector, float w, out float value, out vec4 color) { value = hash_vec4_to_float(vec4(vector, w)); + color.xyz = hash_vec4_to_vec3(vec4(vector, w)); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl index 93132b6044f..420f177e146 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl @@ -76,7 +76,7 @@ void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outVector = c_mod(a, b); + outVector = compatible_fmod(a, b); } void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index ae3ac624e3b..58ecfce5a63 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -39,26 +39,26 @@ */ typedef struct BMPINFOHEADER { - unsigned int biSize; - unsigned int biWidth; - unsigned int biHeight; - unsigned short biPlanes; - unsigned short biBitCount; - unsigned int biCompression; - unsigned int biSizeImage; - unsigned int biXPelsPerMeter; - unsigned int biYPelsPerMeter; - unsigned int biClrUsed; - unsigned int biClrImportant; + uint biSize; + uint biWidth; + uint biHeight; + ushort biPlanes; + ushort biBitCount; + uint biCompression; + uint biSizeImage; + uint biXPelsPerMeter; + uint biYPelsPerMeter; + uint biClrUsed; + uint biClrImportant; } BMPINFOHEADER; #if 0 typedef struct BMPHEADER { - unsigned short biType; - unsigned int biSize; - unsigned short biRes1; - unsigned short biRes2; - unsigned int biOffBits; + ushort biType; + uint biSize; + ushort biRes1; + ushort biRes2; + uint biOffBits; } BMPHEADER; #endif @@ -70,12 +70,12 @@ typedef struct BMPHEADER { CHECK_HEADER_FIELD(_mem, "CI") || CHECK_HEADER_FIELD(_mem, "CP") || \ CHECK_HEADER_FIELD(_mem, "IC") || CHECK_HEADER_FIELD(_mem, "PT")) -static int checkbmp(const unsigned char *mem) +static int checkbmp(const uchar *mem) { int ret_val = 0; BMPINFOHEADER bmi; - unsigned int u; + uint u; if (mem) { if (CHECK_HEADER_FIELD_BMP(mem)) { @@ -104,22 +104,19 @@ static int checkbmp(const unsigned char *mem) return (ret_val); } -int imb_is_a_bmp(const unsigned char *buf) +int imb_is_a_bmp(const uchar *buf) { return checkbmp(buf); } -struct ImBuf *imb_bmp_decode(const unsigned char *mem, - size_t size, - int flags, - char colorspace[IM_MAX_SPACE]) +ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { - struct ImBuf *ibuf = NULL; + ImBuf *ibuf = NULL; BMPINFOHEADER bmi; int x, y, depth, ibuf_depth, skip; - const unsigned char *bmp; - unsigned char *rect; - unsigned short col; + const uchar *bmp; + uchar *rect; + ushort col; double xppm, yppm; bool top_to_bottom = false; @@ -177,7 +174,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, return NULL; } - rect = (unsigned char *)ibuf->rect; + rect = (uchar *)ibuf->rect; if (depth <= 8) { const int rowsize = (depth * x + 31) / 32 * 4; @@ -190,7 +187,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, int nbytes = 0; const char *pcol; if (top_to_bottom) { - rect = (unsigned char *)&ibuf->rect[(i - 1) * x]; + rect = (uchar *)&ibuf->rect[(i - 1) * x]; } for (size_t j = x; j > 0; j--) { bitoffs -= depth; @@ -219,7 +216,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, else if (depth == 16) { for (size_t i = y; i > 0; i--) { if (top_to_bottom) { - rect = (unsigned char *)&ibuf->rect[(i - 1) * x]; + rect = (uchar *)&ibuf->rect[(i - 1) * x]; } for (size_t j = x; j > 0; j--) { col = bmp[0] + (bmp[1] << 8); @@ -237,7 +234,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, const int x_pad = x % 4; for (size_t i = y; i > 0; i--) { if (top_to_bottom) { - rect = (unsigned char *)&ibuf->rect[(i - 1) * x]; + rect = (uchar *)&ibuf->rect[(i - 1) * x]; } for (size_t j = x; j > 0; j--) { rect[0] = bmp[2]; @@ -255,7 +252,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, else if (depth == 32) { for (size_t i = y; i > 0; i--) { if (top_to_bottom) { - rect = (unsigned char *)&ibuf->rect[(i - 1) * x]; + rect = (uchar *)&ibuf->rect[(i - 1) * x]; } for (size_t j = x; j > 0; j--) { rect[0] = bmp[2]; @@ -282,7 +279,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, #undef CHECK_HEADER_FIELD /* Couple of helper functions for writing our data */ -static int putIntLSB(unsigned int ui, FILE *ofile) +static int putIntLSB(uint ui, FILE *ofile) { putc((ui >> 0) & 0xFF, ofile); putc((ui >> 8) & 0xFF, ofile); @@ -290,42 +287,44 @@ static int putIntLSB(unsigned int ui, FILE *ofile) return putc((ui >> 24) & 0xFF, ofile); } -static int putShortLSB(unsigned short us, FILE *ofile) +static int putShortLSB(ushort us, FILE *ofile) { putc((us >> 0) & 0xFF, ofile); return putc((us >> 8) & 0xFF, ofile); } /* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */ -int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) +int imb_savebmp(ImBuf *ibuf, const char *name, int UNUSED(flags)) { BMPINFOHEADER infoheader; - size_t bytesize, extrabytes, ptr; - uchar *data; - FILE *ofile; - (void)flags; /* unused */ + const size_t bytes_per_pixel = (ibuf->planes + 7) >> 3; + BLI_assert(bytes_per_pixel == 1 || bytes_per_pixel == 3); - extrabytes = (4 - ibuf->x * 3 % 4) % 4; - bytesize = (ibuf->x * 3 + extrabytes) * ibuf->y; + const size_t pad_bytes_per_scanline = (4 - ibuf->x * bytes_per_pixel % 4) % 4; + const size_t bytesize = (ibuf->x * bytes_per_pixel + pad_bytes_per_scanline) * ibuf->y; - data = (uchar *)ibuf->rect; - ofile = BLI_fopen(name, "wb"); - if (!ofile) { + const uchar *data = (const uchar *)ibuf->rect; + FILE *ofile = BLI_fopen(name, "wb"); + if (ofile == NULL) { return 0; } - putShortLSB(19778, ofile); /* "BM" */ - putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile); /* Total file size */ - putShortLSB(0, ofile); /* Res1 */ - putShortLSB(0, ofile); /* Res2 */ - putIntLSB(BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile); + const bool is_grayscale = bytes_per_pixel == 1; + const size_t palette_size = is_grayscale ? 255 * 4 : 0; /* RGBA32 */ + const size_t pixel_array_start = BMP_FILEHEADER_SIZE + sizeof(infoheader) + palette_size; + + putShortLSB(19778, ofile); /* "BM" */ + putIntLSB(bytesize + pixel_array_start, ofile); /* Total file size */ + putShortLSB(0, ofile); /* Res1 */ + putShortLSB(0, ofile); /* Res2 */ + putIntLSB(pixel_array_start, ofile); /* offset to start of pixel array */ putIntLSB(sizeof(infoheader), ofile); putIntLSB(ibuf->x, ofile); putIntLSB(ibuf->y, ofile); putShortLSB(1, ofile); - putShortLSB(24, ofile); + putShortLSB(is_grayscale ? 8 : 24, ofile); putIntLSB(0, ofile); putIntLSB(bytesize, ofile); putIntLSB((int)(ibuf->ppm[0] + 0.5), ofile); @@ -333,24 +332,52 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) putIntLSB(0, ofile); putIntLSB(0, ofile); - /* Need to write out padded image data in bgr format */ - for (size_t y = 0; y < ibuf->y; y++) { - for (size_t x = 0; x < ibuf->x; x++) { - ptr = (x + y * ibuf->x) * 4; - if (putc(data[ptr + 2], ofile) == EOF) { - return 0; - } - if (putc(data[ptr + 1], ofile) == EOF) { - return 0; + /* color palette table, which is just every grayscale color, full alpha */ + if (is_grayscale) { + for (char i = 0; i < 255; i++) { + putc(i, ofile); + putc(i, ofile); + putc(i, ofile); + putc(0xFF, ofile); + } + } + + if (is_grayscale) { + for (size_t y = 0; y < ibuf->y; y++) { + for (size_t x = 0; x < ibuf->x; x++) { + const size_t ptr = (x + y * ibuf->x) * 4; + if (putc(data[ptr], ofile) == EOF) { + return 0; + } } - if (putc(data[ptr], ofile) == EOF) { - return 0; + /* Add padding here. */ + for (size_t t = 0; t < pad_bytes_per_scanline; t++) { + if (putc(0, ofile) == EOF) { + return 0; + } } } - /* add padding here */ - for (size_t t = 0; t < extrabytes; t++) { - if (putc(0, ofile) == EOF) { - return 0; + } + else { + /* Need to write out padded image data in BGR format. */ + for (size_t y = 0; y < ibuf->y; y++) { + for (size_t x = 0; x < ibuf->x; x++) { + const size_t ptr = (x + y * ibuf->x) * 4; + if (putc(data[ptr + 2], ofile) == EOF) { + return 0; + } + if (putc(data[ptr + 1], ofile) == EOF) { + return 0; + } + if (putc(data[ptr], ofile) == EOF) { + return 0; + } + } + /* Add padding here. */ + for (size_t t = 0; t < pad_bytes_per_scanline; t++) { + if (putc(0, ofile) == EOF) { + return 0; + } } } } diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp index d2147f833c3..e001b8b21c4 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp +++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp @@ -33,9 +33,9 @@ #include "openimageio_api.h" #include <OpenImageIO/imageio.h> -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "BLI_blenlib.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 88dfa42a416..e1513169736 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -65,6 +65,8 @@ # include "utfconv.h" #endif +#include "MEM_guardedalloc.h" + extern "C" { // The following prevents a linking error in debug mode for MSVC using the libs in CVS @@ -74,8 +76,6 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void) } #endif -#include "MEM_guardedalloc.h" - #include "BLI_blenlib.h" #include "BLI_math_color.h" #include "BLI_threads.h" diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 354344328d3..7192b1295aa 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -252,7 +252,8 @@ typedef enum eBone_Flag { BONE_ADD_PARENT_END_ROLL = (1 << 24), /** this bone was transformed by the mirror function */ BONE_TRANSFORM_MIRROR = (1 << 25), - + /** this bone is associated with a locked vertex group, ONLY USE FOR DRAWING */ + BONE_DRAW_LOCKED_WEIGHT = (1 << 26), } eBone_Flag; /* bone->inherit_scale_mode */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 9db993cca59..39efe838bab 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -492,8 +492,15 @@ typedef struct DisplaceModifierData { char defgrp_name[64]; float midlevel; int space; + short flag; + char _pad[6]; } DisplaceModifierData; +/* DisplaceModifierData->flag */ +enum { + MOD_DISP_INVERT_VGROUP = (1 << 0), +}; + /* DisplaceModifierData->direction */ enum { MOD_DISP_DIR_X = 0, @@ -611,6 +618,7 @@ typedef struct CastModifierData { /* Cast modifier flags */ enum { /* And what bout (1 << 0) flag? ;) */ + MOD_CAST_INVERT_VGROUP = (1 << 0), MOD_CAST_X = (1 << 1), MOD_CAST_Y = (1 << 2), MOD_CAST_Z = (1 << 3), @@ -1292,7 +1300,6 @@ typedef struct WarpModifierData { char defgrp_name[64]; float strength; float falloff_radius; - /** Not used yet. */ char flag; char falloff_type; char _pad[6]; @@ -1300,6 +1307,11 @@ typedef struct WarpModifierData { #define MOD_WARP_VOLUME_PRESERVE 1 +/* WarpModifierData->flag */ +enum { + MOD_WARP_INVERT_VGROUP = (1 << 0), +}; + typedef enum { eWarp_Falloff_None = 0, eWarp_Falloff_Curve = 1, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index fbed0754046..cbed2af7df2 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -374,8 +374,6 @@ typedef struct Object { struct FluidsimSettings *fluidsimSettings DNA_DEPRECATED; // XXX deprecated... replaced by mantaflow, keep for readfile - struct DerivedMesh *derivedDeform, *derivedFinal; - ListBase pc_ids; /** Settings for Bullet rigid body. */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index d3c5a707b44..a52767834a4 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -129,6 +129,12 @@ typedef struct ScrAreaMap { ListBase areabase; } ScrAreaMap; +typedef struct Panel_Runtime { + /* Applied to Panel.ofsx, but saved separately so we can track changes between redraws. */ + int region_ofsx; + char _pad[4]; +} Panel_Runtime; + /** The part from uiBlock that needs saved in file. */ typedef struct Panel { struct Panel *next, *prev; @@ -159,6 +165,8 @@ typedef struct Panel { void *activedata; /** Sub panels. */ ListBase children; + + Panel_Runtime runtime; } Panel; /** @@ -409,7 +417,9 @@ typedef struct ARegion { short flag; /** Current split size in unscaled pixels (if zero it uses regiontype). - * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`. */ + * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`. + * However to get the current region size, you should usually use winx/winy from above, not this! + */ short sizex, sizey; /** Private, cached notifier events. */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index f0a852a7a1a..d741f22cc4f 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -283,13 +283,12 @@ typedef struct ThemeSpace { unsigned char normal[4]; unsigned char vertex_normal[4]; unsigned char loop_normal[4]; - unsigned char bone_solid[4], bone_pose[4], bone_pose_active[4]; + unsigned char bone_solid[4], bone_pose[4], bone_pose_active[4], bone_locked_weight[4]; unsigned char strip[4], strip_select[4]; unsigned char cframe[4]; unsigned char time_keyframe[4], time_gp_keyframe[4]; unsigned char freestyle_edge_mark[4], freestyle_face_mark[4]; unsigned char time_scrub_background[4]; - char _pad5[4]; unsigned char nurb_uline[4], nurb_vline[4]; unsigned char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4]; @@ -414,6 +413,8 @@ typedef struct ThemeSpace { unsigned char info_warning[4], info_warning_text[4]; unsigned char info_info[4], info_info_text[4]; unsigned char info_debug[4], info_debug_text[4]; + unsigned char info_property[4], info_property_text[4]; + unsigned char info_operator[4], info_operator_text[4]; unsigned char paint_curve_pivot[4]; unsigned char paint_curve_handle[4]; diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 0beb14614ec..349b30fa64e 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -233,6 +233,16 @@ PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont, const char *ui_description, float softmin, float softmax); +PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont, + const char *identifier, + int len, + const float *default_value, + float hardmin, + float hardmax, + const char *ui_name, + const char *ui_description, + float softmin, + float softmax); PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont, const char *identifier, int len, diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index d7f6ec1fb5a..c10436ae08e 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -52,6 +52,7 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[]; extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[]; extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; extern const EnumPropertyItem rna_enum_space_graph_mode_items[]; +extern const EnumPropertyItem rna_enum_space_sequencer_view_type_items[]; extern const EnumPropertyItem rna_enum_space_type_items[]; extern const EnumPropertyItem rna_enum_space_image_mode_items[]; extern const EnumPropertyItem rna_enum_space_image_mode_all_items[]; @@ -141,6 +142,8 @@ extern const EnumPropertyItem rna_enum_texture_type_items[]; extern const EnumPropertyItem rna_enum_light_type_items[]; +extern const EnumPropertyItem rna_enum_lightprobes_type_items[]; + extern const EnumPropertyItem rna_enum_unpack_method_items[]; extern const EnumPropertyItem rna_enum_object_type_items[]; diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index e900160a653..b295a169c83 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -51,29 +51,25 @@ static const EnumPropertyItem beztriple_handle_type_items[] = { #endif const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = { - {HD_FREE, - "FREE", - ICON_HANDLETYPE_FREE_VEC, - "Free", - "Completely independent manually set handle"}, + {HD_FREE, "FREE", ICON_HANDLE_FREE, "Free", "Completely independent manually set handle"}, {HD_ALIGN, "ALIGNED", - ICON_HANDLETYPE_ALIGNED_VEC, + ICON_HANDLE_ALIGNED, "Aligned", "Manually set handle with rotation locked together with its pair"}, {HD_VECT, "VECTOR", - ICON_HANDLETYPE_VECTOR_VEC, + ICON_HANDLE_VECTOR, "Vector", "Automatic handles that create straight lines"}, {HD_AUTO, "AUTO", - ICON_HANDLETYPE_AUTO_VEC, + ICON_HANDLE_AUTO, "Automatic", "Automatic handles that create smooth curves"}, {HD_AUTO_ANIM, "AUTO_CLAMPED", - ICON_HANDLETYPE_AUTO_CLAMP_VEC, + ICON_HANDLE_AUTOCLAMPED, "Auto Clamped", "Automatic handles that create smooth curves which only change direction at keyframes"}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 55aa529a30e..73a59cbba11 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -3888,6 +3888,36 @@ PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont_, return prop; } +PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont_, + const char *identifier, + int len, + const float *default_value, + float hardmin, + float hardmax, + const char *ui_name, + const char *ui_description, + float softmin, + float softmax) +{ + PropertyRNA *prop; + + prop = RNA_def_float_vector(cont_, + identifier, + len, + default_value, + hardmin, + hardmax, + ui_name, + ui_description, + softmin, + softmax); + prop->subtype = PROP_TRANSLATION; + + RNA_def_property_ui_range(prop, softmin, softmax, 1, RNA_TRANSLATION_PREC_DEFAULT); + + return prop; +} + PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *identifier, int len, diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index d85c5c5f249..9df21a16e90 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -250,6 +250,9 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char case ID_AR: type = OB_ARMATURE; break; + case ID_LP: + type = OB_LIGHTPROBE; + break; default: { const char *idname; if (RNA_enum_id_from_value(rna_enum_id_type_items, GS(data->name), &idname) == 0) { @@ -665,12 +668,15 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name return linestyle; } -static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name) +static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name, int type) { char safe_name[MAX_ID_NAME - 2]; rna_idname_validate(name, safe_name); LightProbe *probe = BKE_lightprobe_add(bmain, safe_name); + + BKE_lightprobe_type_set(probe, type); + id_us_min(&probe->id); return probe; } @@ -2079,6 +2085,9 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new probe to the main database"); parm = RNA_def_string(func, "name", "Probe", 0, "", "New name for the data-block"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum( + func, "type", rna_enum_lightprobes_type_items, 0, "Type", "The type of lightprobe to add"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "lightprobe", "LightProbe", "", "New light probe data-block"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 589ce1414bb..6f2f12ebf98 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1838,6 +1838,11 @@ static void rna_def_modifier_warp(BlenderRNA *brna) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WarpModifier_defgrp_name_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WARP_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + rna_def_modifier_generic_map_info(srna); } @@ -2889,6 +2894,11 @@ static void rna_def_modifier_displace(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Space", ""); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DISP_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + rna_def_modifier_generic_map_info(srna); } @@ -3217,6 +3227,11 @@ static void rna_def_modifier_cast(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_X); RNA_def_property_ui_text(prop, "X", ""); diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 97cab783aed..cf84d38a880 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -801,7 +801,8 @@ static void rna_def_nlastrip(BlenderRNA *brna) prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED); - RNA_def_property_ui_text(prop, "Muted", "Disable NLA Strip evaluation"); + RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1); + RNA_def_property_ui_text(prop, "Mute", "Disable NLA Strip evaluation"); RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update"); prop = RNA_def_property(srna, "use_reverse", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index ab813f62973..70192198e14 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -25,6 +25,7 @@ #include "DNA_brush_types.h" #include "DNA_collection_types.h" #include "DNA_customdata_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_object_force_types.h" @@ -196,6 +197,13 @@ const EnumPropertyItem rna_enum_metaelem_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_lightprobes_type_items[] = { + {LIGHTPROBE_TYPE_CUBE, "CUBE", ICON_LIGHTPROBE_CUBEMAP, "Cube", ""}, + {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Planar", ""}, + {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Grid", ""}, + {0, NULL, 0, NULL, NULL}, +}; + /* used for 2 enums */ #define OBTYPE_CU_CURVE \ { \ @@ -1574,9 +1582,9 @@ bool rna_Object_modifiers_override_apply(Main *bmain, ModifierData *mod_dst = ED_object_modifier_add( NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type); - /* XXX Current handling of 'copy' from particlesystem modifier is *very* bad (it keeps same psys + /* XXX Current handling of 'copy' from particle-system modifier is *very* bad (it keeps same psys * pointer as source, then calling code copies psys of object separately and do some magic - * remapping of pointers...), unfortunately several pieces of code in Obejct editing area rely on + * remapping of pointers...), unfortunately several pieces of code in Object editing area rely on * this behavior. So for now, hacking around it to get it doing what we want it to do, as getting * a proper behavior would be everything but trivial, and this whole particle thingy is * end-of-life. */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index a5852a30661..29ec968fe2a 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -890,7 +890,7 @@ static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value) /* check for clipping */ if (value > settings->end) { - value = settings->end; + settings->end = value; } /*if (settings->type==PART_REACTOR && value < 1.0) */ @@ -909,7 +909,7 @@ static void rna_PartSettings_end_set(struct PointerRNA *ptr, float value) /* check for clipping */ if (value < settings->sta) { - value = settings->sta; + settings->sta = value; } settings->end = value; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index ea1fb1eb489..262048e55c2 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -941,8 +941,8 @@ static void rna_Scene_start_frame_set(PointerRNA *ptr, int value) CLAMP(value, MINFRAME, MAXFRAME); data->r.sfra = value; - if (data->r.sfra >= data->r.efra) { - data->r.efra = MIN2(data->r.sfra, MAXFRAME); + if (value > data->r.efra) { + data->r.efra = MIN2(value, MAXFRAME); } } @@ -952,8 +952,8 @@ static void rna_Scene_end_frame_set(PointerRNA *ptr, int value) CLAMP(value, MINFRAME, MAXFRAME); data->r.efra = value; - if (data->r.sfra >= data->r.efra) { - data->r.sfra = MAX2(data->r.efra, MINFRAME); + if (data->r.sfra > value) { + data->r.sfra = MAX2(value, MINFRAME); } } @@ -985,10 +985,12 @@ static void rna_Scene_preview_range_start_frame_set(PointerRNA *ptr, int value) /* TODO: or just refuse to set instead? */ data->r.pefra = data->r.efra; } - - /* now set normally */ - CLAMP(value, MINAFRAME, data->r.pefra); + CLAMP(value, MINAFRAME, MAXFRAME); data->r.psfra = value; + + if (value > data->r.pefra) { + data->r.pefra = MIN2(value, MAXFRAME); + } } static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value) @@ -1001,10 +1003,12 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value) /* TODO: or just refuse to set instead? */ data->r.psfra = data->r.sfra; } - - /* now set normally */ - CLAMP(value, data->r.psfra, MAXFRAME); + CLAMP(value, MINAFRAME, MAXFRAME); data->r.pefra = value; + + if (data->r.psfra > value) { + data->r.psfra = MAX2(value, MINAFRAME); + } } static void rna_Scene_show_subframe_update(Main *UNUSED(bmain), @@ -2959,17 +2963,21 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_transform_pivot_point_align", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_AXIS_ALIGN); RNA_def_property_ui_text( - prop, "Only Locations", "Manipulate origins (object, pose and weight paint mode only)"); + prop, + "Only Locations", + "Only transform object locations, without affecting rotation or scaling"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "use_transform_data_origin", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_DATA_ORIGIN); - RNA_def_property_ui_text(prop, "Transform Origins", "Manipulate object data"); + RNA_def_property_ui_text( + prop, "Transform Origins", "Transform object origins, while leaving the shape in place"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "use_transform_skip_children", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_SKIP_CHILDREN); - RNA_def_property_ui_text(prop, "Transform Parents", "Don't transform children"); + RNA_def_property_ui_text( + prop, "Transform Parents", "Transform the parents, leaving the children in place"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 2c5f93e28ed..16dbe38f866 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2701,15 +2701,15 @@ static void rna_def_text(StructRNA *srna) { /* Avoid text icons because they imply this aligns within a frame, see: T71082 */ static const EnumPropertyItem text_align_x_items[] = { - {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", 0, "Left", ""}, - {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", 0, "Center", ""}, - {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", 0, "Right", ""}, + {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", ICON_ANCHOR_LEFT, "Left", ""}, + {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", ICON_ANCHOR_CENTER, "Center", ""}, + {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", ICON_ANCHOR_RIGHT, "Right", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem text_align_y_items[] = { - {SEQ_TEXT_ALIGN_Y_TOP, "TOP", 0, "Top", ""}, - {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", 0, "Center", ""}, - {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", ""}, + {SEQ_TEXT_ALIGN_Y_TOP, "TOP", ICON_ANCHOR_TOP, "Top", ""}, + {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", ICON_ANCHOR_CENTER, "Center", ""}, + {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ANCHOR_BOTTOM, "Bottom", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 67b43cb13df..746f9042dd8 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -161,6 +161,13 @@ const EnumPropertyItem rna_enum_space_graph_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_space_sequencer_view_type_items[] = { + {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""}, + {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""}, + {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SPLITVIEW, "Sequencer/Preview", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #define SACT_ITEM_DOPESHEET \ { \ SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene" \ @@ -2640,7 +2647,9 @@ static void rna_def_space(BlenderRNA *brna) /* access to V2D_VIEWSYNC_SCREEN_TIME */ prop = RNA_def_property(srna, "show_locked_time", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Space_view2d_sync_get", "rna_Space_view2d_sync_set"); - RNA_def_property_ui_text(prop, "Lock Time to Other Windows", ""); + RNA_def_property_ui_text(prop, + "Sync Visible Range", + "Syncronize the visible timeline range with other time-based editors"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Space_view2d_sync_update"); rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_HEADER)); @@ -4458,17 +4467,6 @@ static void rna_def_space_sequencer(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem view_type_items[] = { - {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""}, - {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""}, - {SEQ_VIEW_SEQUENCE_PREVIEW, - "SEQUENCER_PREVIEW", - ICON_SEQ_SPLITVIEW, - "Sequencer/Preview", - ""}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem display_mode_items[] = { {SEQ_DRAW_IMG_IMBUF, "IMAGE", ICON_SEQ_PREVIEW, "Image Preview", ""}, {SEQ_DRAW_IMG_WAVEFORM, "WAVEFORM", ICON_SEQ_LUMA_WAVEFORM, "Luma Waveform", ""}, @@ -4528,12 +4526,14 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceSeq"); RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data"); - rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI)); + rna_def_space_generic_show_region_toggles(srna, + (1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_UI) | + (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_HUD)); /* view type, fairly important */ prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "view"); - RNA_def_property_enum_items(prop, view_type_items); + RNA_def_property_enum_items(prop, rna_enum_space_sequencer_view_type_items); RNA_def_property_ui_text( prop, "View Type", "Type of the Sequencer view (sequencer, preview or both)"); RNA_def_property_update(prop, 0, "rna_Sequencer_view_type_update"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 56f19d313fd..b9fb8638c49 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -2231,6 +2231,14 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Bone Solid", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "bone_locked_weight", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text( + prop, + "Bone Locked Weight", + "Shade for bones corresponding to a locked weight group during painting"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + /* misc */ prop = RNA_def_property(srna, "bundle_solid", PROP_FLOAT, PROP_COLOR_GAMMA); @@ -2508,63 +2516,73 @@ static void rna_def_userdef_theme_space_info(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); prop = RNA_def_property(srna, "info_selected", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_selected"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Selected Line Background", ""); + RNA_def_property_ui_text(prop, "Selected Line Background", "Background color of selected line"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_selected_text", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_selected_text"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Selected Line Text", ""); + RNA_def_property_ui_text(prop, "Selected Line Text Color", "Text color of selected line"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_error", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_error"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Error Background", ""); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Error Icon Background", "Background color of Error icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_error_text", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_error_text"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Error Text", ""); + RNA_def_property_ui_text(prop, "Error Icon Foreground", "Foreground color of Error icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_warning", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_warning"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Warning Background", ""); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Warning Icon Background", "Background color of Warning icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_warning_text", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_warning_text"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Warning Text", ""); + RNA_def_property_ui_text(prop, "Warning Icon Foreground", "Foreground color of Warning icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_info", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_info"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Info Background", ""); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Info Icon Background", "Background color of Info icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_info_text", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_info_text"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Info Text", ""); + RNA_def_property_ui_text(prop, "Info Icon Foreground", "Foreground color of Info icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_debug", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_debug"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Debug Background", ""); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Debug Icon Background", "Background color of Debug icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "info_debug_text", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "info_debug_text"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Debug Text", ""); + RNA_def_property_ui_text(prop, "Debug Icon Foreground", "Foreground color of Debug icon"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "info_property", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Property Icon Background", "Backgrond color of Property icon"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "info_property_text", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Property Icon Foreground", "Foreground color of Property icon"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "info_operator", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Operator Icon Background", "Background color of Operator icon"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "info_operator_text", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Operator Icon Foreground", "Foreground color of Operator icon"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 249581d22bf..bf3c562f95f 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -90,6 +90,7 @@ static const EnumPropertyItem event_mouse_type_items[] = { {MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""}, {MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""}, {MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""}, + {MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", ""}, {0, "", 0, NULL, NULL}, {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""}, {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""}, @@ -186,6 +187,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = { {MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", "MsPan"}, {MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", "MsZoom"}, {MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", "MsRot"}, + {MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", "MsSmartZoom"}, {0, "", 0, NULL, NULL}, {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", "WhUp"}, {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", "WhDown"}, @@ -2185,7 +2187,7 @@ static void rna_def_event(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Is Tablet", "The event has tablet data"); prop = RNA_def_property(srna, "is_mouse_absolute", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "is_motion_absolute", 1); + RNA_def_property_boolean_sdna(prop, NULL, "tablet.is_motion_absolute", 1); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input"); diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 4d4ab64abb9..32e348ea72f 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -152,7 +152,17 @@ static bToolRef *rna_WorkSpace_tools_from_space_node(WorkSpace *workspace, bool }, create); } - +static bToolRef *rna_WorkSpace_tools_from_space_sequencer(WorkSpace *workspace, + int mode, + bool create) +{ + return rna_WorkSpace_tools_from_tkey(workspace, + &(bToolKey){ + .space_type = SPACE_SEQ, + .mode = mode, + }, + create); +} const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), @@ -164,6 +174,8 @@ const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C), return rna_enum_context_mode_items; case SPACE_IMAGE: return rna_enum_space_image_mode_all_items; + case SPACE_SEQ: + return rna_enum_space_sequencer_view_type_items; } return DummyRNA_DEFAULT_items; } @@ -335,6 +347,16 @@ static void rna_def_workspace_tools(BlenderRNA *brna, PropertyRNA *cprop) /* return type */ parm = RNA_def_pointer(func, "result", "WorkSpaceTool", "", ""); RNA_def_function_return(func, parm); + + func = RNA_def_function( + srna, "from_space_sequencer", "rna_WorkSpace_tools_from_space_sequencer"); + RNA_def_function_ui_description(func, ""); + parm = RNA_def_enum(func, "mode", rna_enum_space_sequencer_view_type_items, 0, "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "create", false, "Create", ""); + /* return type */ + parm = RNA_def_pointer(func, "result", "WorkSpaceTool", "", ""); + RNA_def_function_return(func, parm); } static void rna_def_workspace(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 0bf1dd8e2b3..b070a3c7127 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -105,6 +105,7 @@ static void sphere_do(CastModifierData *cmd, int numVerts) { MDeformVert *dvert = NULL; + const bool invert_vgroup = (cmd->flag & MOD_CAST_INVERT_VGROUP) != 0; Object *ctrl_ob = NULL; @@ -198,7 +199,9 @@ static void sphere_do(CastModifierData *cmd, } if (dvert) { - const float weight = defvert_find_weight(&dvert[i], defgrp_index); + const float weight = invert_vgroup ? 1.0f - defvert_find_weight(&dvert[i], defgrp_index) : + defvert_find_weight(&dvert[i], defgrp_index); + if (weight == 0.0f) { continue; } @@ -240,6 +243,8 @@ static void cuboid_do(CastModifierData *cmd, int numVerts) { MDeformVert *dvert = NULL; + const bool invert_vgroup = (cmd->flag & MOD_CAST_INVERT_VGROUP) != 0; + Object *ctrl_ob = NULL; int i, defgrp_index; @@ -365,7 +370,9 @@ static void cuboid_do(CastModifierData *cmd, } if (dvert) { - const float weight = defvert_find_weight(&dvert[i], defgrp_index); + const float weight = invert_vgroup ? 1.0f - defvert_find_weight(&dvert[i], defgrp_index) : + defvert_find_weight(&dvert[i], defgrp_index); + if (weight == 0.0f) { continue; } diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 9cb694be88b..7f65b3bb5ae 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -174,6 +174,7 @@ static void displaceModifier_do_task(void *__restrict userdata, DisplaceUserdata *data = (DisplaceUserdata *)userdata; DisplaceModifierData *dmd = data->dmd; MDeformVert *dvert = data->dvert; + const bool invert_vgroup = (dmd->flag & MOD_DISP_INVERT_VGROUP) != 0; float weight = data->weight; int defgrp_index = data->defgrp_index; int direction = data->direction; @@ -192,7 +193,8 @@ static void displaceModifier_do_task(void *__restrict userdata, float local_vec[3]; if (dvert) { - weight = defvert_find_weight(dvert + iter, defgrp_index); + weight = invert_vgroup ? 1.0f - defvert_find_weight(dvert + iter, defgrp_index) : + defvert_find_weight(dvert + iter, defgrp_index); if (weight == 0.0f) { return; } diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 7155498c942..ba017577004 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -175,7 +175,7 @@ static void warpModifier_do(WarpModifierData *wmd, int i; int defgrp_index; MDeformVert *dvert, *dv = NULL; - + const bool invert_vgroup = (wmd->flag & MOD_WARP_INVERT_VGROUP) != 0; float(*tex_co)[3] = NULL; if (!(wmd->object_from && wmd->object_to)) { @@ -235,7 +235,8 @@ static void warpModifier_do(WarpModifierData *wmd, /* skip if no vert group found */ if (defgrp_index != -1) { dv = &dvert[i]; - weight = defvert_find_weight(dv, defgrp_index) * strength; + weight = invert_vgroup ? 1.0f - defvert_find_weight(dv, defgrp_index) * strength : + defvert_find_weight(dv, defgrp_index) * strength; if (weight <= 0.0f) { continue; } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c index ec4fedec27c..0dfacb19729 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c @@ -28,6 +28,7 @@ static bNodeSocketTemplate sh_node_tex_white_noise_in[] = { static bNodeSocketTemplate sh_node_tex_white_noise_out[] = { {SOCK_FLOAT, 0, N_("Value")}, + {SOCK_RGBA, 0, N_("Color")}, {-1, 0, ""}, }; diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 999cefde104..8f079a75f14 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -21,9 +21,9 @@ * \ingroup bph */ -extern "C" { #include "MEM_guardedalloc.h" +extern "C" { #include "DNA_cloth_types.h" #include "DNA_scene_types.h" #include "DNA_object_force_types.h" @@ -82,8 +82,13 @@ static float cloth_calc_volume(ClothModifierData *clmd) Implicit_Data *data = cloth->implicit; float vol = 0; + /* Early exit for hair, as it never has volume. */ + if (clmd->hairdata) { + return 0.0f; + } + if (clmd->sim_parms->vgroup_pressure > 0) { - for (unsigned int i = 0; i < cloth->tri_num; i++) { + for (unsigned int i = 0; i < cloth->primitive_num; i++) { bool skip_face = false; /* We have custom vertex weights for pressure. */ const MVertTri *vt = &tri[i]; @@ -103,7 +108,7 @@ static float cloth_calc_volume(ClothModifierData *clmd) } } else { - for (unsigned int i = 0; i < cloth->tri_num; i++) { + for (unsigned int i = 0; i < cloth->primitive_num; i++) { const MVertTri *vt = &tri[i]; vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]); } @@ -174,96 +179,17 @@ void BKE_cloth_solver_set_volume(ClothModifierData *clmd) cloth->initial_mesh_volume = cloth_calc_volume(clmd); } -static bool collision_response(ClothModifierData *clmd, - CollisionModifierData *collmd, - CollPair *collpair, - float dt, - float restitution, - float r_impulse[3]) -{ - Cloth *cloth = clmd->clothObject; - int index = collpair->ap1; - bool result = false; - - float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3]; - float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); - - float margin_distance = (float)collpair->distance - epsilon2; - float mag_v_rel; - - zero_v3(r_impulse); - - if (margin_distance > 0.0f) { - return false; /* XXX tested before already? */ - } - - /* only handle static collisions here */ - if (collpair->flag & COLLISION_IN_FUTURE) { - return false; - } - - /* velocity */ - copy_v3_v3(v1, cloth->verts[index].v); - collision_get_collider_velocity(v2_old, v2_new, collmd, collpair); - /* relative velocity = velocity of the cloth point relative to the collider */ - sub_v3_v3v3(v_rel_old, v1, v2_old); - sub_v3_v3v3(v_rel_new, v1, v2_new); - /* normal component of the relative velocity */ - mag_v_rel = dot_v3v3(v_rel_old, collpair->normal); - - /* only valid when moving toward the collider */ - if (mag_v_rel < -ALMOST_ZERO) { - float v_nor_old, v_nor_new; - float v_tan_old[3], v_tan_new[3]; - float bounce, repulse; - - /* Collision response based on - * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005) - * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf - */ - - v_nor_old = mag_v_rel; - v_nor_new = dot_v3v3(v_rel_new, collpair->normal); - - madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old); - madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new); - - bounce = -v_nor_old * restitution; - - repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */ - /* XXX this clamping factor is quite arbitrary ... - * not sure if there is a more scientific approach, but seems to give good results - */ - CLAMP(repulse, 0.0f, 4.0f * bounce); - - if (margin_distance < -epsilon2) { - mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new); - } - else { - bounce = 0.0f; - mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new); - } - - result = true; - } - - return result; -} - /* Init constraint matrix * This is part of the modified CG method suggested by Baraff/Witkin in * "Large Steps in Cloth Simulation" (Siggraph 1998) */ -static void cloth_setup_constraints(ClothModifierData *clmd, - ColliderContacts *contacts, - int totcolliders, - float dt) +static void cloth_setup_constraints(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; Implicit_Data *data = cloth->implicit; ClothVertex *verts = cloth->verts; int mvert_num = cloth->mvert_num; - int i, j, v; + int v; const float ZERO[3] = {0.0f, 0.0f, 0.0f}; @@ -277,37 +203,6 @@ static void cloth_setup_constraints(ClothModifierData *clmd, verts[v].impulse_count = 0; } - - for (i = 0; i < totcolliders; i++) { - ColliderContacts *ct = &contacts[i]; - for (j = 0; j < ct->totcollisions; j++) { - CollPair *collpair = &ct->collisions[j]; - // float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp); - float restitution = 0.0f; - int v = collpair->face1; - float impulse[3]; - - /* pinned verts handled separately */ - if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) { - continue; - } - - /* XXX cheap way of avoiding instability from multiple collisions in the same step - * this should eventually be supported ... - */ - if (verts[v].impulse_count > 0) { - continue; - } - - /* calculate collision response */ - if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse)) { - continue; - } - - BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse); - ++verts[v].impulse_count; - } - } } /* computes where the cloth would be if it were subject to perfectly stiff edges @@ -657,8 +552,8 @@ static void cloth_calc_force( #ifdef CLOTH_FORCE_DRAG BPH_mass_spring_force_drag(data, drag); #endif - /* handle pressure forces */ - if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) { + /* handle pressure forces (making sure that this never gets computed for hair). */ + if ((parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && (clmd->hairdata == NULL)) { /* The difference in pressure between the inside and outside of the mesh.*/ float pressure_difference = 0.0f; @@ -691,7 +586,7 @@ static void cloth_calc_force( pressure_difference *= clmd->sim_parms->pressure_factor; - for (i = 0; i < cloth->tri_num; i++) { + for (i = 0; i < cloth->primitive_num; i++) { const MVertTri *vt = &tri[i]; if (fabs(pressure_difference) > 1E-6f) { if (clmd->sim_parms->vgroup_pressure > 0) { @@ -744,13 +639,14 @@ static void cloth_calc_force( effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL); } - for (i = 0; i < cloth->tri_num; i++) { - const MVertTri *vt = &tri[i]; - BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); + /* Hair has only edges. */ + if ((clmd->hairdata == NULL) && (cloth->primitive_num > 0)) { + for (i = 0; i < cloth->primitive_num; i++) { + const MVertTri *vt = &tri[i]; + BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); + } } - - /* Hair has only edges */ - if (cloth->tri_num == 0) { + else { #if 0 ClothHairData *hairdata = clmd->hairdata; ClothHairData *hair_ij, *hair_kl; @@ -1241,8 +1137,6 @@ int BPH_cloth_solve( unsigned int mvert_num = cloth->mvert_num; float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale; Implicit_Data *id = cloth->implicit; - ColliderContacts *contacts = NULL; - int totcolliders = 0; BKE_sim_debug_data_clear_category("collision"); @@ -1269,25 +1163,8 @@ int BPH_cloth_solve( while (step < tf) { ImplicitSolverResult result; - if (is_hair) { - /* copy velocities for collision */ - for (i = 0; i < mvert_num; i++) { - BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv); - copy_v3_v3(verts[i].v, verts[i].tv); - } - - /* determine contact points */ - if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { - cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders); - } - - /* setup vertex constraints for pinned vertices and contacts */ - cloth_setup_constraints(clmd, contacts, totcolliders, dt); - } - else { - /* setup vertex constraints for pinned vertices */ - cloth_setup_constraints(clmd, NULL, 0, dt); - } + /* setup vertex constraints for pinned vertices */ + cloth_setup_constraints(clmd); /* initialize forces to zero */ BPH_mass_spring_clear_forces(id); @@ -1300,9 +1177,7 @@ int BPH_cloth_solve( cloth_record_result(clmd, &result, dt); /* Calculate collision impulses. */ - if (!is_hair) { - cloth_solve_collisions(depsgraph, ob, clmd, step, dt); - } + cloth_solve_collisions(depsgraph, ob, clmd, step, dt); if (is_hair) { cloth_continuum_step(clmd, dt); @@ -1327,11 +1202,6 @@ int BPH_cloth_solve( BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL); } - /* free contact points */ - if (contacts) { - cloth_free_contacts(contacts, totcolliders); - } - step += dt; } diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index fcb6a77bf36..859ece61ace 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1246,7 +1246,8 @@ PyDoc_STRVAR(M_Geometry_tessellate_polygon_doc, ".. function:: tessellate_polygon(veclist_list)\n" "\n" " Takes a list of polylines (each point a pair or triplet of numbers) and returns " - "the point indices for a polyline filled with triangles.\n" + "the point indices for a polyline filled with triangles. Does not handle degenerate " + "geometry (such as zero-length lines due to consecutive identical points).\n" "\n" " :arg veclist_list: list of polylines\n" " :rtype: list\n"); diff --git a/source/blender/usd/CMakeLists.txt b/source/blender/usd/CMakeLists.txt index f4cf53e573f..6ea02f44d76 100644 --- a/source/blender/usd/CMakeLists.txt +++ b/source/blender/usd/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC usd.h intern/abstract_hierarchy_iterator.h + intern/usd_exporter_context.h intern/usd_hierarchy_iterator.h intern/usd_writer_abstract.h intern/usd_writer_camera.h diff --git a/source/blender/usd/intern/usd_capi.cc b/source/blender/usd/intern/usd_capi.cc index a7c268bf754..83e11cd7bf3 100644 --- a/source/blender/usd/intern/usd_capi.cc +++ b/source/blender/usd/intern/usd_capi.cc @@ -24,6 +24,8 @@ #include <pxr/usd/usd/stage.h> #include <pxr/usd/usdGeom/tokens.h> +#include "MEM_guardedalloc.h" + extern "C" { #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -40,8 +42,6 @@ extern "C" { #include "BLI_path_util.h" #include "BLI_string.h" -#include "MEM_guardedalloc.h" - #include "WM_api.h" #include "WM_types.h" } diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 73fbde4148e..e7a4ca9a005 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC intern/wm_cursors.c intern/wm_dragdrop.c intern/wm_draw.c + intern/wm_event_query.c intern/wm_event_system.c intern/wm_files.c intern/wm_files_link.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index d24157a22a6..cfdb15026fd 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -205,11 +205,6 @@ void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *ar); void WM_cursor_warp(struct wmWindow *win, int x, int y); void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y); -float WM_cursor_pressure(const struct wmWindow *win); - -/* event map */ -int WM_userdef_event_map(int kmitype); -int WM_userdef_event_type_from_keymap_type(int kmitype); /* handlers */ @@ -250,6 +245,11 @@ wmKeyMapItem *WM_event_match_keymap_item(struct bContext *C, wmKeyMap *keymap, const struct wmEvent *event); +wmKeyMapItem *WM_event_match_keymap_item_from_handlers(struct bContext *C, + struct wmWindowManager *wm, + struct ListBase *handlers, + const struct wmEvent *event); + typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata); typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata); @@ -294,8 +294,6 @@ struct wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, /* mouse */ void WM_event_add_mousemove(const struct bContext *C); -bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); -bool WM_event_is_last_mousemove(const struct wmEvent *event); #ifdef WITH_INPUT_NDOF /* 3D mouse */ @@ -631,15 +629,9 @@ bool WM_gesture_is_modal_first(const struct wmGesture *gesture); /* fileselecting support */ void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op); void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval); -int WM_event_modifier_flag(const struct wmEvent *event); -void WM_event_print(const struct wmEvent *event); void WM_operator_region_active_win_set(struct bContext *C); -int WM_event_drag_threshold(const struct wmEvent *event); -bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]); -bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]); - /* drag and drop */ struct wmDrag *WM_event_start_drag( struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags); @@ -783,6 +775,36 @@ bool write_crash_blend(void); /* Lock the interface for any communication */ void WM_set_locked_interface(struct wmWindowManager *wm, bool lock); +/* For testing only 'G_FLAG_EVENT_SIMULATE' */ +struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add); + +const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, + int button_index, + int type_index); +void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win); + +void WM_window_status_area_tag_redraw(struct wmWindow *win); +struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc); +bool WM_window_modal_keymap_status_draw(struct bContext *C, + struct wmWindow *win, + struct uiLayout *layout); + +/* wm_event_query.c */ +void WM_event_print(const struct wmEvent *event); + +int WM_event_modifier_flag(const struct wmEvent *event); + +bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); +bool WM_event_is_last_mousemove(const struct wmEvent *event); + +int WM_event_drag_threshold(const struct wmEvent *event); +bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]); +bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]); + +/* event map */ +int WM_userdef_event_map(int kmitype); +int WM_userdef_event_type_from_keymap_type(int kmitype); + #ifdef WITH_INPUT_NDOF void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof, float r_pan[3], @@ -800,20 +822,6 @@ bool WM_event_is_tablet(const struct wmEvent *event); bool WM_event_is_ime_switch(const struct wmEvent *event); #endif -/* For testing only 'G_FLAG_EVENT_SIMULATE' */ -struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add); - -const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, - int button_index, - int type_index); -void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win); - -void WM_window_status_area_tag_redraw(struct wmWindow *win); -struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc); -bool WM_window_modal_keymap_status_draw(struct bContext *C, - struct wmWindow *win, - struct uiLayout *layout); - /* wm_tooltip.c */ typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C, struct ARegion *ar, diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h index 620150ba14f..36cb5be7547 100644 --- a/source/blender/windowmanager/WM_toolsystem.h +++ b/source/blender/windowmanager/WM_toolsystem.h @@ -41,8 +41,8 @@ struct wmOperatorType; /* wm_toolsystem.c */ -#define WM_TOOLSYSTEM_SPACE_MASK ((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D)) - +#define WM_TOOLSYSTEM_SPACE_MASK \ + ((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D) | (1 << SPACE_SEQ)) /* Values that define a categoey of active tool. */ typedef struct bToolKey { int space_type; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 0c3a5f92113..5870802d02b 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -505,6 +505,19 @@ typedef struct wmGesture { /* ************** wmEvent ************************ */ +typedef struct wmTabletData { + /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */ + int active; + /** range 0.0 (not touching) to 1.0 (full pressure). */ + float pressure; + /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */ + float x_tilt; + /** as above. */ + float y_tilt; + /** Interpret mouse motion as absolute as typical for tablets. */ + char is_motion_absolute; +} wmTabletData; + /** * Each event should have full modifier state. * event comes from event manager and from keymap. @@ -546,13 +559,9 @@ typedef struct wmEvent { /** Set in case a #KM_PRESS went by unhandled. */ char check_click; char check_drag; - char is_motion_absolute; - /** Keymap item, set by handler (weak?). */ - const char *keymap_idname; - - /** Tablet info, only use when the tablet is active. */ - const struct wmTabletData *tablet_data; + /** Tablet info, available for mouse move and button events. */ + wmTabletData tablet; /* custom data */ /** Custom data type, stylus, 6dof, see wm_event_types.h */ @@ -580,18 +589,6 @@ bool WM_event_cursor_click_drag_threshold_met(const wmEvent *event); */ #define WM_EVENT_CURSOR_MOTION_THRESHOLD ((float)U.move_threshold * U.dpi_fac) -/* ************** custom wmEvent data ************** */ -typedef struct wmTabletData { - /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */ - int Active; - /** range 0.0 (not touching) to 1.0 (full pressure). */ - float Pressure; - /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */ - float Xtilt; - /** as above. */ - float Ytilt; -} wmTabletData; - /** Motion progress, for modal handlers. */ typedef enum { P_NOT_STARTED, diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 59975080f49..383ca806d35 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -1088,7 +1088,7 @@ void wm_gizmomap_modal_set( gz->state |= WM_GIZMO_STATE_MODAL; gzmap->gzmap_context.modal = gz; - if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->is_motion_absolute == false)) { + if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->tablet.is_motion_absolute == false)) { WM_cursor_grab_enable(win, WM_CURSOR_WRAP_XY, true, NULL); copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x); gzmap->gzmap_context.event_grabcursor = win->grabcursor; diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 8e796a7981a..b82865a727d 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -304,8 +304,7 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4]) if ((G.debug & G_DEBUG) == 0) { if (win->ghostwin) { - /* Note: There is no tabletdata on Windows if no tablet device is connected. */ - if (win->eventstate->is_motion_absolute == false) { + if (win->eventstate->tablet.is_motion_absolute == false) { GHOST_SetCursorGrab(win->ghostwin, mode, mode_axis, bounds, NULL); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 09b7d89fc2b..a26a728461d 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -514,12 +514,12 @@ void wm_draw_region_blend(ARegion *ar, int view, bool blend) /* Slide vertical panels */ float ofs_x = BLI_rcti_size_x(&ar->winrct) * (1.0f - alpha_easing); - if (ar->alignment == RGN_ALIGN_RIGHT) { + if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT) { rect_geo.xmin += ofs_x; rect_tex.xmax *= alpha_easing; alpha = 1.0f; } - else if (ar->alignment == RGN_ALIGN_LEFT) { + else if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_LEFT) { rect_geo.xmax -= ofs_x; rect_tex.xmin += 1.0f - alpha_easing; alpha = 1.0f; @@ -581,7 +581,14 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) /* Compute UI layouts for dynamically size regions. */ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->visible && ar->do_draw && ar->type && ar->type->layout) { + /* Dynamic region may have been flagged as too small because their size on init is 0. + * ARegion.visible is false then, as expected. The layout should still be created then, so + * the region size can be updated (it may turn out to be not too small then). */ + const bool ignore_visibility = (ar->flag & RGN_FLAG_DYNAMIC_SIZE) && + (ar->flag & RGN_FLAG_TOO_SMALL) && + !(ar->flag & RGN_FLAG_HIDDEN); + + if ((ar->visible || ignore_visibility) && ar->do_draw && ar->type && ar->type->layout) { CTX_wm_region_set(C, ar); ED_region_do_layout(C, ar); CTX_wm_region_set(C, NULL); diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c new file mode 100644 index 00000000000..3cec185fd36 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -0,0 +1,427 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + * + * Read-only queries utility functions for the event system. + */ + +#include <stdlib.h> +#include <string.h> + +#include "DNA_listBase.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "wm_event_system.h" +#include "wm_event_types.h" + +#include "RNA_enum_types.h" + +#include "DEG_depsgraph.h" + +/* -------------------------------------------------------------------- */ +/** \name Event Printing + * \{ */ + +/* for debugging only, getting inspecting events manually is tedious */ +void WM_event_print(const wmEvent *event) +{ + if (event) { + const char *unknown = "UNKNOWN"; + const char *type_id = unknown; + const char *val_id = unknown; + + RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id); + RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id); + + printf( + "wmEvent type:%d / %s, val:%d / %s,\n" + " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n" + " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n", + event->type, + type_id, + event->val, + val_id, + event->shift, + event->ctrl, + event->alt, + event->oskey, + event->keymodifier, + event->x, + event->y, + event->ascii, + BLI_str_utf8_size(event->utf8_buf), + event->utf8_buf, + (const void *)event); + +#ifdef WITH_INPUT_NDOF + if (ISNDOF(event->type)) { + const wmNDOFMotionData *ndof = event->customdata; + if (event->type == NDOF_MOTION) { + printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n", + UNPACK3(ndof->rvec), + UNPACK3(ndof->tvec), + ndof->dt, + ndof->progress); + } + else { + /* ndof buttons printed already */ + } + } +#endif /* WITH_INPUT_NDOF */ + + if (event->tablet.active != EVT_TABLET_NONE) { + const wmTabletData *wmtab = &event->tablet; + printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n", + wmtab->active, + wmtab->pressure, + wmtab->x_tilt, + wmtab->y_tilt); + } + } + else { + printf("wmEvent - NULL\n"); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Modifier/Type Queries + * \{ */ + +int WM_event_modifier_flag(const wmEvent *event) +{ + int flag = 0; + if (event->ctrl) { + flag |= KM_CTRL; + } + if (event->alt) { + flag |= KM_ALT; + } + if (event->shift) { + flag |= KM_SHIFT; + } + if (event->oskey) { + flag |= KM_OSKEY; + } + return flag; +} + +bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask) +{ + /* Keyboard. */ + if (mask & EVT_TYPE_MASK_KEYBOARD) { + if (ISKEYBOARD(event_type)) { + return true; + } + } + else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) { + if (ISKEYMODIFIER(event_type)) { + return true; + } + } + + /* Mouse. */ + if (mask & EVT_TYPE_MASK_MOUSE) { + if (ISMOUSE(event_type)) { + return true; + } + } + else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) { + if (ISMOUSE_WHEEL(event_type)) { + return true; + } + } + else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) { + if (ISMOUSE_GESTURE(event_type)) { + return true; + } + } + + /* Tweak. */ + if (mask & EVT_TYPE_MASK_TWEAK) { + if (ISTWEAK(event_type)) { + return true; + } + } + + /* Action Zone. */ + if (mask & EVT_TYPE_MASK_ACTIONZONE) { + if (IS_EVENT_ACTIONZONE(event_type)) { + return true; + } + } + + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Motion Queries + * \{ */ + +/* for modal callbacks, check configuration for how to interpret exit with tweaks */ +bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) +{ + /* if the release-confirm userpref setting is enabled, + * tweak events can be canceled when mouse is released + */ + if (U.flag & USER_RELEASECONFIRM) { + /* option on, so can exit with km-release */ + if (event->val == KM_RELEASE) { + switch (tweak_event) { + case EVT_TWEAK_L: + case EVT_TWEAK_M: + case EVT_TWEAK_R: + return 1; + } + } + else { + /* if the initial event wasn't a tweak event then + * ignore USER_RELEASECONFIRM setting: see [#26756] */ + if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { + return 1; + } + } + } + else { + /* this is fine as long as not doing km-release, otherwise + * some items (i.e. markers) being tweaked may end up getting + * dropped all over + */ + if (event->val != KM_RELEASE) { + return 1; + } + } + + return 0; +} + +bool WM_event_is_last_mousemove(const wmEvent *event) +{ + while ((event = event->next)) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + return false; + } + } + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Click/Drag Checks + * + * Values under this limit are detected as clicks. + * + * \{ */ + +int WM_event_drag_threshold(const struct wmEvent *event) +{ + int drag_threshold; + if (WM_event_is_tablet(event)) { + drag_threshold = U.drag_threshold_tablet; + } + else if (ISMOUSE(event->prevtype)) { + drag_threshold = U.drag_threshold_mouse; + } + else { + /* Typically keyboard, could be NDOF button or other less common types. */ + drag_threshold = U.drag_threshold; + } + return drag_threshold * U.dpi_fac; +} + +bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2]) +{ + const int drag_threshold = WM_event_drag_threshold(event); + return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold; +} + +bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2]) +{ + const int drag_delta[2] = { + prev_xy[0] - event->x, + prev_xy[1] - event->y, + }; + return WM_event_drag_test_with_delta(event, drag_delta); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Preference Mapping + * \{ */ + +int WM_userdef_event_map(int kmitype) +{ + switch (kmitype) { + case WHEELOUTMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE; + case WHEELINMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; + } + + return kmitype; +} + +/** + * Use so we can check if 'wmEvent.type' is released in modal operators. + * + * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar. + */ +int WM_userdef_event_type_from_keymap_type(int kmitype) +{ + switch (kmitype) { + case EVT_TWEAK_L: + return LEFTMOUSE; + case EVT_TWEAK_M: + return MIDDLEMOUSE; + case EVT_TWEAK_R: + return RIGHTMOUSE; + case WHEELOUTMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE; + case WHEELINMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; + } + + return kmitype; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event NDOF Input Access + * \{ */ + +#ifdef WITH_INPUT_NDOF + +void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom) +{ + int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS; + r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f); + r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f); + r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f); +} + +void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3]) +{ + r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f); + r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f); + r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f); +} + +float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]) +{ + float angle; + angle = normalize_v3_v3(axis, ndof->rvec); + + axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f); + axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f); + axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f); + + return ndof->dt * angle; +} + +void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]) +{ + float axis[3]; + float angle; + + angle = WM_event_ndof_to_axis_angle(ndof, axis); + axis_angle_to_quat(q, axis, angle); +} +#endif /* WITH_INPUT_NDOF */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Tablet Input Access + * \{ */ + +/* applies the global tablet pressure correction curve */ +float wm_pressure_curve(float pressure) +{ + if (U.pressure_threshold_max != 0.0f) { + pressure /= U.pressure_threshold_max; + } + + CLAMP(pressure, 0.0f, 1.0f); + + if (U.pressure_softness != 0.0f) { + pressure = powf(pressure, powf(4.0f, -U.pressure_softness)); + } + + return pressure; +} + +/* if this is a tablet event, return tablet pressure and set *pen_flip + * to 1 if the eraser tool is being used, 0 otherwise */ +float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2]) +{ + if (tilt) { + tilt[0] = event->tablet.x_tilt; + tilt[1] = event->tablet.y_tilt; + } + + if (pen_flip) { + (*pen_flip) = (event->tablet.active == EVT_TABLET_ERASER); + } + + return event->tablet.pressure; +} + +bool WM_event_is_tablet(const struct wmEvent *event) +{ + return (event->tablet.active != EVT_TABLET_NONE); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event IME Input Access + * \{ */ + +#ifdef WITH_INPUT_IME +/* most os using ctrl/oskey + space to switch ime, avoid added space */ +bool WM_event_is_ime_switch(const struct wmEvent *event) +{ + return event->val == KM_PRESS && event->type == SPACEKEY && + (event->ctrl || event->oskey || event->shift || event->alt); +} +#endif + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f5970e8fb61..7339f463855 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -70,7 +70,6 @@ #include "RNA_access.h" #include "UI_interface.h" -#include "UI_view2d.h" #include "PIL_time.h" @@ -84,8 +83,6 @@ #include "wm_event_system.h" #include "wm_event_types.h" -#include "RNA_enum_types.h" - #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -104,7 +101,6 @@ #define USE_GIZMO_MOUSE_PRIORITY_HACK static void wm_notifier_clear(wmNotifier *note); -static void update_tablet_data(wmWindow *win, wmEvent *event); static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, @@ -114,6 +110,8 @@ static int wm_operator_call_internal(bContext *C, const bool poll_only, wmEvent *event); +static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot); + /* -------------------------------------------------------------------- */ /** \name Event Management * \{ */ @@ -126,14 +124,6 @@ wmEvent *wm_event_add_ex(wmWindow *win, *event = *event_to_add; - update_tablet_data(win, event); - - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - /* We could have a preference to support relative tablet motion (we can't detect that). */ - event->is_motion_absolute = ((event->tablet_data != NULL) && - (event->tablet_data->Active != GHOST_kTabletModeNone)); - } - if (event_to_add_after == NULL) { BLI_addtail(&win->queue, event); } @@ -177,10 +167,6 @@ void wm_event_free(wmEvent *event) } } - if (event->tablet_data) { - MEM_freeN((void *)event->tablet_data); - } - MEM_freeN(event); } @@ -195,9 +181,6 @@ void wm_event_free_all(wmWindow *win) void wm_event_init_from_window(wmWindow *win, wmEvent *event) { - /* make sure we don't copy any owned pointers */ - BLI_assert(win->eventstate->tablet_data == NULL); - *event = *(win->eventstate); } @@ -682,6 +665,82 @@ static void wm_handler_ui_cancel(bContext *C) /** \} */ /* -------------------------------------------------------------------- */ +/** \name WM Reports + * + * Access to #wmWindowManager.reports + * \{ */ + +/** + * Show the report in the info header. + */ +void WM_report_banner_show(void) +{ + wmWindowManager *wm = G_MAIN->wm.first; + ReportList *wm_reports = &wm->reports; + ReportTimerInfo *rti; + + /* After adding reports to the global list, reset the report timer. */ + WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); + + /* Records time since last report was added */ + wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05); + + rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); + wm_reports->reporttimer->customdata = rti; +} + +#ifdef WITH_INPUT_NDOF +void WM_ndof_deadzone_set(float deadzone) +{ + GHOST_setNDOFDeadZone(deadzone); +} +#endif + +static void wm_add_reports(ReportList *reports) +{ + /* if the caller owns them, handle this */ + if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) { + wmWindowManager *wm = G_MAIN->wm.first; + + /* add reports to the global list, otherwise they are not seen */ + BLI_movelisttolist(&wm->reports.list, &reports->list); + + WM_report_banner_show(); + } +} + +void WM_report(ReportType type, const char *message) +{ + ReportList reports; + + BKE_reports_init(&reports, RPT_STORE); + BKE_report(&reports, type, message); + + wm_add_reports(&reports); + + BKE_reports_clear(&reports); +} + +void WM_reportf(ReportType type, const char *format, ...) +{ + DynStr *ds; + va_list args; + + ds = BLI_dynstr_new(); + va_start(args, format); + BLI_dynstr_vappendf(ds, format, args); + va_end(args); + + char *str = BLI_dynstr_get_cstring(ds); + WM_report(type, str); + MEM_freeN(str); + + BLI_dynstr_free(ds); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Operator Logic * \{ */ @@ -762,164 +821,6 @@ void WM_operator_region_active_win_set(bContext *C) } } -int WM_event_modifier_flag(const wmEvent *event) -{ - int flag = 0; - if (event->ctrl) { - flag |= KM_CTRL; - } - if (event->alt) { - flag |= KM_ALT; - } - if (event->shift) { - flag |= KM_SHIFT; - } - if (event->oskey) { - flag |= KM_OSKEY; - } - return flag; -} - -/* for debugging only, getting inspecting events manually is tedious */ -void WM_event_print(const wmEvent *event) -{ - if (event) { - const char *unknown = "UNKNOWN"; - const char *type_id = unknown; - const char *val_id = unknown; - - RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id); - RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id); - - printf( - "wmEvent type:%d / %s, val:%d / %s,\n" - " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n" - " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n", - event->type, - type_id, - event->val, - val_id, - event->shift, - event->ctrl, - event->alt, - event->oskey, - event->keymodifier, - event->x, - event->y, - event->ascii, - BLI_str_utf8_size(event->utf8_buf), - event->utf8_buf, - event->keymap_idname, - (const void *)event); - -#ifdef WITH_INPUT_NDOF - if (ISNDOF(event->type)) { - const wmNDOFMotionData *ndof = event->customdata; - if (event->type == NDOF_MOTION) { - printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n", - UNPACK3(ndof->rvec), - UNPACK3(ndof->tvec), - ndof->dt, - ndof->progress); - } - else { - /* ndof buttons printed already */ - } - } -#endif /* WITH_INPUT_NDOF */ - - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n", - wmtab->Active, - wmtab->Pressure, - wmtab->Xtilt, - wmtab->Ytilt); - } - } - else { - printf("wmEvent - NULL\n"); - } -} - -/** - * Show the report in the info header. - */ -void WM_report_banner_show(void) -{ - wmWindowManager *wm = G_MAIN->wm.first; - ReportList *wm_reports = &wm->reports; - ReportTimerInfo *rti; - - /* After adding reports to the global list, reset the report timer. */ - WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); - - /* Records time since last report was added */ - wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05); - - rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); - wm_reports->reporttimer->customdata = rti; -} - -bool WM_event_is_last_mousemove(const wmEvent *event) -{ - while ((event = event->next)) { - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - return false; - } - } - return true; -} - -#ifdef WITH_INPUT_NDOF -void WM_ndof_deadzone_set(float deadzone) -{ - GHOST_setNDOFDeadZone(deadzone); -} -#endif - -static void wm_add_reports(ReportList *reports) -{ - /* if the caller owns them, handle this */ - if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) { - wmWindowManager *wm = G_MAIN->wm.first; - - /* add reports to the global list, otherwise they are not seen */ - BLI_movelisttolist(&wm->reports.list, &reports->list); - - WM_report_banner_show(); - } -} - -void WM_report(ReportType type, const char *message) -{ - ReportList reports; - - BKE_reports_init(&reports, RPT_STORE); - BKE_report(&reports, type, message); - - wm_add_reports(&reports); - - BKE_reports_clear(&reports); -} - -void WM_reportf(ReportType type, const char *format, ...) -{ - DynStr *ds; - va_list args; - - ds = BLI_dynstr_new(); - va_start(args, format); - BLI_dynstr_vappendf(ds, format, args); - va_end(args); - - char *str = BLI_dynstr_get_cstring(ds); - WM_report(type, str); - MEM_freeN(str); - - BLI_dynstr_free(ds); -} - /* (caller_owns_reports == true) when called from python */ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports) { @@ -1301,105 +1202,6 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event) } } -#if 1 /* may want to disable operator remembering previous state for testing */ - -static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties) -{ - bool changed = false; - IDPropertyTemplate val = {0}; - IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); - PropertyRNA *iterprop; - - CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname); - - iterprop = RNA_struct_iterator_property(op->type->srna); - - RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) { - PropertyRNA *prop = itemptr.data; - if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) { - if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */ - const char *identifier = RNA_property_identifier(prop); - IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier); - if (idp_src) { - IDProperty *idp_dst = IDP_CopyProperty(idp_src); - - /* note - in the future this may need to be done recursively, - * but for now RNA doesn't access nested operators */ - idp_dst->flag |= IDP_FLAG_GHOST; - - /* add to temporary group instead of immediate replace, - * because we are iterating over this group */ - IDP_AddToGroup(replaceprops, idp_dst); - changed = true; - } - } - } - } - RNA_PROP_END; - - IDP_MergeGroup(op->properties, replaceprops, true); - IDP_FreeProperty(replaceprops); - return changed; -} - -bool WM_operator_last_properties_init(wmOperator *op) -{ - bool changed = false; - if (op->type->last_properties) { - changed |= operator_last_properties_init_impl(op, op->type->last_properties); - for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { - IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname); - if (idp_src) { - changed |= operator_last_properties_init_impl(opm, idp_src); - } - } - } - return changed; -} - -bool WM_operator_last_properties_store(wmOperator *op) -{ - if (op->type->last_properties) { - IDP_FreeProperty(op->type->last_properties); - op->type->last_properties = NULL; - } - - if (op->properties) { - CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname); - op->type->last_properties = IDP_CopyProperty(op->properties); - } - - if (op->macro.first != NULL) { - for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { - if (opm->properties) { - if (op->type->last_properties == NULL) { - op->type->last_properties = IDP_New( - IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties"); - } - IDProperty *idp_macro = IDP_CopyProperty(opm->properties); - STRNCPY(idp_macro->name, opm->type->idname); - IDP_ReplaceInGroup(op->type->last_properties, idp_macro); - } - } - } - - return (op->type->last_properties != NULL); -} - -#else - -bool WM_operator_last_properties_init(wmOperator *UNUSED(op)) -{ - return false; -} - -bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) -{ - return false; -} - -#endif - /** * Also used for exec when 'event' is NULL. */ @@ -1954,42 +1756,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) } } -/* do userdef mappings */ -int WM_userdef_event_map(int kmitype) -{ - switch (kmitype) { - case WHEELOUTMOUSE: - return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE; - case WHEELINMOUSE: - return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; - } - - return kmitype; -} - -/** - * Use so we can check if 'wmEvent.type' is released in modal operators. - * - * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar. - */ -int WM_userdef_event_type_from_keymap_type(int kmitype) -{ - switch (kmitype) { - case EVT_TWEAK_L: - return LEFTMOUSE; - case EVT_TWEAK_M: - return MIDDLEMOUSE; - case EVT_TWEAK_R: - return RIGHTMOUSE; - case WHEELOUTMOUSE: - return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE; - case WHEELINMOUSE: - return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; - } - - return kmitype; -} - static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi) { if (kmi->flag & KMI_INACTIVE) { @@ -2011,19 +1777,16 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi) if (kmitype != KM_ANY) { if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) { - const wmTabletData *wmtab = winevent->tablet_data; + const wmTabletData *wmtab = &winevent->tablet; - if (wmtab == NULL) { - return false; - } - else if (winevent->type != LEFTMOUSE) { + if (winevent->type != LEFTMOUSE) { /* tablet events can occur on hover + keypress */ return false; } - else if ((kmitype == TABLET_STYLUS) && (wmtab->Active != EVT_TABLET_STYLUS)) { + else if ((kmitype == TABLET_STYLUS) && (wmtab->active != EVT_TABLET_STYLUS)) { return false; } - else if ((kmitype == TABLET_ERASER) && (wmtab->Active != EVT_TABLET_ERASER)) { + else if ((kmitype == TABLET_ERASER) && (wmtab->active != EVT_TABLET_ERASER)) { return false; } } @@ -2103,10 +1866,10 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, * This is done since we only want to use double click events to match key-map items, * allowing modal functions to check for press/release events without having to interpret them. */ -static void wm_event_modalkeymap(const bContext *C, - wmOperator *op, - wmEvent *event, - bool *dbl_click_disabled) +static void wm_event_modalkeymap_begin(const bContext *C, + wmOperator *op, + wmEvent *event, + bool *dbl_click_disabled) { BLI_assert(event->type != EVT_MODAL_MAP); @@ -2159,25 +1922,13 @@ static void wm_event_modalkeymap(const bContext *C, } /** - * Check whether operator is allowed to run in case interface is locked, - * If interface is unlocked, will always return truth. + * Restore changes from #wm_event_modalkeymap_begin + * + * \warning bad hacking event system... + * better restore event type for checking of #KM_CLICK for example. + * Modal maps could use different method (ton). */ -static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot) -{ - wmWindowManager *wm = CTX_wm_manager(C); - - if (wm->is_interface_locked) { - if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) { - return false; - } - } - - return true; -} - -/* bad hacking event system... better restore event type for checking of KM_CLICK for example */ -/* XXX modal maps could use different method (ton) */ -static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled) +static void wm_event_modalkeymap_end(wmEvent *event, bool dbl_click_disabled) { if (event->type == EVT_MODAL_MAP) { event->type = event->prevtype; @@ -2196,7 +1947,8 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler_base, wmEvent *event, - PointerRNA *properties) + PointerRNA *properties, + const char *kmi_idname) { int retval = OPERATOR_PASS_THROUGH; @@ -2221,7 +1973,7 @@ static int wm_handler_operator_call(bContext *C, wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); - wm_event_modalkeymap(C, op, event, &dbl_click_disabled); + wm_event_modalkeymap_begin(C, op, event, &dbl_click_disabled); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth++; @@ -2236,7 +1988,7 @@ static int wm_handler_operator_call(bContext *C, * the event, operator etc have all been freed. - campbell */ if (CTX_wm_manager(C) == wm) { - wm_event_modalmap_end(event, dbl_click_disabled); + wm_event_modalkeymap_end(event, dbl_click_disabled); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth--; @@ -2298,7 +2050,7 @@ static int wm_handler_operator_call(bContext *C, } } else { - wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0); + wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0); if (ot && wm_operator_check_locked_interface(C, ot)) { bool use_last_properties = true; @@ -2636,10 +2388,8 @@ static int wm_handlers_do_keymap_with_keymap_handler( PRINT("%s: item matched '%s'\n", __func__, kmi->idname); - /* weak, but allows interactive callback to not use rawkey */ - event->keymap_idname = kmi->idname; - - action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr); + action |= wm_handler_operator_call( + C, handlers, &handler->head, event, kmi->ptr, kmi->idname); if (action & WM_HANDLER_BREAK) { /* not always_pass here, it denotes removed handler_base */ @@ -2693,13 +2443,11 @@ static int wm_handlers_do_keymap_with_gizmo_handler( if (wm_eventmatch(event, kmi)) { PRINT("%s: item matched '%s'\n", __func__, kmi->idname); - /* weak, but allows interactive callback to not use rawkey */ - event->keymap_idname = kmi->idname; - CTX_wm_gizmo_group_set(C, gzgroup); /* handler->op is called later, we want keymap op to be triggered here */ - action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr); + action |= wm_handler_operator_call( + C, handlers, &handler->head, event, kmi->ptr, kmi->idname); CTX_wm_gizmo_group_set(C, NULL); @@ -2990,7 +2738,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } else { - action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL); + action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL); } } else { @@ -4099,91 +3847,6 @@ void WM_event_add_mousemove(const bContext *C) window->addmousemove = 1; } -/* for modal callbacks, check configuration for how to interpret exit with tweaks */ -bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) -{ - /* if the release-confirm userpref setting is enabled, - * tweak events can be canceled when mouse is released - */ - if (U.flag & USER_RELEASECONFIRM) { - /* option on, so can exit with km-release */ - if (event->val == KM_RELEASE) { - switch (tweak_event) { - case EVT_TWEAK_L: - case EVT_TWEAK_M: - case EVT_TWEAK_R: - return 1; - } - } - else { - /* if the initial event wasn't a tweak event then - * ignore USER_RELEASECONFIRM setting: see [#26756] */ - if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { - return 1; - } - } - } - else { - /* this is fine as long as not doing km-release, otherwise - * some items (i.e. markers) being tweaked may end up getting - * dropped all over - */ - if (event->val != KM_RELEASE) { - return 1; - } - } - - return 0; -} - -bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask) -{ - /* Keyboard. */ - if (mask & EVT_TYPE_MASK_KEYBOARD) { - if (ISKEYBOARD(event_type)) { - return true; - } - } - else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) { - if (ISKEYMODIFIER(event_type)) { - return true; - } - } - - /* Mouse. */ - if (mask & EVT_TYPE_MASK_MOUSE) { - if (ISMOUSE(event_type)) { - return true; - } - } - else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) { - if (ISMOUSE_WHEEL(event_type)) { - return true; - } - } - else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) { - if (ISMOUSE_GESTURE(event_type)) { - return true; - } - } - - /* Tweak. */ - if (mask & EVT_TYPE_MASK_TWEAK) { - if (ISTWEAK(event_type)) { - return true; - } - } - - /* Action Zone. */ - if (mask & EVT_TYPE_MASK_ACTIONZONE) { - if (IS_EVENT_ACTIONZONE(event_type)) { - return true; - } - } - - return false; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -4421,41 +4084,23 @@ static void wm_eventemulation(wmEvent *event, bool test_only) } } -/* applies the global tablet pressure correction curve */ -float wm_pressure_curve(float pressure) +void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab) { - if (U.pressure_threshold_max != 0.0f) { - pressure /= U.pressure_threshold_max; - } - - CLAMP(pressure, 0.0f, 1.0f); - - if (U.pressure_softness != 0.0f) { - pressure = powf(pressure, powf(4.0f, -U.pressure_softness)); - } - - return pressure; -} - -/* adds customdata to event */ -static void update_tablet_data(wmWindow *win, wmEvent *event) -{ - const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin); - - /* if there's tablet data from an active tablet device then add it */ - if ((td != NULL) && td->Active != GHOST_kTabletModeNone) { - struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet"); - - wmtab->Active = (int)td->Active; - wmtab->Pressure = wm_pressure_curve(td->Pressure); - wmtab->Xtilt = td->Xtilt; - wmtab->Ytilt = td->Ytilt; - - event->tablet_data = wmtab; - // printf("%s: using tablet %.5f\n", __func__, wmtab->Pressure); + if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) { + wmtab->active = (int)tablet_data->Active; + wmtab->pressure = wm_pressure_curve(tablet_data->Pressure); + wmtab->x_tilt = tablet_data->Xtilt; + wmtab->y_tilt = tablet_data->Ytilt; + /* We could have a preference to support relative tablet motion (we can't detect that). */ + wmtab->is_motion_absolute = true; + // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure); } else { - event->tablet_data = NULL; + wmtab->active = EVT_TABLET_NONE; + wmtab->pressure = 1.0f; + wmtab->x_tilt = 0.0f; + wmtab->y_tilt = 0.0f; + wmtab->is_motion_absolute = false; // printf("%s: not using tablet\n", __func__); } } @@ -4607,6 +4252,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void copy_v2_v2_int(&event.x, &cd->x); wm_stereo3d_mouse_offset_apply(win, &event.x); + wm_tablet_data_from_ghost(&cd->tablet, &event.tablet); event.prevtype = event.type; event.prevval = event.val; @@ -4614,7 +4260,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void { wmEvent *event_new = wm_event_add_mousemove(win, &event); copy_v2_v2_int(&evt->x, &event_new->x); - evt->is_motion_absolute = event_new->is_motion_absolute; + evt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; } /* also add to other window if event is there, this makes overdraws disappear nicely */ @@ -4632,7 +4278,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void { wmEvent *event_new = wm_event_add_mousemove(owin, &oevent); copy_v2_v2_int(&oevt->x, &event_new->x); - oevt->is_motion_absolute = event_new->is_motion_absolute; + oevt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; } } @@ -4646,6 +4292,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void pd->deltaX = -pd->deltaX; pd->deltaY = -pd->deltaY; break; + case GHOST_kTrackpadEventSmartMagnify: + event.type = MOUSESMARTZOOM; + break; case GHOST_kTrackpadEventRotate: event.type = MOUSEROTATE; break; @@ -4696,6 +4345,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void event.type = MIDDLEMOUSE; } + /* Get tablet data. */ + wm_tablet_data_from_ghost(&bd->tablet, &event.tablet); + wm_eventemulation(&event, false); /* copy previous state to prev event state (two old!) */ @@ -4706,17 +4358,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void evt->val = event.val; evt->type = event.type; - if (win->active == 0) { - int cx, cy; - - /* Entering window, update mouse pos. - * (ghost sends win-activate *after* the mouseclick in window!) */ - wm_get_cursor_position(win, &cx, &cy); - - event.x = evt->x = cx; - event.y = evt->y = cy; - } - /* double click test */ if (wm_event_is_double_click(&event, evt)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); @@ -4737,6 +4378,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void oevent.y = event.y; oevent.type = event.type; oevent.val = event.val; + oevent.tablet = event.tablet; wm_event_add(owin, &oevent); } @@ -5003,6 +4645,29 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void #endif } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name WM Interface Locking + * \{ */ + +/** + * Check whether operator is allowed to run in case interface is locked, + * If interface is unlocked, will always return truth. + */ +static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + if (wm->is_interface_locked) { + if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) { + return false; + } + } + + return true; +} + void WM_set_locked_interface(wmWindowManager *wm, bool lock) { /* This will prevent events from being handled while interface is locked @@ -5024,96 +4689,12 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock) BKE_spacedata_draw_locks(lock); } -#ifdef WITH_INPUT_NDOF +/** \} */ /* -------------------------------------------------------------------- */ -/** \name NDOF Utility Functions +/** \name Event / Keymap Matching API * \{ */ -void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom) -{ - int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS; - r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f); - r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f); - r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f); -} - -void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3]) -{ - r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f); - r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f); - r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f); -} - -float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]) -{ - float angle; - angle = normalize_v3_v3(axis, ndof->rvec); - - axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f); - axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f); - axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f); - - return ndof->dt * angle; -} - -void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]) -{ - float axis[3]; - float angle; - - angle = WM_event_ndof_to_axis_angle(ndof, axis); - axis_angle_to_quat(q, axis, angle); -} -#endif /* WITH_INPUT_NDOF */ - -/* if this is a tablet event, return tablet pressure and set *pen_flip - * to 1 if the eraser tool is being used, 0 otherwise */ -float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2]) -{ - int erasor = 0; - float pressure = 1; - - if (tilt) { - zero_v2(tilt); - } - - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - - erasor = (wmtab->Active == EVT_TABLET_ERASER); - if (wmtab->Active != EVT_TABLET_NONE) { - pressure = wmtab->Pressure; - if (tilt) { - tilt[0] = wmtab->Xtilt; - tilt[1] = wmtab->Ytilt; - } - } - } - - if (pen_flip) { - (*pen_flip) = erasor; - } - - return pressure; -} - -bool WM_event_is_tablet(const struct wmEvent *event) -{ - return (event->tablet_data) ? true : false; -} - -#ifdef WITH_INPUT_IME -/* most os using ctrl/oskey + space to switch ime, avoid added space */ -bool WM_event_is_ime_switch(const struct wmEvent *event) -{ - return event->val == KM_PRESS && event->type == SPACEKEY && - (event->ctrl || event->oskey || event->shift || event->alt); -} -#endif - -/** \} */ - wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler) { wmKeyMap *keymap; @@ -5141,10 +4722,10 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm return NULL; } -static wmKeyMapItem *wm_kmi_from_event(bContext *C, - wmWindowManager *wm, - ListBase *handlers, - const wmEvent *event) +wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C, + wmWindowManager *wm, + ListBase *handlers, + const wmEvent *event) { LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) { /* during this loop, ui handlers for nested menus can tag multiple handlers free */ @@ -5167,6 +4748,8 @@ static wmKeyMapItem *wm_kmi_from_event(bContext *C, return NULL; } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Cursor Keymap Status * @@ -5379,7 +4962,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) wm_eventemulation(&test_event, true); wmKeyMapItem *kmi = NULL; for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { - kmi = wm_kmi_from_event(C, wm, handlers[handler_index], &test_event); + kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event); if (kmi) { break; } @@ -5475,43 +5058,3 @@ bool WM_window_modal_keymap_status_draw(bContext *UNUSED(C), wmWindow *win, uiLa } /** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Event Click/Drag Checks - * - * Values under this limit are detected as clicks. - * - * \{ */ - -int WM_event_drag_threshold(const struct wmEvent *event) -{ - int drag_threshold; - if (WM_event_is_tablet(event)) { - drag_threshold = U.drag_threshold_tablet; - } - else if (ISMOUSE(event->prevtype)) { - drag_threshold = U.drag_threshold_mouse; - } - else { - /* Typically keyboard, could be NDOF button or other less common types. */ - drag_threshold = U.drag_threshold; - } - return drag_threshold * U.dpi_fac; -} - -bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2]) -{ - const int drag_threshold = WM_event_drag_threshold(event); - return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold; -} - -bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2]) -{ - const int drag_delta[2] = { - prev_xy[0] - event->x, - prev_xy[1] - event->y, - }; - return WM_event_drag_test_with_delta(event, drag_delta); -} - -/** \} */ diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 1809a233ce1..f5e507fc317 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1109,12 +1109,13 @@ const char *WM_key_event_string(const short type, const bool compact) case LEFTCTRLKEY: case RIGHTCTRLKEY: if (platform == MACOS) { - return "^"; + return key_event_glyph_or_text(font_id, "^", "\xe2\x8c\x83"); } return IFACE_("Ctrl"); case LEFTALTKEY: case RIGHTALTKEY: { if (platform == MACOS) { + /* Option symbol on Mac keyboard. */ single_glyph = "\xe2\x8c\xa5"; } return key_event_glyph_or_text(font_id, IFACE_("Alt"), single_glyph); @@ -1124,28 +1125,23 @@ const char *WM_key_event_string(const short type, const bool compact) return key_event_glyph_or_text(font_id, IFACE_("Cmd"), "\xe2\x8c\x98"); } else if (platform == MSWIN) { - return key_event_glyph_or_text(font_id, IFACE_("Win"), "\xe2\x8a\x9e"); + return key_event_glyph_or_text(font_id, IFACE_("Win"), "\xe2\x9d\x96"); } - return IFACE_("OSkey"); + return IFACE_("OS"); } break; - case TABKEY: { - if (platform == MACOS) { - single_glyph = "\xe2\x86\xb9"; - } - return key_event_glyph_or_text(font_id, IFACE_("Tab"), single_glyph); - } + case TABKEY: + return key_event_glyph_or_text(font_id, IFACE_("Tab"), "\xe2\xad\xbe"); case BACKSPACEKEY: return key_event_glyph_or_text(font_id, IFACE_("Bksp"), "\xe2\x8c\xab"); case ESCKEY: - return key_event_glyph_or_text(font_id, IFACE_("Esc"), NULL /* "\xe2\x8e\x8b" */); - case RETKEY: { if (platform == MACOS) { - single_glyph = "\xe2\x8f\x8e"; + single_glyph = "\xe2\x8e\x8b"; } - return key_event_glyph_or_text(font_id, IFACE_("Enter"), single_glyph); - } + return key_event_glyph_or_text(font_id, IFACE_("Esc"), single_glyph); + case RETKEY: + return key_event_glyph_or_text(font_id, IFACE_("Enter"), "\xe2\x86\xb5"); case SPACEKEY: - return key_event_glyph_or_text(font_id, IFACE_("Space"), NULL /* "\xe2\x90\xa3" */); + return key_event_glyph_or_text(font_id, IFACE_("Space"), "\xe2\x90\xa3"); case LEFTARROWKEY: return key_event_glyph_or_text(font_id, IFACE_("Left"), "\xe2\x86\x90"); case UPARROWKEY: diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 678b7d9dcee..5837e8e952c 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -720,6 +720,111 @@ void WM_operator_properties_free(PointerRNA *ptr) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Operator Last Properties API + * \{ */ + +#if 1 /* may want to disable operator remembering previous state for testing */ + +static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties) +{ + bool changed = false; + IDPropertyTemplate val = {0}; + IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); + PropertyRNA *iterprop; + + CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname); + + iterprop = RNA_struct_iterator_property(op->type->srna); + + RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) { + PropertyRNA *prop = itemptr.data; + if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) { + if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */ + const char *identifier = RNA_property_identifier(prop); + IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier); + if (idp_src) { + IDProperty *idp_dst = IDP_CopyProperty(idp_src); + + /* note - in the future this may need to be done recursively, + * but for now RNA doesn't access nested operators */ + idp_dst->flag |= IDP_FLAG_GHOST; + + /* add to temporary group instead of immediate replace, + * because we are iterating over this group */ + IDP_AddToGroup(replaceprops, idp_dst); + changed = true; + } + } + } + } + RNA_PROP_END; + + IDP_MergeGroup(op->properties, replaceprops, true); + IDP_FreeProperty(replaceprops); + return changed; +} + +bool WM_operator_last_properties_init(wmOperator *op) +{ + bool changed = false; + if (op->type->last_properties) { + changed |= operator_last_properties_init_impl(op, op->type->last_properties); + for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { + IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname); + if (idp_src) { + changed |= operator_last_properties_init_impl(opm, idp_src); + } + } + } + return changed; +} + +bool WM_operator_last_properties_store(wmOperator *op) +{ + if (op->type->last_properties) { + IDP_FreeProperty(op->type->last_properties); + op->type->last_properties = NULL; + } + + if (op->properties) { + CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname); + op->type->last_properties = IDP_CopyProperty(op->properties); + } + + if (op->macro.first != NULL) { + for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { + if (opm->properties) { + if (op->type->last_properties == NULL) { + op->type->last_properties = IDP_New( + IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties"); + } + IDProperty *idp_macro = IDP_CopyProperty(opm->properties); + STRNCPY(idp_macro->name, opm->type->idname); + IDP_ReplaceInGroup(op->type->last_properties, idp_macro); + } + } + } + + return (op->type->last_properties != NULL); +} + +#else + +bool WM_operator_last_properties_init(wmOperator *UNUSED(op)) +{ + return false; +} + +bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) +{ + return false; +} + +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Default Operator Callbacks * \{ */ diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 3218f8c45e4..8e49e47c492 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -487,6 +487,8 @@ static bool toolsystem_key_ensure_check(const bToolKey *tkey) break; case SPACE_NODE: return true; + case SPACE_SEQ: + return true; } return false; } @@ -516,6 +518,11 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp mode = 0; break; } + case SPACE_SEQ: { + SpaceSeq *sseq = sa->spacedata.first; + mode = sseq->view; + break; + } } return mode; } @@ -736,6 +743,17 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) case SPACE_NODE: { return "builtin.select_box"; } + case SPACE_SEQ: { + switch (tkey->mode) { + case SEQ_VIEW_SEQUENCE: + return "builtin.select"; + case SEQ_VIEW_PREVIEW: + return "builtin.annotate"; + case SEQ_VIEW_SEQUENCE_PREVIEW: + return "builtin.select"; + } + return "builtin.select_box"; + } } return "builtin.select_box"; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 583a11f1244..4f70eeefb76 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -548,6 +548,12 @@ void WM_window_set_dpi(const wmWindow *win) BLF_default_dpi(U.pixelsize * U.dpi); } +static void wm_window_update_eventstate(wmWindow *win) +{ + /* Update mouse position when a window is activated. */ + wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y); +} + static void wm_window_ensure_eventstate(wmWindow *win) { if (win->eventstate) { @@ -555,7 +561,7 @@ static void wm_window_ensure_eventstate(wmWindow *win) } win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); - wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y); + wm_window_update_eventstate(win); } /* belongs to below */ @@ -703,6 +709,8 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo /* happens after fileread */ wm_window_ensure_eventstate(win); + + WM_window_set_dpi(win); } /* add keymap handlers (1 handler for all keys in map!) */ @@ -1207,7 +1215,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr case GHOST_kEventWindowActivate: { GHOST_TEventKeyData kdata; wmEvent event; - int wx, wy; const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) | (query_qual(CONTROL) ? KM_CTRL : 0) | (query_qual(ALT) ? KM_ALT : 0) | (query_qual(OS) ? KM_OSKEY : 0)); @@ -1292,10 +1299,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr win->eventstate->keymodifier = 0; /* entering window, update mouse pos. but no event */ - wm_get_cursor_position(win, &wx, &wy); - - win->eventstate->x = wx; - win->eventstate->y = wy; + wm_window_update_eventstate(win); win->addmousemove = 1; /* enables highlighted buttons */ @@ -1456,12 +1460,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr case GHOST_kEventDraggingDropDone: { wmEvent event; GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt); - int wx, wy; /* entering window, update mouse pos */ - wm_get_cursor_position(win, &wx, &wy); - win->eventstate->x = wx; - win->eventstate->y = wy; + wm_window_update_eventstate(win); wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */ @@ -1543,9 +1544,21 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr wm_event_add_ghostevent(wm, win, type, data); break; } - default: + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + if (win->active == 0) { + /* Entering window, update cursor and tablet state. + * (ghost sends win-activate *after* the mouse-click in window!) */ + wm_window_update_eventstate(win); + } + + wm_event_add_ghostevent(wm, win, type, data); + break; + } + default: { wm_event_add_ghostevent(wm, win, type, data); break; + } } } return 1; @@ -2099,21 +2112,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y) } } -/** - * Get the cursor pressure, in most cases you'll want to use wmTabletData from the event - */ -float WM_cursor_pressure(const struct wmWindow *win) -{ - const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin); - /* if there's tablet data from an active tablet device then add it */ - if ((td != NULL) && td->Active != GHOST_kTabletModeNone) { - return wm_pressure_curve(td->Pressure); - } - else { - return -1.0f; - } -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -2190,8 +2188,8 @@ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect) } } - BLI_assert(screen_rect.xmin < screen_rect.xmax); - BLI_assert(screen_rect.ymin < screen_rect.ymax); + BLI_assert(BLI_rcti_is_valid(&screen_rect)); + *r_rect = screen_rect; } diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index c53ccda170a..97c5980e3e7 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -31,6 +31,7 @@ #define WM_HANDLER_MODAL 4 /* MODAL|BREAK means unhandled */ struct ARegion; +struct GHOST_TabletData; struct ScrArea; /* wmKeyMap is in DNA_windowmanager.h, it's saveable */ @@ -148,7 +149,9 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file); void wm_event_do_refresh_wm_and_depsgraph(bContext *C); void wm_event_do_notifiers(bContext *C); +/* wm_event_query.c */ float wm_pressure_curve(float raw_pressure); +void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab); /* wm_keymap.c */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 252eb9673ae..ebb0d7dd878 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -63,6 +63,8 @@ enum { MOUSEPAN = 0x000e, MOUSEZOOM = 0x000f, MOUSEROTATE = 0x0010, + MOUSESMARTZOOM = 0x0017, + /* defaults from ghost */ WHEELUPMOUSE = 0x000a, WHEELDOWNMOUSE = 0x000b, @@ -359,7 +361,8 @@ enum { (((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) || (event_type) == OSKEY) /* test whether the event is a mouse button */ -#define ISMOUSE(event_type) ((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) +#define ISMOUSE(event_type) \ + (((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) || (event_type) == MOUSESMARTZOOM) #define ISMOUSE_WHEEL(event_type) ((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE) #define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSEROTATE) |