Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2020-02-01 05:25:32 +0300
committerYimingWu <xp8110@outlook.com>2020-02-01 05:25:32 +0300
commitb47883a990ee68e659a8a8b44729be9b8e0d002f (patch)
tree24a7733807992fc84445d30b63deaedfe1ab40a1 /source/blender/editors
parentb5abbc40a07041af91dca5d0a4acd8e5f1518c91 (diff)
parentd9ec25844b4ac3143775615469fe69b27105c108 (diff)
Merge remote-tracking branch 'origin/master' into temp-lanpr-review
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c134
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/curve/editcurve.c11
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c32
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c18
-rw-r--r--source/blender/editors/include/ED_mball.h1
-rw-r--r--source/blender/editors/include/ED_object.h10
-rw-r--r--source/blender/editors/include/ED_transform.h29
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/interface/interface_templates.c10
-rw-r--r--source/blender/editors/io/CMakeLists.txt10
-rw-r--r--source/blender/editors/io/io_ops.c7
-rw-r--r--source/blender/editors/io/io_usd.c240
-rw-r--r--source/blender/editors/io/io_usd.h31
-rw-r--r--source/blender/editors/object/object_data_transform.c99
-rw-r--r--source/blender/editors/object/object_intern.h8
-rw-r--r--source/blender/editors/object/object_transform.c38
-rw-r--r--source/blender/editors/physics/CMakeLists.txt14
-rw-r--r--source/blender/editors/physics/particle_edit.c1
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c5
-rw-r--r--source/blender/editors/physics/particle_object.c2
-rw-r--r--source/blender/editors/physics/physics_fluid.c1647
-rw-r--r--source/blender/editors/physics/physics_intern.h14
-rw-r--r--source/blender/editors/physics/physics_ops.c14
-rw-r--r--source/blender/editors/render/render_opengl.c115
-rw-r--r--source/blender/editors/screen/area.c2
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c29
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c35
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c8
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c17
-rw-r--r--source/blender/editors/space_file/filelist.c6
-rw-r--r--source/blender/editors/space_file/filesel.c3
-rw-r--r--source/blender/editors/space_graph/graph_edit.c4
-rw-r--r--source/blender/editors/space_image/image_draw.c9
-rw-r--r--source/blender/editors/space_image/image_ops.c304
-rw-r--r--source/blender/editors/space_image/space_image.c68
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c21
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c28
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c30
-rw-r--r--source/blender/editors/transform/CMakeLists.txt2
-rw-r--r--source/blender/editors/transform/transform.c328
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_convert_object.c84
-rw-r--r--source/blender/editors/transform/transform_draw.c114
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c344
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.h31
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c370
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c11
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c3
-rw-r--r--source/blender/editors/transform/transform_snap.h2
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
58 files changed, 2588 insertions, 1803 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index a3d8695d186..2ec1634fa38 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -5057,72 +5057,76 @@ void ANIM_channel_draw_widgets(const bContext *C,
}
/* Special for Grease Pencil Layer. */
else if (ale->type == ANIMTYPE_GPLAYER) {
- /* Add some offset to make it more pleasing to the eye. */
- offset += SLIDER_WIDTH / 2.1f;
-
- char *gp_rna_path = NULL;
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- const short width = SLIDER_WIDTH / 5;
-
- /* Create the RNA pointers. */
- RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
- RNA_id_pointer_create(ale->id, &id_ptr);
- int icon;
-
- /* Layer opacity. */
- UI_block_emboss_set(block, UI_EMBOSS);
- prop = RNA_struct_find_property(&ptr, "opacity");
- gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
- if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
- uiDefAutoButR(block,
- &ptr,
- prop,
- array_index,
- "",
- ICON_NONE,
- offset,
- ymid,
- width * 3,
- channel_height);
- }
- MEM_freeN(gp_rna_path);
-
- /* Mask Layer. */
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- prop = RNA_struct_find_property(&ptr, "mask_layer");
- gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
- if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
- icon = (gpl->flag & GP_LAYER_USE_MASK) ? ICON_MOD_MASK : ICON_LAYER_ACTIVE;
- uiDefAutoButR(block,
- &ptr,
- prop,
- array_index,
- "",
- icon,
- offset + (width * 3),
- ymid,
- width,
- channel_height);
- }
- MEM_freeN(gp_rna_path);
-
- /* Layer onion skinning switch. */
- prop = RNA_struct_find_property(&ptr, "use_onion_skinning");
- gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
- if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
- icon = (gpl->onion_flag & GP_LAYER_ONIONSKIN) ? ICON_ONIONSKIN_ON : ICON_ONIONSKIN_OFF;
- uiDefAutoButR(block,
- &ptr,
- prop,
- array_index,
- "",
- icon,
- offset + (width * 4),
- ymid,
- width,
- channel_height);
+ bGPdata *gpd = (bGPdata *)ale->id;
+ if ((gpd != NULL) && ((gpd->flag & GP_DATA_ANNOTATIONS) == 0)) {
+ /* Add some offset to make it more pleasing to the eye. */
+ offset += SLIDER_WIDTH / 2.1f;
+
+ char *gp_rna_path = NULL;
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ const short width = SLIDER_WIDTH / 5;
+
+ /* Create the RNA pointers. */
+ RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
+ RNA_id_pointer_create(ale->id, &id_ptr);
+ int icon;
+
+ /* Layer opacity. */
+ UI_block_emboss_set(block, UI_EMBOSS);
+ prop = RNA_struct_find_property(&ptr, "opacity");
+ gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ array_index,
+ "",
+ ICON_NONE,
+ offset,
+ ymid,
+ width * 3,
+ channel_height);
+ }
+ MEM_freeN(gp_rna_path);
+
+ /* Mask Layer. */
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ prop = RNA_struct_find_property(&ptr, "mask_layer");
+ gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
+ icon = (gpl->flag & GP_LAYER_USE_MASK) ? ICON_MOD_MASK : ICON_LAYER_ACTIVE;
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ array_index,
+ "",
+ icon,
+ offset + (width * 3),
+ ymid,
+ width,
+ channel_height);
+ }
+ MEM_freeN(gp_rna_path);
+
+ /* Layer onion skinning switch. */
+ prop = RNA_struct_find_property(&ptr, "use_onion_skinning");
+ gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
+ icon = (gpl->onion_flag & GP_LAYER_ONIONSKIN) ? ICON_ONIONSKIN_ON :
+ ICON_ONIONSKIN_OFF;
+ uiDefAutoButR(block,
+ &ptr,
+ prop,
+ array_index,
+ "",
+ icon,
+ offset + (width * 4),
+ ymid,
+ width,
+ channel_height);
+ }
+ MEM_freeN(gp_rna_path);
}
- MEM_freeN(gp_rna_path);
}
/* Only if RNA-Path found. */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 55c9b661074..d366978ba2b 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -463,7 +463,7 @@ static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
- /* loop over all selected pchans
+ /* Loop over all selected pchan's.
*
* TODO, loop over children before parents if multiple bones
* at once are to be predictable*/
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index af2d92533c3..e7803fdaafb 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -908,7 +908,7 @@ static bool curve_is_animated(Curve *cu)
static void fcurve_path_rename(AnimData *adt,
const char *orig_rna_path,
- char *rna_path,
+ const char *rna_path,
ListBase *orig_curves,
ListBase *curves)
{
@@ -922,11 +922,15 @@ static void fcurve_path_rename(AnimData *adt,
nfcu = copy_fcurve(fcu);
spath = nfcu->rna_path;
nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
+
+ /* copy_fcurve() sets nfcu->grp to NULL. To maintain the groups, we need to keep the pointer.
+ * As a result, the group's 'channels' pointers will be wrong, which is fixed by calling
+ * `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
+ nfcu->grp = fcu->grp;
BLI_addtail(curves, nfcu);
if (fcu->grp) {
action_groups_remove_channel(adt->action, fcu);
- action_groups_add_channel(adt->action, fcu->grp, nfcu);
}
else if ((adt->action) && (&adt->action->curves == orig_curves)) {
BLI_remlink(&adt->action->curves, fcu);
@@ -1077,6 +1081,9 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
}
*orig_curves = curves;
+ if (adt != NULL) {
+ BKE_action_groups_reconstruct(adt->action);
+ }
}
/* return 0 if animation data wasn't changed, 1 otherwise */
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index fd8fe103a2d..4cc0c865093 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -385,9 +385,8 @@ set(ICON_NAMES
mod_mask
mod_cloth
mod_explode
- mod_fluidsim
mod_multires
- mod_smoke
+ mod_fluid
mod_solidify
mod_screw
mod_vertex_weight
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
index 24571f67fdb..1c8c46a2bad 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
@@ -52,6 +52,7 @@
static void arrow2d_draw_geom(wmGizmo *gz, const float matrix[4][4], const float color[4])
{
+ const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
const float size = 0.11f;
const float size_breadth = size / 2.0f;
const float size_length = size * 1.7f;
@@ -74,11 +75,21 @@ static void arrow2d_draw_geom(wmGizmo *gz, const float matrix[4][4], const float
immVertex2f(pos, 0.0f, arrow_length);
immEnd();
- immBegin(GPU_PRIM_TRIS, 3);
- immVertex2f(pos, size_breadth, arrow_length);
- immVertex2f(pos, -size_breadth, arrow_length);
- immVertex2f(pos, 0.0f, arrow_length + size_length);
- immEnd();
+ if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) {
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immVertex2f(pos, -size / 2, arrow_length);
+ immVertex2f(pos, size / 2, arrow_length);
+ immVertex2f(pos, size / 2, arrow_length + size);
+ immVertex2f(pos, -size / 2, arrow_length + size);
+ immEnd();
+ }
+ else {
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2f(pos, size_breadth, arrow_length);
+ immVertex2f(pos, -size_breadth, arrow_length);
+ immVertex2f(pos, 0.0f, arrow_length + size_length);
+ immEnd();
+ }
immUnbindProgram();
@@ -197,6 +208,11 @@ static void GIZMO_GT_arrow_2d(wmGizmoType *gzt)
gzt->struct_size = sizeof(wmGizmo);
/* rna */
+ static EnumPropertyItem rna_enum_draw_style_items[] = {
+ {ED_GIZMO_ARROW_STYLE_NORMAL, "NORMAL", 0, "Normal", ""},
+ {ED_GIZMO_ARROW_STYLE_BOX, "BOX", 0, "Box", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
RNA_def_float_rotation(gzt->srna,
"angle",
@@ -208,6 +224,12 @@ static void GIZMO_GT_arrow_2d(wmGizmoType *gzt)
"",
DEG2RADF(-360.0f),
DEG2RADF(360.0f));
+ RNA_def_enum(gzt->srna,
+ "draw_style",
+ rna_enum_draw_style_items,
+ ED_GIZMO_ARROW_STYLE_NORMAL,
+ "Draw Style",
+ "");
}
void ED_gizmotypes_arrow_2d(void)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index 7e6db43dbb3..ef3014eabc2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -286,7 +286,7 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2
else {
copy_v2_v2(point_local, (float[2]){UNPACK2(mval)});
sub_v2_v2(point_local, gz->matrix_basis[3]);
- mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC));
+ mul_v2_fl(point_local, 1.0f / gz->scale_final);
}
/* The 'gz->scale_final' is already applied when projecting. */
if (len_squared_v2(point_local) < 1.0f) {
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 67ffc6adc9f..1331cc92d96 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1797,6 +1797,11 @@ static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *op)
}
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
+ continue;
+ }
+
for (int i = 0; i < gps->totpoints; i++) {
dvert = &gps->dvert[i];
MDeformWeight *dw = defvert_find_index(dvert, def_nr);
@@ -1864,7 +1869,8 @@ static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
MDeformVert *dverta, *dvertb;
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
- if (gps->dvert == NULL) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
continue;
}
@@ -1959,6 +1965,11 @@ static int gpencil_vertex_group_normalize_exec(bContext *C, wmOperator *op)
}
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
+ continue;
+ }
+
/* look for max value */
float maxvalue = 0.0f;
for (int i = 0; i < gps->totpoints; i++) {
@@ -2027,10 +2038,11 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
}
CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
- /* verify the strokes has something to change */
- if (gps->totpoints == 0) {
+ /* Verify the strokes has something to change. */
+ if ((gps->totpoints == 0) || (gps->dvert == NULL)) {
continue;
}
+
/* look for tot value */
float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__);
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 5afb645d9e7..8ffae0f2b66 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -25,7 +25,6 @@
#define __ED_MBALL_H__
struct Base;
-struct MetaBall;
struct Object;
struct UndoType;
struct bContext;
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index a5f56689c95..d27eeb270ac 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -421,6 +421,16 @@ void ED_object_data_xform_by_mat4(struct XFormObjectData *xod, const float mat[4
void ED_object_data_xform_restore(struct XFormObjectData *xod);
void ED_object_data_xform_tag_update(struct XFormObjectData *xod);
+/* Container helper API. */
+struct XFormObjectData_Container;
+struct XFormObjectData_Container *ED_object_data_xform_container_create(void);
+void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds);
+void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
+ struct Main *bmain,
+ struct Depsgraph *depsgraph);
+void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container *xds,
+ struct Object *ob);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 0771f39f905..29bac9df93a 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -27,8 +27,6 @@
/* ******************* Registration Function ********************** */
struct Object;
-struct SnapObjectContext;
-struct SnapObjectParams;
struct bContext;
struct wmKeyConfig;
struct wmOperatorType;
@@ -107,7 +105,6 @@ bool calculateTransformCenter(struct bContext *C,
struct Object;
struct Scene;
-struct TransInfo;
struct wmGizmoGroup;
struct wmGizmoGroupType;
@@ -168,10 +165,28 @@ void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
/* *** transform_gizmo_extrude_3d.c *** */
void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt);
-bool ED_widgetgroup_gizmo2d_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
-void ED_widgetgroup_gizmo2d_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_draw_prepare(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+/* Transform: Axis/Cage */
+bool ED_widgetgroup_gizmo2d_xform_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_xform_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_xform_setup_no_cage(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_xform_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_xform_draw_prepare(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
+
+/* Resize: Axis */
+bool ED_widgetgroup_gizmo2d_resize_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_resize_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_resize_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_resize_draw_prepare(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
+
+/* Rotate: Axis */
+bool ED_widgetgroup_gizmo2d_rotate_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_rotate_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_rotate_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup);
#define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 2bf50d3b4b8..44c734e264a 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -560,7 +560,7 @@ DEF_ICON_MODIFIER(MOD_CLOTH)
DEF_ICON_MODIFIER(MOD_EXPLODE)
DEF_ICON_MODIFIER(MOD_FLUIDSIM)
DEF_ICON_MODIFIER(MOD_MULTIRES)
-DEF_ICON_MODIFIER(MOD_SMOKE)
+DEF_ICON_MODIFIER(MOD_FLUID)
DEF_ICON_MODIFIER(MOD_SOLIDIFY)
DEF_ICON_MODIFIER(MOD_SCREW)
DEF_ICON_MODIFIER(MOD_VERTEX_WEIGHT)
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 17247736d3b..71fa28640e0 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1819,11 +1819,13 @@ static int modifier_can_delete(ModifierData *md)
{
/* fluid particle modifier can't be deleted here */
if (md->type == eModifierType_ParticleSystem) {
- if (((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID) {
+ short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type;
+ if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP ||
+ particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY ||
+ particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER) {
return 0;
}
}
-
return 1;
}
@@ -1836,7 +1838,7 @@ static int modifier_is_simulation(ModifierData *md)
eModifierType_Cloth,
eModifierType_Collision,
eModifierType_Fluidsim,
- eModifierType_Smoke,
+ eModifierType_Fluid,
eModifierType_Softbody,
eModifierType_Surface,
eModifierType_DynamicPaint)) {
@@ -2069,7 +2071,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
eModifierType_Softbody,
eModifierType_ParticleSystem,
eModifierType_Cloth,
- eModifierType_Smoke)) {
+ eModifierType_Fluid)) {
uiItemO(row,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"),
ICON_NONE,
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 5a35b251d0c..5afe348158f 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../depsgraph
../../makesdna
../../makesrna
+ ../../usd
../../windowmanager
../../../../intern/guardedalloc
)
@@ -39,11 +40,13 @@ set(SRC
io_cache.c
io_collada.c
io_ops.c
+ io_usd.c
io_alembic.h
io_cache.h
io_collada.h
io_ops.h
+ io_usd.h
)
set(LIB
@@ -69,6 +72,13 @@ if(WITH_ALEMBIC)
endif()
endif()
+if(WITH_USD)
+ list(APPEND LIB
+ bf_usd
+ )
+ add_definitions(-DWITH_USD)
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index e04fe4a20c0..acb511a414d 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -33,6 +33,10 @@
# include "io_alembic.h"
#endif
+#ifdef WITH_USD
+# include "io_usd.h"
+#endif
+
#include "io_cache.h"
void ED_operatortypes_io(void)
@@ -46,6 +50,9 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_alembic_import);
WM_operatortype_append(WM_OT_alembic_export);
#endif
+#ifdef WITH_USD
+ WM_operatortype_append(WM_OT_usd_export);
+#endif
WM_operatortype_append(CACHEFILE_OT_open);
WM_operatortype_append(CACHEFILE_OT_reload);
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
new file mode 100644
index 00000000000..2818b134509
--- /dev/null
+++ b/source/blender/editors/io/io_usd.c
@@ -0,0 +1,240 @@
+/*
+ * 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 editor/io
+ */
+
+#ifdef WITH_USD
+# include "DNA_space_types.h"
+
+# include "BKE_context.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
+
+# include "BLI_path_util.h"
+# include "BLI_string.h"
+# include "BLI_utildefines.h"
+
+# include "MEM_guardedalloc.h"
+
+# include "RNA_access.h"
+# include "RNA_define.h"
+
+# include "UI_interface.h"
+# include "UI_resources.h"
+
+# include "WM_api.h"
+# include "WM_types.h"
+
+# include "DEG_depsgraph.h"
+
+# include "io_usd.h"
+# include "usd.h"
+
+const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
+ {DAG_EVAL_RENDER,
+ "RENDER",
+ 0,
+ "Render",
+ "Use Render settings for object visibility, modifier settings, etc"},
+ {DAG_EVAL_VIEWPORT,
+ "VIEWPORT",
+ 0,
+ "Viewport",
+ "Use Viewport settings for object visibility, modifier settings, etc"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
+ * This is set when the operator is invoked, and not set when it is only executed. */
+enum { AS_BACKGROUND_JOB = 1 };
+typedef struct eUSDOperatorOptions {
+ bool as_background_job;
+} eUSDOperatorOptions;
+
+static int wm_usd_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ eUSDOperatorOptions *options = MEM_callocN(sizeof(eUSDOperatorOptions), "eUSDOperatorOptions");
+ options->as_background_job = true;
+ op->customdata = options;
+
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+ const char *main_blendfile_path = BKE_main_blendfile_path(bmain);
+
+ if (main_blendfile_path[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, main_blendfile_path, sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".usdc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_usd_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ eUSDOperatorOptions *options = (eUSDOperatorOptions *)op->customdata;
+ const bool as_background_job = (options != NULL && options->as_background_job);
+ MEM_SAFE_FREE(op->customdata);
+
+ const bool selected_objects_only = RNA_boolean_get(op->ptr, "selected_objects_only");
+ const bool visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only");
+ const bool export_animation = RNA_boolean_get(op->ptr, "export_animation");
+ const bool export_hair = RNA_boolean_get(op->ptr, "export_hair");
+ const bool export_uvmaps = RNA_boolean_get(op->ptr, "export_uvmaps");
+ const bool export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ const bool export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ const bool use_instancing = RNA_boolean_get(op->ptr, "use_instancing");
+ const bool evaluation_mode = RNA_enum_get(op->ptr, "evaluation_mode");
+
+ struct USDExportParams params = {
+ export_animation,
+ export_hair,
+ export_uvmaps,
+ export_normals,
+ export_materials,
+ selected_objects_only,
+ visible_objects_only,
+ use_instancing,
+ evaluation_mode,
+ };
+
+ bool ok = USD_export(C, filename, &params, as_background_job);
+
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayout *col;
+ struct PointerRNA *ptr = op->ptr;
+
+ uiLayoutSetPropSep(layout, true);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "selected_objects_only", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "visible_objects_only", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "export_animation", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_hair", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_uvmaps", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_normals", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "export_materials", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_instancing", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "evaluation_mode", 0, NULL, ICON_NONE);
+}
+
+void WM_OT_usd_export(struct wmOperatorType *ot)
+{
+ ot->name = "Export USD";
+ ot->description = "Export current scene in a USD archive";
+ ot->idname = "WM_OT_usd_export";
+
+ ot->invoke = wm_usd_export_invoke;
+ ot->exec = wm_usd_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_usd_export_draw;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_USD,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna,
+ "selected_objects_only",
+ false,
+ "Only Export Selected Objects",
+ "Only selected objects are exported. Unselected parents of selected objects are "
+ "exported as empty transform");
+
+ RNA_def_boolean(ot->srna,
+ "visible_objects_only",
+ true,
+ "Only Export Visible Objects",
+ "Only visible objects are exported. Invisible parents of visible objects are "
+ "exported as empty transform");
+
+ RNA_def_boolean(ot->srna,
+ "export_animation",
+ false,
+ "Export Animation",
+ "When checked, the render frame range is exported. When false, only the current "
+ "frame is exported");
+ RNA_def_boolean(ot->srna,
+ "export_hair",
+ false,
+ "Export Hair",
+ "When checked, hair is exported as USD curves");
+ RNA_def_boolean(ot->srna,
+ "export_uvmaps",
+ true,
+ "Export UV Maps",
+ "When checked, all UV maps of exported meshes are included in the export");
+ RNA_def_boolean(ot->srna,
+ "export_normals",
+ true,
+ "Export Normals",
+ "When checked, normals of exported meshes are included in the export");
+ RNA_def_boolean(ot->srna,
+ "export_materials",
+ true,
+ "Export Materials",
+ "When checked, the viewport settings of materials are exported as USD preview "
+ "materials, and material assignments are exported as geometry subsets");
+
+ RNA_def_boolean(ot->srna,
+ "use_instancing",
+ false,
+ "Use Instancing (EXPERIMENTAL)",
+ "When true, dupli-objects are written as instances of the original in USD. "
+ "Experimental feature, not working perfectly");
+
+ RNA_def_enum(ot->srna,
+ "evaluation_mode",
+ rna_enum_usd_export_evaluation_mode_items,
+ DAG_EVAL_RENDER,
+ "Evaluation Mode",
+ "Determines visibility of objects and modifier settings");
+}
+
+#endif /* WITH_USD */
diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h
new file mode 100644
index 00000000000..4738e1c348d
--- /dev/null
+++ b/source/blender/editors/io/io_usd.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef __IO_USD_H__
+#define __IO_USD_H__
+
+/** \file
+ * \ingroup editor/io
+ */
+
+struct wmOperatorType;
+
+void WM_OT_usd_export(struct wmOperatorType *ot);
+
+#endif /* __IO_USD_H__ */
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
index 51d8fb8fd72..29b0cb88935 100644
--- a/source/blender/editors/object/object_data_transform.c
+++ b/source/blender/editors/object/object_data_transform.c
@@ -49,10 +49,12 @@
#include "BKE_mesh.h"
#include "BKE_armature.h"
#include "BKE_lattice.h"
+#include "BKE_scene.h"
#include "bmesh.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "WM_types.h"
@@ -575,3 +577,100 @@ void ED_object_data_xform_tag_update(struct XFormObjectData *xod_base)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Data Transform Container
+ *
+ * Use to implement 'Affect Only Origins' feature.
+ *
+ * \{ */
+
+struct XFormObjectData_Container {
+ GHash *obdata_in_obmode_map;
+};
+
+struct XFormObjectData_Extra {
+ Object *ob;
+ float obmat_orig[4][4];
+ struct XFormObjectData *xod;
+};
+
+void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container *xds, Object *ob)
+{
+ if (xds->obdata_in_obmode_map == NULL) {
+ xds->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ void **xf_p;
+ if (!BLI_ghash_ensure_p(xds->obdata_in_obmode_map, ob->data, &xf_p)) {
+ struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
+ copy_m4_m4(xf->obmat_orig, ob->obmat);
+ xf->ob = ob;
+ /* Result may be NULL, that's OK. */
+ xf->xod = ED_object_data_xform_create(ob->data);
+ *xf_p = xf;
+ }
+}
+
+/**
+ * This may be called multiple times with the same data.
+ * Each time, the original transformations are re-applied, instead of accumulating the changes.
+ */
+void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
+ struct Main *bmain,
+ Depsgraph *depsgraph)
+{
+ if (xds->obdata_in_obmode_map == NULL) {
+ return;
+ }
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, xds->obdata_in_obmode_map) {
+ ID *id = BLI_ghashIterator_getKey(&gh_iter);
+ struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
+ if (xf->xod == NULL) {
+ continue;
+ }
+
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, xf->ob);
+ float imat[4][4], dmat[4][4];
+ invert_m4_m4(imat, xf->obmat_orig);
+ mul_m4_m4m4(dmat, imat, ob_eval->obmat);
+ invert_m4(dmat);
+
+ ED_object_data_xform_by_mat4(xf->xod, dmat);
+ if (xf->ob->type == OB_ARMATURE) {
+ /* TODO: none of the current flags properly update armatures, needs investigation. */
+ DEG_id_tag_update(id, 0);
+ }
+ else {
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ }
+ }
+}
+
+/** Callback for #GHash free. */
+static void trans_obdata_in_obmode_free_elem(void *xf_p)
+{
+ struct XFormObjectData_Extra *xf = xf_p;
+ if (xf->xod) {
+ ED_object_data_xform_destroy(xf->xod);
+ }
+ MEM_freeN(xf);
+}
+
+struct XFormObjectData_Container *ED_object_data_xform_container_create(void)
+{
+ struct XFormObjectData_Container *xds = MEM_callocN(sizeof(*xds), __func__);
+ xds->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+ return xds;
+}
+
+void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds)
+{
+ BLI_ghash_free(xds->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
+ MEM_freeN(xds);
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 41205bc8778..352ba744d92 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -129,7 +129,7 @@ void OBJECT_OT_hook_assign(struct wmOperatorType *ot);
void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
-/* object_group.c */
+/* object_collection.c */
void COLLECTION_OT_create(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
@@ -172,7 +172,7 @@ void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
-/* grease pencil modifiers */
+/* object_gpencil_modifiers.c */
void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot);
@@ -180,7 +180,7 @@ void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
-/* shader fx */
+/* object_shader_fx.c */
void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot);
void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot);
@@ -265,7 +265,7 @@ void OBJECT_OT_shape_key_retime(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
-/* object_group.c */
+/* object_collection.c */
void OBJECT_OT_collection_add(struct wmOperatorType *ot);
void OBJECT_OT_collection_link(struct wmOperatorType *ot);
void OBJECT_OT_collection_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 826d1db2538..45b9c6306ac 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -72,6 +72,7 @@
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_gpencil.h"
+#include "ED_object.h"
#include "MEM_guardedalloc.h"
@@ -292,6 +293,8 @@ static int object_clear_transform_generic_exec(bContext *C,
void (*clear_func)(Object *, const bool),
const char default_ksName[])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
KeyingSet *ks;
const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta");
@@ -304,6 +307,16 @@ static int object_clear_transform_generic_exec(bContext *C,
return OPERATOR_CANCELLED;
}
+ /* Support transforming the object data. */
+ const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ SCE_XFORM_DATA_ORIGIN);
+ struct XFormObjectData_Container *xds = NULL;
+
+ if (use_transform_data_origin) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ xds = ED_object_data_xform_container_create();
+ }
+
/* get KeyingSet to use */
ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
@@ -311,18 +324,29 @@ static int object_clear_transform_generic_exec(bContext *C,
* (so that object-transform clearing won't be applied at same time as bone-clearing)
*/
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
- /* run provided clearing function */
- clear_func(ob, clear_delta);
-
- ED_autokeyframe_object(C, scene, ob, ks);
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ continue;
+ }
- /* tag for updates */
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_item_ensure(xds, ob);
}
+
+ /* run provided clearing function */
+ clear_func(ob, clear_delta);
+
+ ED_autokeyframe_object(C, scene, ob, ks);
+
+ /* tag for updates */
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
CTX_DATA_END;
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_update_all(xds, bmain, depsgraph);
+ ED_object_data_xform_container_destroy(xds);
+ }
+
/* this is needed so children are also updated */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 021c17a94c2..0998280c381 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
+ ../../../../intern/mantaflow/extern
)
set(INC_SYS
@@ -56,19 +57,10 @@ set(LIB
)
if(WITH_MOD_FLUID)
- list(APPEND INC
- ../../../../intern/elbeem/extern
- )
- list(APPEND LIB
- bf_intern_elbeem
- )
- add_definitions(-DWITH_MOD_FLUID)
-endif()
-
-if(WITH_MOD_SMOKE)
list(APPEND LIB
- bf_intern_smoke
+ bf_intern_mantaflow
)
+ add_definitions(-DWITH_FLUID)
endif()
if(WITH_INTERNATIONAL)
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f16a372cb3c..9d3388bd220 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -5324,6 +5324,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
psys_reset(psys, PSYS_RESET_DEPSGRAPH);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
}
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index aee79523c87..e85b025e28e 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -262,6 +262,11 @@ static void particle_undosys_step_decode(struct bContext *C,
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+ if ((pset->flag & PE_DRAW_PART) != 0) {
+ psys_free_path_cache(NULL, edit);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ }
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index cfb3a400f47..4df74434c6a 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1065,7 +1065,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
if (ELEM(md->type,
eModifierType_ParticleSystem,
eModifierType_DynamicPaint,
- eModifierType_Smoke)) {
+ eModifierType_Fluid)) {
BLI_remlink(&ob_to->modifiers, md);
modifier_free(md);
}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 44858e36fab..5414c2a44a2 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -18,7 +18,7 @@
*/
/** \file
- * \ingroup edphys
+ * \ingroup edphys
*/
#include <math.h>
@@ -31,1219 +31,808 @@
/* types */
#include "DNA_action_types.h"
#include "DNA_object_types.h"
-#include "DNA_object_fluidsim_types.h"
+#include "BLI_blenlib.h"
+#include "BLI_path_util.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_fluidsim.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_fluid.h"
+#include "BKE_global.h"
#include "DEG_depsgraph.h"
#include "ED_screen.h"
-#include "ED_object.h"
+#include "PIL_time.h"
#include "WM_types.h"
#include "WM_api.h"
#include "physics_intern.h" // own include
+#include "manta_fluid_API.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_fluid_types.h"
+#include "DNA_mesh_types.h"
+
+#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
+#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
+#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
+#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
+#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
+#define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides"
+#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
+#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
+#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
+#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
+#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
+#define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides"
+#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
+
+typedef struct FluidJob {
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+ const char *type;
+ const char *name;
-/* enable/disable overall compilation */
-#ifdef WITH_MOD_FLUID
-
-# include "LBM_fluidsim.h"
-
-# include "BLI_blenlib.h"
-# include "BLI_path_util.h"
-# include "BLI_math.h"
+ struct Main *bmain;
+ Scene *scene;
+ Depsgraph *depsgraph;
+ Object *ob;
-# include "BKE_global.h"
-# include "BKE_main.h"
+ FluidModifierData *mmd;
-# include "WM_api.h"
+ int success;
+ double start;
-# include "DNA_scene_types.h"
-# include "DNA_mesh_types.h"
+ int *pause_frame;
+} FluidJob;
-static float get_fluid_viscosity(FluidsimSettings *settings)
+static inline bool fluid_is_bake_all(FluidJob *job)
{
- return (1.0f / powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue;
+ return (STREQ(job->type, FLUID_JOB_BAKE_ALL));
}
-
-static float get_fluid_rate(FluidsimSettings *settings)
+static inline bool fluid_is_bake_data(FluidJob *job)
{
- float rate = 1.0f; /* default rate if not animated... */
-
- rate = settings->animRate;
-
- if (rate < 0.0f) {
- rate = 0.0f;
- }
-
- return rate;
+ return (STREQ(job->type, FLUID_JOB_BAKE_DATA));
}
-
-static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss)
+static inline bool fluid_is_bake_noise(FluidJob *job)
{
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- }
- else {
- copy_v3_v3(gravity, fss->grav);
- }
+ return (STREQ(job->type, FLUID_JOB_BAKE_NOISE));
}
-
-static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss)
+static inline bool fluid_is_bake_mesh(FluidJob *job)
{
- if (!scene->unit.system) {
- return fss->realsize;
- }
- else {
- float dim[3];
- float longest_axis;
-
- BKE_object_dimensions_get(domainob, dim);
- longest_axis = max_fff(dim[0], dim[1], dim[2]);
-
- return longest_axis * scene->unit.scale_length;
- }
+ return (STREQ(job->type, FLUID_JOB_BAKE_MESH));
}
-
-static bool fluid_is_animated_mesh(FluidsimSettings *fss)
+static inline bool fluid_is_bake_particle(FluidJob *job)
{
- return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen);
+ return (STREQ(job->type, FLUID_JOB_BAKE_PARTICLES));
}
-
-/* ********************** fluid sim settings struct functions ********************** */
-
-# if 0
-/* helper function */
-void fluidsimGetGeometryObjFilename(Object *ob, char *dst) //, char *srcname)
+static inline bool fluid_is_bake_guiding(FluidJob *job)
{
- //BLI_snprintf(dst, FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
- BLI_snprintf(dst, FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
+ return (STREQ(job->type, FLUID_JOB_BAKE_GUIDES));
}
-# endif
-
-/* ********************** fluid sim channel helper functions ********************** */
-
-typedef struct FluidAnimChannels {
- int length;
-
- double aniFrameTime;
-
- float *timeAtFrame;
- float *DomainTime;
- float *DomainGravity;
- float *DomainViscosity;
-} FluidAnimChannels;
-
-typedef struct FluidObject {
- struct FluidObject *next, *prev;
-
- struct Object *object;
-
- float *Translation;
- float *Rotation;
- float *Scale;
- float *Active;
-
- float *InitialVelocity;
-
- float *AttractforceStrength;
- float *AttractforceRadius;
- float *VelocityforceStrength;
- float *VelocityforceRadius;
-
- float *VertexCache;
- int numVerts, numTris;
-} FluidObject;
-
-// no. of entries for the two channel sizes
-# define CHANNEL_FLOAT 1
-# define CHANNEL_VEC 3
-
-// simplify channels before printing
-// for API this is done anyway upon init
-# if 0
-static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries)
+static inline bool fluid_is_free_all(FluidJob *job)
{
- int i, j;
- int channelSize = paramsize;
-
- if (entries == 3) {
- elbeemSimplifyChannelVec3(channel, &channelSize);
- }
- else if (entries == 1) {
- elbeemSimplifyChannelFloat(channel, &channelSize);
- }
- else {
- /* invalid, cant happen? */
- }
-
- fprintf(file, " CHANNEL %s =\n", str);
- for (i = 0; i < channelSize; i++) {
- fprintf(file, " ");
- for (j = 0; j <= entries; j++) { // also print time value
- fprintf(file, " %f ", channel[i * (entries + 1) + j]);
- if (j == entries - 1) {
- fprintf(file, " ");
- }
- }
- fprintf(file, "\n");
- }
-
- fprintf(file, " ;\n");
+ return (STREQ(job->type, FLUID_JOB_FREE_ALL));
}
-# endif
-
-/* Note: fluid anim channel data layout
- * ------------------------------------
- * CHANNEL_FLOAT:
- * frame 1 |frame 2
- * [dataF][time][dataF][time]
- *
- * CHANNEL_VEC:
- * frame 1 |frame 2
- * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time]
- */
-
-static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels)
+static inline bool fluid_is_free_data(FluidJob *job)
{
- int i;
-
- channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float),
- "timeAtFrame channel");
-
- channels->timeAtFrame[0] = channels->timeAtFrame[1] =
- domainSettings->animStart; // start at index 1
-
- for (i = 2; i <= channels->length; i++) {
- channels->timeAtFrame[i] = channels->timeAtFrame[i - 1] + (float)channels->aniFrameTime;
- }
+ return (STREQ(job->type, FLUID_JOB_FREE_DATA));
}
-
-/* if this is slow, can replace with faster, less readable code */
-static void set_channel(float *channel, float time, float *value, int i, int size)
+static inline bool fluid_is_free_noise(FluidJob *job)
{
- if (size == CHANNEL_FLOAT) {
- channel[(i * 2) + 0] = value[0];
- channel[(i * 2) + 1] = time;
- }
- else if (size == CHANNEL_VEC) {
- channel[(i * 4) + 0] = value[0];
- channel[(i * 4) + 1] = value[1];
- channel[(i * 4) + 2] = value[2];
- channel[(i * 4) + 3] = time;
- }
+ return (STREQ(job->type, FLUID_JOB_FREE_NOISE));
}
-
-static void set_vertex_channel(Depsgraph *depsgraph,
- float *channel,
- float time,
- struct Scene *scene,
- struct FluidObject *fobj,
- int i)
+static inline bool fluid_is_free_mesh(FluidJob *job)
{
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float *verts;
- int *tris = NULL, numVerts = 0, numTris = 0;
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
- int framesize = (3 * fobj->numVerts) + 1;
- int j;
-
- if (channel == NULL) {
- return;
- }
+ return (STREQ(job->type, FLUID_JOB_FREE_MESH));
+}
+static inline bool fluid_is_free_particles(FluidJob *job)
+{
+ return (STREQ(job->type, FLUID_JOB_FREE_PARTICLES));
+}
+static inline bool fluid_is_free_guiding(FluidJob *job)
+{
+ return (STREQ(job->type, FLUID_JOB_FREE_GUIDES));
+}
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
+static bool fluid_initjob(
+ bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
+{
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
- /* don't allow mesh to change number of verts in anim sequence */
- if (numVerts != fobj->numVerts) {
- MEM_freeN(channel);
- channel = NULL;
- return;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
+ return false;
}
-
- /* fill frame of channel with vertex locations */
- for (j = 0; j < (3 * numVerts); j++) {
- channel[i * framesize + j] = verts[j];
+ mds = mmd->domain;
+ if (!mds) {
+ BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size);
+ return false;
}
- channel[i * framesize + framesize - 1] = time;
- MEM_freeN(verts);
- MEM_freeN(tris);
-}
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ job->depsgraph = CTX_data_depsgraph_pointer(C);
+ job->ob = CTX_data_active_object(C);
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
-static void free_domain_channels(FluidAnimChannels *channels)
-{
- if (!channels->timeAtFrame) {
- return;
- }
- MEM_freeN(channels->timeAtFrame);
- channels->timeAtFrame = NULL;
- MEM_freeN(channels->DomainGravity);
- channels->DomainGravity = NULL;
- MEM_freeN(channels->DomainViscosity);
- channels->DomainViscosity = NULL;
- MEM_freeN(channels->DomainTime);
- channels->DomainTime = NULL;
+ return true;
}
-static void free_all_fluidobject_channels(ListBase *fobjects)
+static bool fluid_initpaths(FluidJob *job, ReportList *reports)
{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- if (fobj->Translation) {
- MEM_freeN(fobj->Translation);
- fobj->Translation = NULL;
- MEM_freeN(fobj->Rotation);
- fobj->Rotation = NULL;
- MEM_freeN(fobj->Scale);
- fobj->Scale = NULL;
- MEM_freeN(fobj->Active);
- fobj->Active = NULL;
- MEM_freeN(fobj->InitialVelocity);
- fobj->InitialVelocity = NULL;
- }
-
- if (fobj->AttractforceStrength) {
- MEM_freeN(fobj->AttractforceStrength);
- fobj->AttractforceStrength = NULL;
- MEM_freeN(fobj->AttractforceRadius);
- fobj->AttractforceRadius = NULL;
- MEM_freeN(fobj->VelocityforceStrength);
- fobj->VelocityforceStrength = NULL;
- MEM_freeN(fobj->VelocityforceRadius);
- fobj->VelocityforceRadius = NULL;
- }
+ FluidDomainSettings *mds = job->mmd->domain;
+ char temp_dir[FILE_MAX];
+ temp_dir[0] = '\0';
- if (fobj->VertexCache) {
- MEM_freeN(fobj->VertexCache);
- fobj->VertexCache = NULL;
- }
- }
-}
+ const char *relbase = modifier_path_relbase(job->bmain, job->ob);
-static void fluid_init_all_channels(bContext *C,
- Depsgraph *depsgraph,
- Object *UNUSED(fsDomain),
- FluidsimSettings *domainSettings,
- FluidAnimChannels *channels,
- ListBase *fobjects)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base;
- int i;
- int length = channels->length;
- float eval_time;
-
- /* init time values (assuming that time moves at a constant speed; may be overridden later) */
- init_time(domainSettings, channels);
-
- /* allocate domain animation channels */
- channels->DomainGravity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "channel DomainGravity");
- channels->DomainViscosity = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainViscosity");
- channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainTime");
-
- /* allocate fluid objects */
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- if (fluidmd) {
- FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object");
- fobj->object = ob;
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- BLI_addtail(fobjects, fobj);
- continue;
- }
-
- fobj->Translation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Translation");
- fobj->Rotation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Rotation");
- fobj->Scale = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), "fluidobject Scale");
- fobj->Active = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject Active");
- fobj->InitialVelocity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject InitialVelocity");
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- fobj->AttractforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceStrength");
- fobj->AttractforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceRadius");
- fobj->VelocityforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceStrength");
- fobj->VelocityforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceRadius");
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- float *verts = NULL;
- int *tris = NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd);
-
- initElbeemMesh(depsgraph,
- scene,
- ob,
- &fobj->numVerts,
- &verts,
- &fobj->numTris,
- &tris,
- 0,
- modifierIndex);
- fobj->VertexCache = MEM_callocN(length * ((fobj->numVerts * CHANNEL_VEC) + 1) *
- sizeof(float),
- "fluidobject VertexCache");
-
- MEM_freeN(verts);
- MEM_freeN(tris);
- }
-
- BLI_addtail(fobjects, fobj);
- }
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (mds->cache_directory[0] == '\0') {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Fluid: Empty cache path, reset to default '%s'",
+ mds->cache_directory);
}
- /* now we loop over the frames and fill the allocated channels with data */
- for (i = 0; i < channels->length; i++) {
- FluidObject *fobj;
- float viscosity, gravity[3];
- float timeAtFrame, time;
+ BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(temp_dir, relbase);
- eval_time = domainSettings->bakeStart + i;
+ /* Ensure whole path exists */
+ const bool dir_exists = BLI_dir_create_recursive(temp_dir);
- /* Modifying the global scene isn't nice, but we can do it in
- * this part of the process before a threaded job is created */
- scene->r.cfra = (int)eval_time;
- ED_update_for_newframe(CTX_data_main(C), depsgraph);
+ /* We change path to some presumably valid default value, but do not allow bake process to
+ * continue, this gives user chance to set manually another path. */
+ if (!dir_exists) {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
- /* now scene data should be current according to animation system, so we fill the channels */
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid: Could not create cache directory '%s', reset to default '%s'",
+ temp_dir,
+ mds->cache_directory);
- /* Domain time */
- /* TODO: have option for not running sim, time mangling,
- * in which case second case comes in handy. */
- if (channels->DomainTime) {
- time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime;
- timeAtFrame = channels->timeAtFrame[i] + time;
+ BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(temp_dir, relbase);
- channels->timeAtFrame[i + 1] = timeAtFrame;
- set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT);
- }
- else {
- timeAtFrame = channels->timeAtFrame[i + 1];
+ /* Ensure whole path exists and is writable. */
+ if (!BLI_dir_create_recursive(temp_dir)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid: Could not use default cache directory '%s', "
+ "please define a valid cache path manually",
+ temp_dir);
}
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR);
- /* Domain properties - gravity/viscosity */
- get_fluid_gravity(gravity, scene, domainSettings);
- set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC);
- viscosity = get_fluid_viscosity(domainSettings);
- set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT);
-
- /* object movement */
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float active = (float)((fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE) ? 1 : 0);
- float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f};
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
-
- /* init euler rotation values and convert to elbeem format */
- /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */
- if (i) {
- copy_v3_v3(old_rot, fobj->Rotation + 4 * (i - 1));
- mul_v3_fl(old_rot, (float)-M_PI / 180.f);
- }
-
- mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat);
- mul_v3_fl(rot_d, -180.0f / (float)M_PI);
-
- set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC);
- set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC);
- set_channel(fobj->Scale, timeAtFrame, ob->scale, i, CHANNEL_VEC);
- set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT);
- set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC);
-
- // printf("Active: %f, Frame: %f\n", active, timeAtFrame);
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- set_channel(fobj->AttractforceStrength,
- timeAtFrame,
- &fluidmd->fss->attractforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->AttractforceRadius,
- timeAtFrame,
- &fluidmd->fss->attractforceRadius,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceStrength,
- timeAtFrame,
- &fluidmd->fss->velocityforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceRadius,
- timeAtFrame,
- &fluidmd->fss->velocityforceRadius,
- i,
- CHANNEL_FLOAT);
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- set_vertex_channel(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i);
- }
- }
+ return false;
}
+
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR);
+ return true;
}
-static void export_fluid_objects(Depsgraph *depsgraph,
- ListBase *fobjects,
- Scene *scene,
- int length)
+static void fluid_bake_free(void *customdata)
{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
+ FluidJob *job = customdata;
+ MEM_freeN(job);
+}
- float *verts = NULL;
- int *tris = NULL;
- int numVerts = 0, numTris = 0;
- bool deform = fluid_is_animated_mesh(fluidmd->fss);
+static void fluid_bake_sequence(FluidJob *job)
+{
+ FluidDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
+ int frame = 1, orig_frame;
+ int frames;
+ int *pause_frame = NULL;
+ bool is_first_frame;
- elbeemMesh fsmesh;
+ frames = mds->cache_frame_end - mds->cache_frame_start + 1;
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
+ if (frames <= 0) {
+ BLI_strncpy(mds->error, N_("No frames to bake"), sizeof(mds->error));
+ return;
+ }
- elbeemResetMesh(&fsmesh);
+ /* Show progress bar. */
+ if (job->do_update) {
+ *(job->do_update) = true;
+ }
- fsmesh.type = fluidmd->fss->type;
- fsmesh.name = ob->id.name;
+ /* Get current pause frame (pointer) - depending on bake type */
+ pause_frame = job->pause_frame;
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
+ /* Set frame to start point (depending on current pause frame value) */
+ is_first_frame = ((*pause_frame) == 0);
+ frame = is_first_frame ? mds->cache_frame_start : (*pause_frame);
- fsmesh.numVertices = numVerts;
- fsmesh.numTriangles = numTris;
- fsmesh.vertices = verts;
- fsmesh.triangles = tris;
+ /* Save orig frame and update scene frame */
+ orig_frame = CFRA;
+ CFRA = frame;
- fsmesh.channelSizeTranslation = fsmesh.channelSizeRotation = fsmesh.channelSizeScale =
- fsmesh.channelSizeInitialVel = fsmesh.channelSizeActive = length;
+ /* Loop through selected frames */
+ for (; frame <= mds->cache_frame_end; frame++) {
+ const float progress = (frame - mds->cache_frame_start) / (float)frames;
- fsmesh.channelTranslation = fobj->Translation;
- fsmesh.channelRotation = fobj->Rotation;
- fsmesh.channelScale = fobj->Scale;
- fsmesh.channelActive = fobj->Active;
+ /* Keep track of pause frame - needed to init future loop */
+ (*pause_frame) = frame;
- if (ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fsmesh.channelInitialVel = fobj->InitialVelocity;
- fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD) ? 1 : 0);
+ /* If user requested stop, quit baking */
+ if (G.is_break) {
+ job->success = 0;
+ return;
}
- if (fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
+ /* Update progress bar */
+ if (job->do_update) {
+ *(job->do_update) = true;
}
- else if (fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
+ if (job->progress) {
+ *(job->progress) = progress;
}
- fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue;
- fsmesh.volumeInitType = fluidmd->fss->volumeInitType;
- fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value
-
- if (fsmesh.type == OB_FLUIDSIM_CONTROL) {
- fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart;
- fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd;
- fsmesh.cpsQuality = fluidmd->fss->cpsQuality;
- fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE);
+ CFRA = frame;
- fsmesh.channelSizeAttractforceRadius = fsmesh.channelSizeVelocityforceStrength =
- fsmesh.channelSizeVelocityforceRadius = fsmesh.channelSizeAttractforceStrength = length;
-
- fsmesh.channelAttractforceStrength = fobj->AttractforceStrength;
- fsmesh.channelAttractforceRadius = fobj->AttractforceRadius;
- fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength;
- fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius;
- }
- else {
- fsmesh.channelAttractforceStrength = fsmesh.channelAttractforceRadius =
- fsmesh.channelVelocityforceStrength = fsmesh.channelVelocityforceRadius = NULL;
- }
-
- /* animated meshes */
- if (deform) {
- fsmesh.channelSizeVertices = length;
- fsmesh.channelVertices = fobj->VertexCache;
-
- /* remove channels */
- fsmesh.channelTranslation = fsmesh.channelRotation = fsmesh.channelScale = NULL;
-
- /* Override user settings, only noslip is supported here! */
- if (fsmesh.type != OB_FLUIDSIM_CONTROL) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- }
+ /* Update animation system */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
+ }
- elbeemAddMesh(&fsmesh);
+ /* Restore frame position that we were on before bake */
+ CFRA = orig_frame;
+}
- if (verts) {
- MEM_freeN(verts);
+static void fluid_bake_endjob(void *customdata)
+{
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_NOISE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_NOISE;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
+ }
+ if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_MESH;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_MESH;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH;
+ }
+ if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_PARTICLES;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_PARTICLES;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
+ }
+ if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_GUIDE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_GUIDE;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
+ }
+ if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_DATA;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_DATA;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
+ }
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ /* Bake was successful:
+ * Report for ended bake and how long it took */
+ if (job->success) {
+ /* Show bake info */
+ WM_reportf(
+ RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
+ }
+ else {
+ if (mds->error != NULL && mds->error[0] != '\0') {
+ WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
- if (tris) {
- MEM_freeN(tris);
+ else { /* User canceled the bake */
+ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
}
}
}
-static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain)
+static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- Base *base;
- Object *newdomain = NULL;
- int channelObjCount = 0;
- int fluidInputCount = 0;
-
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- /* only find objects with fluid modifiers */
- if (!fluidmdtmp || ob->type != OB_MESH) {
- continue;
- }
-
- if (fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) {
- /* if no initial domain object given, find another potential domain */
- if (!fsDomain) {
- newdomain = ob;
- }
- /* if there's more than one domain, cancel */
- else if (fsDomain && ob != fsDomain) {
- BKE_report(reports, RPT_ERROR, "There should be only one domain object");
- return 0;
- }
- }
-
- /* count number of objects needed for animation channels */
- if (!ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- channelObjCount++;
- }
-
- /* count number of fluid input objects */
- if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fluidInputCount++;
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ char temp_dir[FILE_MAX];
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
+
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE;
+ job->pause_frame = &mds->cache_frame_pause_noise;
+ }
+ if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_MESH;
+ job->pause_frame = &mds->cache_frame_pause_mesh;
+ }
+ if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(
+ temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_dir_create_recursive(
+ temp_dir); /* Create 'particles' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES;
+ job->pause_frame = &mds->cache_frame_pause_particles;
+ }
+ if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDE;
+ job->pause_frame = &mds->cache_frame_pause_guide;
+ }
+ if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
+
+ BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_DATA;
+ job->pause_frame = &mds->cache_frame_pause_data;
+
+ if (mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
+ BLI_path_join(
+ temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
}
}
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
- if (newdomain) {
- fsDomain = newdomain;
- }
+ fluid_bake_sequence(job);
- if (!fsDomain) {
- BKE_report(reports, RPT_ERROR, "No domain object found");
- return 0;
+ if (do_update) {
+ *do_update = true;
}
-
- if (channelObjCount >= 255) {
- BKE_report(reports, RPT_ERROR, "Cannot bake with more than 256 objects");
- return 0;
+ if (stop) {
+ *stop = 0;
}
-
- if (fluidInputCount == 0) {
- BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene");
- return 0;
- }
-
- return 1;
}
-# define FLUID_SUFFIX_CONFIG "fluidsim.cfg"
-# define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
-# define FLUID_SUFFIX_SURFACE "fluidsurface"
-
-static bool fluid_init_filepaths(Main *bmain,
- ReportList *reports,
- FluidsimSettings *domainSettings,
- Object *fsDomain,
- char *targetDir,
- char *targetFile)
+static void fluid_free_endjob(void *customdata)
{
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
- /* prepare names... */
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
- /* We do not accept empty paths, they can end in random places silently, see T51176. */
- if (domainSettings->surfdataPath[0] == '\0') {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
- BKE_reportf(reports,
- RPT_WARNING,
- "Fluidsim: empty cache path, reset to default '%s'",
- domainSettings->surfdataPath);
+ /* Free was successful:
+ * Report for ended free job and how long it took */
+ if (job->success) {
+ /* Show free job info */
+ WM_reportf(
+ RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
-
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is writeable. */
- const bool dir_exists = BLI_dir_create_recursive(targetDir);
- const bool is_writable = BLI_file_is_writable(targetFile);
-
- /* We change path to some presumably valid default value,
- * but do not allow bake process to continue,
- * this gives user chance to set manually another path. */
- if (!dir_exists || !is_writable) {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
-
- if (!dir_exists) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not create cache directory '%s', reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
+ else {
+ if (mds->error != NULL && mds->error[0] != '\0') {
+ WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
- else {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
+ else { /* User canceled the free job */
+ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
}
-
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is writeable. */
- if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not use default cache directory '%s', "
- "please define a valid cache path manually",
- targetDir);
- }
- return false;
}
-
- return true;
}
-/* ******************************************************************************** */
-/* ********************** write fluidsim config to file ************************* */
-/* ******************************************************************************** */
+static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
-typedef struct FluidBakeJob {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- float *progress;
- int current_frame;
- elbeemSimulationSettings *settings;
-} FluidBakeJob;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
-static void fluidbake_free(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
- MEM_freeN(fb);
-}
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
-/* called by fluidbake, only to check job 'stop' value */
-static int fluidbake_breakjob(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ int cache_map = 0;
- if (fb->stop && *(fb->stop)) {
- return 1;
+ if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
+ cache_map |= (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ }
+ if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
+ }
+ if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
+ }
+ if (fluid_is_free_particles(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_PARTICLES;
+ }
+ if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_GUIDE;
}
+#ifdef WITH_FLUID
+ BKE_fluid_cache_free(mds, job->ob, cache_map);
+#endif
- /* this is not nice yet, need to make the jobs list template better
- * for identifying/acting upon various different jobs */
- /* but for now we'll reuse the render break... */
- return (G.is_break);
-}
+ *do_update = true;
+ *stop = 0;
-/* called by fluidbake, wmJob sends notifier */
-static void fluidbake_updatejob(void *customdata, float progress)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ /* Reset scene frame to cache frame start */
+ CFRA = mds->cache_frame_start;
- *(fb->do_update) = true;
- *(fb->progress) = progress;
+ /* Update scene so that viewport shows freed up scene */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
}
-static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+/***************************** Operators ******************************/
- fb->stop = stop;
- fb->do_update = do_update;
- fb->progress = progress;
+static int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ char error_msg[256] = "\0";
- G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
+ if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ fluid_bake_free(job);
+ return OPERATOR_CANCELLED;
+ }
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ fluid_bake_startjob(job, NULL, NULL, NULL);
+ fluid_bake_endjob(job);
+ fluid_bake_free(job);
- elbeemSimulate();
- *do_update = true;
- *stop = 0;
+ return OPERATOR_FINISHED;
}
-static void fluidbake_endjob(void *customdata)
+static int fluid_bake_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const wmEvent *UNUSED(_event))
{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ Scene *scene = CTX_data_scene(C);
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ char error_msg[256] = "\0";
- if (fb->settings) {
- MEM_freeN(fb->settings);
- fb->settings = NULL;
+ if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ fluid_bake_free(job);
+ return OPERATOR_CANCELLED;
}
-}
-static int runSimulationCallback(void *data, int status, int frame)
-{
- FluidBakeJob *fb = (FluidBakeJob *)data;
- elbeemSimulationSettings *settings = fb->settings;
-
- if (status == FLUIDSIM_CBSTATUS_NEWFRAME) {
- fluidbake_updatejob(fb, frame / (float)settings->noOfFrames);
-# if 0
- printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n",
- status,
- frame,
- settings->domainId,
- settings->noOfFrames); // DEBUG
-# endif
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
}
- if (fluidbake_breakjob(fb)) {
- return FLUIDSIM_CBRET_ABORT;
- }
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Bake",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_FLUID);
+
+ WM_jobs_customdata_set(wm_job, job, fluid_bake_free);
+ WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_bake_startjob, NULL, NULL, fluid_bake_endjob);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_event_add_modal_handler(C, op);
- return FLUIDSIM_CBRET_CONTINUE;
+ return OPERATOR_RUNNING_MODAL;
}
-static void fluidbake_free_data(FluidAnimChannels *channels,
- ListBase *fobjects,
- elbeemSimulationSettings *fsset,
- FluidBakeJob *fb)
+static int fluid_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- free_domain_channels(channels);
- MEM_freeN(channels);
- channels = NULL;
-
- free_all_fluidobject_channels(fobjects);
- BLI_freelistN(fobjects);
- MEM_freeN(fobjects);
- fobjects = NULL;
-
- if (fsset) {
- MEM_freeN(fsset);
- fsset = NULL;
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
- if (fb) {
- MEM_freeN(fb);
- fb = NULL;
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
}
+ return OPERATOR_PASS_THROUGH;
}
-/* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
-static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
+static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
{
- char targetDir[FILE_MAX], targetFile[FILE_MAX];
- char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX];
- char previewDir[FILE_MAX], previewFile[FILE_MAX];
- int curFrame = 1, exists = 0;
-
- BLI_join_dirfile(
- targetDir, sizeof(targetDir), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
- BLI_join_dirfile(
- targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME);
- BLI_join_dirfile(
- previewDir, sizeof(previewDir), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
-
- BLI_path_abs(targetDir, relbase);
- BLI_path_abs(targetDirVel, relbase);
- BLI_path_abs(previewDir, relbase);
-
- do {
- BLI_strncpy(targetFile, targetDir, sizeof(targetFile));
- BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel));
- BLI_strncpy(previewFile, previewDir, sizeof(previewFile));
-
- BLI_path_frame(targetFile, curFrame, 0);
- BLI_path_frame(targetFileVel, curFrame, 0);
- BLI_path_frame(previewFile, curFrame, 0);
-
- curFrame++;
-
- if ((exists = BLI_exists(targetFile))) {
- BLI_delete(targetFile, false, false);
- BLI_delete(targetFileVel, false, false);
- BLI_delete(previewFile, false, false);
- }
- } while (exists);
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
- return;
-}
+ /*
+ * Get modifier data
+ */
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
+ }
-static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- int i;
- FluidsimSettings *domainSettings;
-
- char debugStrBuffer[256];
-
- int gridlevels = 0;
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
- const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- const char *suffixSurface = FLUID_SUFFIX_SURFACE;
-
- char targetDir[FILE_MAX]; // store & modify output settings
- char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
-
- float domainMat[4][4];
- float invDomMat[4][4];
-
- int noFrames;
- int origFrame = scene->r.cfra;
-
- FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels),
- "fluid domain animation channels");
- ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
- FluidsimModifierData *fluidmd = NULL;
- Mesh *mesh = NULL;
-
- FluidBakeJob *fb;
- elbeemSimulationSettings *fsset = MEM_callocN(sizeof(elbeemSimulationSettings),
- "Fluid sim settings");
-
- fb = MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
-
- if (BLI_getenv(strEnvName)) {
- int dlevel = atoi(BLI_getenv(strEnvName));
- elbeemSetDebugLevel(dlevel);
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",
- strEnvName);
- elbeemDebugOut(debugStrBuffer);
+ /* Cannot free data if other bakes currently working */
+ if (mmd->domain->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE |
+ FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES)) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
+ return OPERATOR_CANCELLED;
}
- /* Make sure it corresponds to startFrame setting
- * (old: noFrames = scene->r.efra - scene->r.sfra +1). */
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ job->bmain = CTX_data_main(C);
+ job->scene = scene;
+ job->depsgraph = CTX_data_depsgraph_pointer(C);
+ job->ob = ob;
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
- noFrames = scene->r.efra - 0;
- if (noFrames <= 0) {
- BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)");
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
}
- /* check scene for sane object/modifier settings */
- if (!fluid_validate_scene(reports, view_layer, fsDomain)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Free",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_FLUID);
- /* these both have to be valid, otherwise we wouldn't be here */
- fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- domainSettings = fluidmd->fss;
- mesh = fsDomain->data;
-
- domainSettings->bakeStart = 1;
- domainSettings->bakeEnd = scene->r.efra;
-
- // calculate bounding box
- fluid_get_bb(mesh->mvert,
- mesh->totvert,
- fsDomain->obmat,
- domainSettings->bbStart,
- domainSettings->bbSize);
-
- // reset last valid frame
- domainSettings->lastgoodframe = -1;
-
- /* delete old baked files */
- fluidsim_delete_until_lastframe(domainSettings, relbase);
-
- /* rough check of settings... */
- if (domainSettings->previewresxyz > domainSettings->resolutionxyz) {
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n",
- domainSettings->previewresxyz,
- domainSettings->resolutionxyz);
- elbeemDebugOut(debugStrBuffer);
- domainSettings->previewresxyz = domainSettings->resolutionxyz;
- }
- // set adaptive coarsening according to resolutionxyz
- // this should do as an approximation, with in/outflow
- // doing this more accurate would be overkill
- // perhaps add manual setting?
- if (domainSettings->maxRefine < 0) {
- if (domainSettings->resolutionxyz > 128) {
- gridlevels = 2;
- }
- else if (domainSettings->resolutionxyz > 64) {
- gridlevels = 1;
- }
- else {
- gridlevels = 0;
- }
- }
- else {
- gridlevels = domainSettings->maxRefine;
- }
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Baking %s, refine: %d\n",
- fsDomain->id.name,
- gridlevels);
- elbeemDebugOut(debugStrBuffer);
-
- /* ******** prepare output file paths ******** */
- if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return false;
- }
+ WM_jobs_customdata_set(wm_job, job, fluid_bake_free);
+ WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_free_startjob, NULL, NULL, fluid_free_endjob);
- /* DG TODO: why using endframe and not "noFrames" here?
- * because "noFrames" is buggy too? (not using sfra) */
- channels->length = scene->r.efra;
- channels->aniFrameTime = (double)((double)domainSettings->animEnd -
- (double)domainSettings->animStart) /
- (double)noFrames;
-
- /* ******** initialize and allocate animation channels ******** */
- fluid_init_all_channels(C, depsgraph, fsDomain, domainSettings, channels, fobjects);
-
- /* reset to original current frame */
- scene->r.cfra = origFrame;
- ED_update_for_newframe(CTX_data_main(C), CTX_data_depsgraph_pointer(C));
-
- /* ******** init domain object's matrix ******** */
- copy_m4_m4(domainMat, fsDomain->obmat);
- if (!invert_m4_m4(invDomMat, domainMat)) {
- BLI_snprintf(
- debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n");
- elbeemDebugOut(debugStrBuffer);
- BKE_report(reports, RPT_ERROR, "Invalid object matrix");
-
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
+ WM_set_locked_interface(CTX_wm_manager(C), true);
- /* ******** start writing / exporting ******** */
- // use .tmp, don't overwrite/delete original file
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- /* ******** export domain to elbeem ******** */
- elbeemResetSettings(fsset);
- fsset->version = 1;
- fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) :
- domainSettings->threads;
- // setup global settings
- copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
- copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
-
- // simulate with 50^3
- fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
- fsset->previewresxyz = (int)domainSettings->previewresxyz;
-
- fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
- fsset->viscosity = get_fluid_viscosity(domainSettings);
- get_fluid_gravity(fsset->gravity, scene, domainSettings);
-
- // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
- fsset->animStart = domainSettings->animStart;
- fsset->aniFrameTime = channels->aniFrameTime;
- fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
-
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
-
- // defaults for compressibility and adaptive grids
- fsset->gstar = domainSettings->gstar;
- fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
- fsset->generateParticles = domainSettings->generateParticles;
- fsset->numTracerParticles = domainSettings->generateTracers;
- fsset->surfaceSmoothing = domainSettings->surfaceSmoothing;
- fsset->surfaceSubdivs = domainSettings->surfaceSubdivs;
- fsset->farFieldSize = domainSettings->farFieldSize;
- BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
-
- // domain channels
- fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity =
- channels->length;
- fsset->channelFrameTime = channels->DomainTime;
- fsset->channelViscosity = channels->DomainViscosity;
- fsset->channelGravity = channels->DomainGravity;
-
- fsset->runsimCallback = &runSimulationCallback;
- fsset->runsimUserData = fb;
-
- if (domainSettings->typeFlags & OB_FSBND_NOSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (domainSettings->typeFlags & OB_FSBND_PARTSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
- }
- else if (domainSettings->typeFlags & OB_FSBND_FREESLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
- }
- fsset->domainobsPartslip = domainSettings->partSlipValue;
+ /* Free Fluid Geometry */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ return OPERATOR_FINISHED;
+}
- /* use domainobsType also for surface generation flag (bit: >=64) */
- if (domainSettings->typeFlags & OB_FSSG_NOOBS) {
- fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS;
+static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+
+ /*
+ * Get modifier data
+ */
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
}
- else {
- fsset->mFsSurfGenSetting = 0; // "normal" mode
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
}
- fsset->generateVertexVectors = (domainSettings->domainNovecgen == 0);
+ G.is_break = true;
- // init blender domain transform matrix
- {
- int j;
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- fsset->surfaceTrafo[i * 4 + j] = invDomMat[j][i];
- }
- }
- }
+ return OPERATOR_FINISHED;
+}
- /* ******** init solver with settings ******** */
- elbeemInit();
- elbeemAddDomain(fsset);
+void FLUID_OT_bake_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake All";
+ ot->description = "Bake Entire Fluid Simulation";
+ ot->idname = FLUID_JOB_BAKE_ALL;
- /* ******** export all fluid objects to elbeem ******** */
- export_fluid_objects(depsgraph, fobjects, scene, channels->length);
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* custom data for fluid bake job */
- fb->settings = fsset;
+void FLUID_OT_free_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free All";
+ ot->description = "Free Entire Fluid Simulation";
+ ot->idname = FLUID_JOB_FREE_ALL;
- if (do_job) {
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- scene,
- "Fluid Simulation",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_OBJECT_SIM_FLUID);
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* setup job */
- WM_jobs_customdata_set(wm_job, fb, fluidbake_free);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
+void FLUID_OT_bake_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Data";
+ ot->description = "Bake Fluid Data";
+ ot->idname = FLUID_JOB_BAKE_DATA;
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
- else {
- short dummy_stop = 0, dummy_do_update = 0;
- float dummy_progress = 0.0f;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* blocking, use with exec() */
- fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
- fluidbake_endjob((void *)fb);
- fluidbake_free((void *)fb);
- }
+void FLUID_OT_free_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Data";
+ ot->description = "Free Fluid Data";
+ ot->idname = FLUID_JOB_FREE_DATA;
+
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
- /* ******** free stored animation data ******** */
- fluidbake_free_data(channels, fobjects, NULL, NULL);
+void FLUID_OT_bake_noise(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Noise";
+ ot->description = "Bake Fluid Noise";
+ ot->idname = FLUID_JOB_BAKE_NOISE;
- // elbeemFree();
- return 1;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static void UNUSED_FUNCTION(fluidsimFreeBake)(Object *UNUSED(ob))
+void FLUID_OT_free_noise(wmOperatorType *ot)
{
- /* not implemented yet */
+ /* identifiers */
+ ot->name = "Free Noise";
+ ot->description = "Free Fluid Noise";
+ ot->idname = FLUID_JOB_FREE_NOISE;
+
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-#else /* WITH_MOD_FLUID */
+void FLUID_OT_bake_mesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Mesh";
+ ot->description = "Bake Fluid Mesh";
+ ot->idname = FLUID_JOB_BAKE_MESH;
+
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
-/* only compile dummy functions */
-static int fluidsimBake(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
- Object *UNUSED(ob),
- short UNUSED(do_job))
+void FLUID_OT_free_mesh(wmOperatorType *ot)
{
- return 0;
+ /* identifiers */
+ ot->name = "Free Mesh";
+ ot->description = "Free Fluid Mesh";
+ ot->idname = FLUID_JOB_FREE_MESH;
+
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-#endif /* WITH_MOD_FLUID */
+void FLUID_OT_bake_particles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Particles";
+ ot->description = "Bake Fluid Particles";
+ ot->idname = FLUID_JOB_BAKE_PARTICLES;
-/***************************** Operators ******************************/
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
+}
-static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+void FLUID_OT_free_particles(wmOperatorType *ot)
{
- /* only one bake job at a time */
- if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
- return OPERATOR_CANCELLED;
- }
+ /* identifiers */
+ ot->name = "Free Particles";
+ ot->description = "Free Fluid Particles";
+ ot->idname = FLUID_JOB_FREE_PARTICLES;
- if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) {
- return OPERATOR_CANCELLED;
- }
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
- return OPERATOR_FINISHED;
+void FLUID_OT_bake_guides(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bake Guides";
+ ot->description = "Bake Fluid Guiding";
+ ot->idname = FLUID_JOB_BAKE_GUIDES;
+
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static int fluid_bake_exec(bContext *C, wmOperator *op)
+void FLUID_OT_free_guides(wmOperatorType *ot)
{
- if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) {
- return OPERATOR_CANCELLED;
- }
+ /* identifiers */
+ ot->name = "Free Guides";
+ ot->description = "Free Fluid Guiding";
+ ot->idname = FLUID_JOB_FREE_GUIDES;
- return OPERATOR_FINISHED;
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-void FLUID_OT_bake(wmOperatorType *ot)
+void FLUID_OT_pause_bake(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Fluid Simulation Bake";
- ot->description = "Bake fluid simulation";
- ot->idname = "FLUID_OT_bake";
+ ot->name = "Pause Bake";
+ ot->description = "Pause Bake";
+ ot->idname = FLUID_JOB_BAKE_PAUSE;
/* api callbacks */
- ot->invoke = fluid_bake_invoke;
- ot->exec = fluid_bake_exec;
+ ot->exec = fluid_pause_exec;
ot->poll = ED_operator_object_active_editable;
}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index fc2f3d21bb6..3af818b3a9d 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -103,7 +103,19 @@ void BOID_OT_state_move_up(struct wmOperatorType *ot);
void BOID_OT_state_move_down(struct wmOperatorType *ot);
/* physics_fluid.c */
-void FLUID_OT_bake(struct wmOperatorType *ot);
+void FLUID_OT_bake_all(struct wmOperatorType *ot);
+void FLUID_OT_free_all(struct wmOperatorType *ot);
+void FLUID_OT_bake_data(struct wmOperatorType *ot);
+void FLUID_OT_free_data(struct wmOperatorType *ot);
+void FLUID_OT_bake_noise(struct wmOperatorType *ot);
+void FLUID_OT_free_noise(struct wmOperatorType *ot);
+void FLUID_OT_bake_mesh(struct wmOperatorType *ot);
+void FLUID_OT_free_mesh(struct wmOperatorType *ot);
+void FLUID_OT_bake_particles(struct wmOperatorType *ot);
+void FLUID_OT_free_particles(struct wmOperatorType *ot);
+void FLUID_OT_bake_guides(struct wmOperatorType *ot);
+void FLUID_OT_free_guides(struct wmOperatorType *ot);
+void FLUID_OT_pause_bake(struct wmOperatorType *ot);
/* dynamicpaint.c */
void DPAINT_OT_bake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index b1b3927d05e..d1536733b9b 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -126,7 +126,19 @@ static void operatortypes_boids(void)
static void operatortypes_fluid(void)
{
- WM_operatortype_append(FLUID_OT_bake);
+ WM_operatortype_append(FLUID_OT_bake_all);
+ WM_operatortype_append(FLUID_OT_free_all);
+ WM_operatortype_append(FLUID_OT_bake_data);
+ WM_operatortype_append(FLUID_OT_free_data);
+ WM_operatortype_append(FLUID_OT_bake_noise);
+ WM_operatortype_append(FLUID_OT_free_noise);
+ WM_operatortype_append(FLUID_OT_bake_mesh);
+ WM_operatortype_append(FLUID_OT_free_mesh);
+ WM_operatortype_append(FLUID_OT_bake_particles);
+ WM_operatortype_append(FLUID_OT_free_particles);
+ WM_operatortype_append(FLUID_OT_bake_guides);
+ WM_operatortype_append(FLUID_OT_free_guides);
+ WM_operatortype_append(FLUID_OT_pause_bake);
}
/**************************** point cache **********************************/
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 10244cfa3fd..3a77e1e1565 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_camera_types.h"
+#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_blenlib.h"
@@ -35,13 +36,18 @@
#include "BLI_threads.h"
#include "BLI_task.h"
+#include "DNA_anim_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -123,6 +129,9 @@ typedef struct OGLRender {
int totvideos;
+ /* For only rendering frames that have a key in animation data. */
+ BLI_bitmap *render_frames;
+
/* quick lookup */
int view_id;
@@ -517,6 +526,71 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
}
+static void gather_frames_to_render_for_adt(OGLRender *oglrender,
+ int frame_start,
+ int frame_end,
+ const AnimData *adt)
+{
+ if (adt == NULL || adt->action == NULL) {
+ return;
+ }
+
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
+ if (fcu->driver != NULL || fcu->fpt != NULL) {
+ /* Drivers have values for any point in time, so to get "the keyed frames" they are
+ * useless. Same for baked FCurves, they also have keys for every frame, which is not
+ * useful for rendering the keyed subset of the frames. */
+ continue;
+ }
+
+ bool found = false; /* Not interesting, we just want a starting point for the for-loop.*/
+ int key_index = binarysearch_bezt_index(fcu->bezt, frame_start, fcu->totvert, &found);
+ for (; key_index < fcu->totvert; key_index++) {
+ BezTriple *bezt = &fcu->bezt[key_index];
+ /* The frame range to render uses integer frame numbers, and the frame
+ * step is also an integer, so we always render on the frame. */
+ int frame_nr = round_fl_to_int(bezt->vec[1][0]);
+
+ /* (frame_nr < frame_start) cannot happen because of the binary search above. */
+ BLI_assert(frame_nr >= frame_start);
+ if (frame_nr > frame_end) {
+ break;
+ }
+ BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
+ }
+ }
+}
+
+/**
+ * Collect the frame numbers for which selected objects have keys in the animation data.
+ * The frames ares stored in #OGLRender.render_frames.
+ */
+static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
+{
+ Scene *scene = CTX_data_scene(C);
+ int frame_start = PSFRA;
+ int frame_end = PEFRA;
+
+ /* Will be freed in screen_opengl_render_end(). */
+ oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
+ "OGLRender::render_frames");
+
+ /* The first frame should always be rendered, otherwise there is nothing to write to file. */
+ BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob->adt != NULL) {
+ gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, ob->adt);
+ }
+
+ AnimData *adt = BKE_animdata_from_id(ob->data);
+ if (adt != NULL) {
+ gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, adt);
+ }
+ }
+ CTX_DATA_END;
+}
+
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
{
/* new render clears all callbacks */
@@ -532,6 +606,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
int sizex, sizey;
bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
+ const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
@@ -665,6 +740,10 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->movie_ctx_arr = NULL;
if (is_animation) {
+ if (is_render_keyed_only) {
+ gather_frames_to_render(C, oglrender);
+ }
+
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
task_scheduler = BLI_task_scheduler_create(1);
@@ -731,6 +810,8 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
#endif
+ MEM_SAFE_FREE(oglrender->render_frames);
+
if (oglrender->mh) {
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
for (i = 0; i < oglrender->totvideos; i++) {
@@ -995,8 +1076,11 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
}
- /* render into offscreen buffer */
- screen_opengl_render_apply(C, oglrender);
+ if (oglrender->render_frames == NULL ||
+ BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
+ /* render into offscreen buffer */
+ screen_opengl_render_apply(C, oglrender);
+ }
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
@@ -1124,6 +1208,23 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static char *screen_opengl_render_description(struct bContext *UNUSED(C),
+ struct wmOperatorType *UNUSED(ot),
+ struct PointerRNA *ptr)
+{
+ if (!RNA_boolean_get(ptr, "animation")) {
+ return NULL;
+ }
+
+ if (RNA_boolean_get(ptr, "render_keyed_only")) {
+ return BLI_strdup(
+ "Render the viewport for the animation range of this scene, but only render keyframes of "
+ "selected objects");
+ }
+
+ return BLI_strdup("Render the viewport for the animation range of this scene");
+}
+
void RENDER_OT_opengl(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1134,6 +1235,7 @@ void RENDER_OT_opengl(wmOperatorType *ot)
ot->idname = "RENDER_OT_opengl";
/* api callbacks */
+ ot->get_description = screen_opengl_render_description;
ot->invoke = screen_opengl_render_invoke;
ot->exec = screen_opengl_render_exec; /* blocking */
ot->modal = screen_opengl_render_modal;
@@ -1147,6 +1249,15 @@ void RENDER_OT_opengl(wmOperatorType *ot)
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna,
+ "render_keyed_only",
+ 0,
+ "Render Keyframes Only",
+ "Render only those frames where selected objects have a key in their "
+ "animation data. Only used when rendering animation");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_boolean(
ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e3070903ccc..98bee156090 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1595,6 +1595,8 @@ static void ed_default_handlers(
}
}
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) {
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 5b8fd33a4e9..501c36286d0 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1389,13 +1389,13 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
ScrArea *ctx_sa = CTX_wm_area(C);
- if (ctx_sa->full) {
+ if (ctx_sa != NULL && ctx_sa->full) {
sa = ctx_sa;
ED_area_newspace(C, ctx_sa, space_type, true);
sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
- else if (ctx_sa->spacetype == space_type) {
+ else if (ctx_sa != NULL && ctx_sa->spacetype == space_type) {
sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
}
else {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 9975c49dc54..7c47f7439ab 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -4229,19 +4229,6 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
* Animation Step.
* \{ */
-static int match_area_with_refresh(int spacetype, int refresh)
-{
- switch (spacetype) {
- case SPACE_TIME:
- if (refresh & SPACE_TIME) {
- return 1;
- }
- break;
- }
-
- return 0;
-}
-
static int match_region_with_redraws(int spacetype,
int regiontype,
int redraws,
@@ -4524,10 +4511,6 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
}
}
-
- if (match_area_with_refresh(sa->spacetype, sad->refresh)) {
- ED_area_tag_refresh(sa);
- }
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 06d79b8a49d..7f71110b360 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1560,9 +1560,9 @@ static void paint_2d_canvas_free(ImagePaintState *s)
}
}
-static void paint_2d_transform_mouse(ImagePaintState *s, const float in[2], float out[2])
+static void paint_2d_transform_mouse(View2D *v2d, const float in[2], float out[2])
{
- UI_view2d_region_to_view(s->v2d, in[0], in[1], &out[0], &out[1]);
+ UI_view2d_region_to_view(v2d, in[0], in[1], &out[0], &out[1]);
}
static bool is_inside_tile(const int size[2], const float pos[2], const float brush[2])
@@ -1656,8 +1656,9 @@ void paint_2d_stroke(void *ps,
brush_painter_2d_refresh_cache(s, painter, tile, new_coord, mval, pressure, distance, size);
- if (paint_2d_op(s, tile, old_coord, new_coord))
+ if (paint_2d_op(s, tile, old_coord, new_coord)) {
tile->need_redraw = true;
+ }
}
painter->firsttouch = 0;
@@ -1899,14 +1900,24 @@ void paint_2d_bucket_fill(const bContext *C,
return;
}
+ View2D *v2d = s ? s->v2d : &CTX_wm_region(C)->v2d;
float uv_origin[2];
float image_init[2];
- paint_2d_transform_mouse(s, mouse_init, image_init);
+ paint_2d_transform_mouse(v2d, mouse_init, image_init);
int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
- ImageUser *iuser = paint_2d_get_tile_iuser(s, tile_number);
- if (!iuser) {
- return;
+
+ ImageUser local_iuser, *iuser;
+ if (s != NULL) {
+ iuser = paint_2d_get_tile_iuser(s, tile_number);
+ if (iuser == NULL) {
+ return;
+ }
+ }
+ else {
+ iuser = &local_iuser;
+ BKE_imageuser_default(iuser);
+ iuser->tile = tile_number;
}
ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
@@ -2125,8 +2136,8 @@ void paint_2d_gradient_fill(
return;
}
- paint_2d_transform_mouse(s, mouse_final, image_final);
- paint_2d_transform_mouse(s, mouse_init, image_init);
+ paint_2d_transform_mouse(s->v2d, mouse_final, image_final);
+ paint_2d_transform_mouse(s->v2d, mouse_init, image_init);
sub_v2_v2(image_init, uv_origin);
sub_v2_v2(image_final, uv_origin);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 6a67c469955..d649f5017eb 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -748,11 +748,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
iuser.tile = tile_number;
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
if (ibuf == NULL) {
- iuser.tile = 0;
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL) {
- return 0;
- }
+ return false;
}
if (interp) {
@@ -3554,16 +3550,7 @@ static void project_bucket_init(const ProjPaintState *ps,
break;
}
}
- if (ibuf == NULL) {
- /* Failed to find the specific tile, fall back to the primary tile. */
- for (image_index = 0; image_index < ps->image_tot; image_index++) {
- ProjPaintImage *projIma = &ps->projImages[image_index];
- if ((projIma->ima == tpage) && (projIma->iuser.tile == 0)) {
- ibuf = projIma->ibuf;
- break;
- }
- }
- }
+ BLI_assert(ibuf != NULL);
}
/* context switching done */
@@ -4454,11 +4441,19 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
}
if (image_index == ps->image_tot) {
- PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
- e->ima = tpage;
- e->tile = tile;
- BLI_addtail(&used_images, e);
- ps->image_tot++;
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile;
+ if (BKE_image_has_ibuf(tpage, &iuser)) {
+ PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
+ e->ima = tpage;
+ e->tile = tile;
+ BLI_addtail(&used_images, e);
+ ps->image_tot++;
+ }
+ else {
+ image_index = -1;
+ }
}
tpage_last = tpage;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 536d93cac29..cafdd72c7cd 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -2339,7 +2339,9 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->true_location);
+ float loc_world[3];
+ mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
+ paint_last_stroke_update(scene, loc_world);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -3314,7 +3316,9 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->true_location);
+ float loc_world[3];
+ mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location);
+ paint_last_stroke_update(scene, loc_world);
ED_region_tag_redraw(vc->ar);
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index fdf96917b56..fb095a57835 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -813,7 +813,6 @@ const char *buttons_context_dir[] = {
"cloth",
"soft_body",
"fluid",
- "smoke",
"collision",
"brush",
"dynamic_paint",
@@ -1061,24 +1060,14 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
return 1;
}
}
- else if (CTX_data_equals(member, "fluid")) {
- PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
- if (ptr && ptr->data) {
- Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
- CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
- return 1;
- }
- }
-
- else if (CTX_data_equals(member, "smoke")) {
+ else if (CTX_data_equals(member, "fluid")) {
PointerRNA *ptr = get_pointer_type(path, &RNA_Object);
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
- CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ CTX_data_pointer_set(result, &ob->id, &RNA_FluidModifier, md);
return 1;
}
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 1ea7d81f9da..a567aeed826 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1001,6 +1001,9 @@ static int filelist_geticon_ex(const int typeflag,
else if (typeflag & FILE_TYPE_ALEMBIC) {
return ICON_FILE_3D;
}
+ else if (typeflag & FILE_TYPE_USD) {
+ return ICON_FILE_3D;
+ }
else if (typeflag & FILE_TYPE_OBJECT_IO) {
return ICON_FILE_3D;
}
@@ -2130,6 +2133,9 @@ int ED_path_extension_type(const char *path)
else if (BLI_path_extension_check(path, ".abc")) {
return FILE_TYPE_ALEMBIC;
}
+ else if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", NULL)) {
+ return FILE_TYPE_USD;
+ }
else if (BLI_path_extension_check(path, ".zip")) {
return FILE_TYPE_ARCHIVE;
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 99e4fc62980..02fb98aa7d7 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -215,6 +215,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
/* Protection against pyscripts not setting proper size limit... */
char *tmp = RNA_property_string_get_alloc(
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 4d2772aabee..03df93e4c8a 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1409,6 +1409,8 @@ static void decimate_exit(bContext *C, wmOperator *op)
if (dgo == NULL) {
return;
}
+
+ ScrArea *sa = dgo->sa;
LinkData *link;
for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
@@ -1422,7 +1424,7 @@ static void decimate_exit(bContext *C, wmOperator *op)
/* Return to normal cursor and header status. */
WM_cursor_modal_restore(win);
- ED_area_status_text(dgo->sa, NULL);
+ ED_area_status_text(sa, NULL);
/* cleanup */
op->customdata = NULL;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 9a633427d82..3f563fe9033 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -549,12 +549,15 @@ static void draw_udim_label(ARegion *ar, float fx, float fy, const char *label)
int textwidth = BLF_width(blf_mono_font, label, strlen(label)) + 10;
float stepx = BLI_rcti_size_x(&ar->v2d.mask) / BLI_rctf_size_x(&ar->v2d.cur);
float opacity;
- if (textwidth < 0.5f * (stepx - 10))
+ if (textwidth < 0.5f * (stepx - 10)) {
opacity = 1.0f;
- else if (textwidth < (stepx - 10))
+ }
+ else if (textwidth < (stepx - 10)) {
opacity = 2.0f - 2.0f * (textwidth / (stepx - 10));
- else
+ }
+ else {
opacity = 0.0f;
+ }
BLF_color4ub(blf_mono_font, 220, 220, 220, 150 * opacity);
BLF_position(blf_mono_font, (int)(x + 10), (int)(y + 10), 0);
BLF_draw_ascii(blf_mono_font, label, strlen(label));
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 4404f904891..9b091979f1e 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1267,49 +1267,61 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
-static int image_get_udim(const char *filepath, LinkNodePair *udim_tiles)
+/* Checks whether the given filepath refers to a UDIM texture.
+ * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
+ *
+ * If the result is positive, the filepath will be overwritten with that of
+ * the 1001 tile.
+ * udim_tiles may get filled even if the result ultimately is false! */
+static int image_get_udim(char *filepath, LinkNodePair *udim_tiles)
{
char filename[FILE_MAX], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
- if (strstr(filename, "1001") == NULL) {
+ unsigned short digits;
+ char base_head[FILE_MAX], base_tail[FILE_MAX];
+ int id = BLI_stringdec(filename, base_head, base_tail, &digits);
+
+ if (id < 1001 || id >= IMA_UDIM_MAX) {
return 0;
}
bool is_udim = true;
+ bool has_primary = false;
int max_udim = 0;
- unsigned short digits;
- char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_stringdec(filename, base_head, base_tail, &digits);
- if (id == 1001) {
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
- continue;
- }
- char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_stringdec(dir[i].relname, head, tail, &digits);
-
- if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
- !(STREQLEN(base_tail, tail, FILE_MAX))) {
- continue;
- }
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+ char head[FILE_MAX], tail[FILE_MAX];
+ id = BLI_stringdec(dir[i].relname, head, tail, &digits);
- if (id < 1001 || id >= 2000) {
- is_udim = false;
- break;
- }
+ if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
+ !(STREQLEN(base_tail, tail, FILE_MAX))) {
+ continue;
+ }
- BLI_linklist_append(udim_tiles, POINTER_FROM_INT(id));
- max_udim = max_ii(max_udim, id);
+ if (id < 1001 || id >= IMA_UDIM_MAX) {
+ is_udim = false;
+ break;
+ }
+ if (id == 1001) {
+ has_primary = true;
}
- BLI_filelist_free(dir, totfile);
+ BLI_linklist_append(udim_tiles, POINTER_FROM_INT(id));
+ max_udim = max_ii(max_udim, id);
}
+ BLI_filelist_free(dir, totfile);
- return is_udim ? (max_udim - 1001) : 0;
+ if (is_udim && has_primary) {
+ BLI_stringenc_path(filepath, dirname, base_head, base_tail, digits, 1001);
+ return max_udim - 1000;
+ }
+ return 0;
}
/**
@@ -1320,27 +1332,34 @@ static int image_get_udim(const char *filepath, LinkNodePair *udim_tiles)
* \param ofs: [out] offset the first frame number in the sequence.
* \return the number of contiguous frames in the sequence
*/
-static int image_sequence_get_len(ImageFrameRange *frame_range, int *ofs, LinkNodePair *udim_tiles)
+static int image_sequence_get_len(ImageFrameRange *frame_range,
+ int *ofs,
+ char *filepath_range,
+ LinkNodePair *udim_tiles)
{
ImageFrame *frame;
BLI_listbase_sort(&frame_range->frames, image_cmp_frame);
+ BLI_strncpy(filepath_range, frame_range->filepath, FILE_MAX);
frame = frame_range->frames.first;
if (frame != NULL) {
int frame_curr = frame->framenr;
(*ofs) = frame_curr;
- if (udim_tiles != NULL && (frame_curr == 1001)) {
- return 1 + image_get_udim(frame_range->filepath, udim_tiles);
- }
- else {
- while (frame != NULL && (frame->framenr == frame_curr)) {
- frame_curr++;
- frame = frame->next;
+ if (udim_tiles != NULL) {
+ int len_udim = image_get_udim(filepath_range, udim_tiles);
+ if (len_udim > 0) {
+ *ofs = 1001;
+ return len_udim;
}
- return frame_curr - (*ofs);
}
+
+ while (frame != NULL && (frame->framenr == frame_curr)) {
+ frame_curr++;
+ frame = frame->next;
+ }
+ return frame_curr - (*ofs);
}
*ofs = 0;
return 0;
@@ -1422,7 +1441,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
char filepath[FILE_MAX];
int frame_seq_len = 0;
int frame_ofs = 1;
- LinkNodePair udim_tiles = {NULL};
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
@@ -1445,13 +1463,13 @@ static int image_open_exec(bContext *C, wmOperator *op)
frame_range = frame_range->next) {
int frame_range_ofs;
+ LinkNodePair udim_tiles = {NULL};
LinkNodePair *udim_tiles_ptr = use_udim ? (&udim_tiles) : NULL;
- int frame_range_seq_len = image_sequence_get_len(
- frame_range, &frame_range_ofs, udim_tiles_ptr);
- BLI_freelistN(&frame_range->frames);
char filepath_range[FILE_MAX];
- BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
+ int frame_range_seq_len = image_sequence_get_len(
+ frame_range, &frame_range_ofs, filepath_range, udim_tiles_ptr);
+ BLI_freelistN(&frame_range->frames);
if (was_relative) {
BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
@@ -1473,35 +1491,42 @@ static int image_open_exec(bContext *C, wmOperator *op)
frame_seq_len = frame_range_seq_len;
frame_ofs = frame_range_ofs;
}
+
+ BLI_linklist_free(udim_tiles.list, NULL);
}
BLI_freelistN(&frame_ranges_all);
}
else {
/* for drag & drop etc. */
+
+ LinkNodePair udim_tiles = {NULL};
frame_seq_len = 1;
+ char filepath_range[FILE_MAX];
+ BLI_strncpy(filepath_range, filepath, FILE_MAX);
- if (use_udim) {
+ if (use_udim > 0) {
/* Try to find UDIM tiles corresponding to the image */
- frame_seq_len = 1 + image_get_udim(filepath, &udim_tiles);
+ int udim_len = image_get_udim(filepath_range, &udim_tiles);
/* If we found something, mark the image as tiled. */
- if (frame_seq_len > 1) {
+ if (udim_len) {
+ frame_seq_len = udim_len;
frame_ofs = 1001;
}
}
ima = image_open_single(bmain,
op,
- filepath,
+ filepath_range,
BKE_main_blendfile_path(bmain),
is_relative_path,
use_multiview,
frame_seq_len,
frame_ofs,
&udim_tiles);
- }
- BLI_linklist_free(udim_tiles.list, NULL);
+ BLI_linklist_free(udim_tiles.list, NULL);
+ }
if (ima == NULL) {
return OPERATOR_CANCELLED;
@@ -4212,32 +4237,108 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* ********************* Add tile operator ****************** */
-static bool tile_poll(bContext *C)
+static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
+{
+ float color[4];
+ RNA_float_get_array(ptr, "color", color);
+ int gen_type = RNA_enum_get(ptr, "generated_type");
+ int width = RNA_int_get(ptr, "width");
+ int height = RNA_int_get(ptr, "height");
+ bool is_float = RNA_boolean_get(ptr, "float");
+ int planes = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
+
+ return BKE_image_fill_tile(ima, tile, width, height, color, gen_type, planes, is_float);
+}
+
+static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
+{
+ uiLayout *split, *col[2];
+
+ split = uiLayoutSplit(layout, 0.5f, false);
+ col[0] = uiLayoutColumn(split, false);
+ col[1] = uiLayoutColumn(split, false);
+
+ uiItemL(col[0], IFACE_("Color"), ICON_NONE);
+ uiItemR(col[1], ptr, "color", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Width"), ICON_NONE);
+ uiItemR(col[1], ptr, "width", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Height"), ICON_NONE);
+ uiItemR(col[1], ptr, "height", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], ptr, "alpha", 0, NULL, ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
+ uiItemR(col[1], ptr, "generated_type", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], ptr, "float", 0, NULL, ICON_NONE);
+}
+
+static void def_fill_tile(StructOrFunctionRNA *srna)
+{
+ PropertyRNA *prop;
+ static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ prop = RNA_def_float_color(
+ srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
+ RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
+ RNA_def_property_float_array_default(prop, default_color);
+ RNA_def_enum(srna,
+ "generated_type",
+ rna_enum_image_generated_type_items,
+ IMA_GENTYPE_BLANK,
+ "Generated Type",
+ "Fill the image with a grid for UV map testing");
+ prop = RNA_def_int(srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_int(srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+
+ /* Only needed when filling the first tile. */
+ RNA_def_boolean(
+ srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
+ RNA_def_boolean(srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
+}
+
+static bool tile_add_poll(bContext *C)
{
Image *ima = CTX_data_edit_image(C);
- return (ima != NULL && ima->source == IMA_SRC_TILED);
+ return (ima != NULL && ima->source == IMA_SRC_TILED && BKE_image_has_ibuf(ima, NULL));
}
static int tile_add_exec(bContext *C, wmOperator *op)
{
Image *ima = CTX_data_edit_image(C);
- int tile_number = RNA_int_get(op->ptr, "number");
-
+ int start_tile = RNA_int_get(op->ptr, "number");
+ int end_tile = min_ii(start_tile + RNA_int_get(op->ptr, "count"), IMA_UDIM_MAX);
+ bool fill_tile = RNA_boolean_get(op->ptr, "fill");
char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0);
- ImageTile *tile = BKE_image_add_tile(ima, tile_number, label);
+ bool created_tile = false;
+ for (int tile_number = start_tile; tile_number < end_tile; tile_number++) {
+ ImageTile *tile = BKE_image_add_tile(ima, tile_number, label);
+
+ if (tile != NULL) {
+ ima->active_tile_index = BLI_findindex(&ima->tiles, tile);
+
+ if (fill_tile) {
+ do_fill_tile(op->ptr, ima, tile);
+ }
+
+ created_tile = true;
+ }
+ }
MEM_freeN(label);
- if (tile == NULL) {
+ if (!created_tile) {
return OPERATOR_CANCELLED;
}
- ima->active_tile_index = BLI_findindex(&ima->tiles, tile);
-
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
-
return OPERATOR_FINISHED;
}
@@ -4256,9 +4357,10 @@ static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev
}
RNA_int_set(op->ptr, "number", next_number);
+ RNA_int_set(op->ptr, "count", 1);
RNA_string_set(op->ptr, "label", "");
- return WM_operator_props_dialog_popup(C, op, 5 * UI_UNIT_X, 5 * UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
static void tile_add_draw(bContext *UNUSED(C), wmOperator *op)
@@ -4276,8 +4378,17 @@ static void tile_add_draw(bContext *UNUSED(C), wmOperator *op)
uiItemL(col[0], IFACE_("Number"), ICON_NONE);
uiItemR(col[1], &ptr, "number", 0, "", ICON_NONE);
+ uiItemL(col[0], IFACE_("Count"), ICON_NONE);
+ uiItemR(col[1], &ptr, "count", 0, "", ICON_NONE);
+
uiItemL(col[0], IFACE_("Label"), ICON_NONE);
uiItemR(col[1], &ptr, "label", 0, "", ICON_NONE);
+
+ uiItemR(layout, &ptr, "fill", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(&ptr, "fill")) {
+ draw_fill_tile(&ptr, layout);
+ }
}
void IMAGE_OT_tile_add(wmOperatorType *ot)
@@ -4288,7 +4399,7 @@ void IMAGE_OT_tile_add(wmOperatorType *ot)
ot->idname = "IMAGE_OT_tile_add";
/* api callbacks */
- ot->poll = tile_poll;
+ ot->poll = tile_add_poll;
ot->exec = tile_add_exec;
ot->invoke = tile_add_invoke;
ot->ui = tile_add_draw;
@@ -4298,7 +4409,10 @@ void IMAGE_OT_tile_add(wmOperatorType *ot)
RNA_def_int(
ot->srna, "number", 1002, 1001, INT_MAX, "Number", "UDIM number of the tile", 1001, 1099);
+ RNA_def_int(ot->srna, "count", 1, 1, INT_MAX, "Count", "How many tiles to add", 1, 1000);
RNA_def_string(ot->srna, "label", NULL, 0, "Label", "Optional tile label");
+ RNA_def_boolean(ot->srna, "fill", true, "Fill", "Fill new tile with a generated image");
+ def_fill_tile(ot->srna);
}
/* ********************* Remove tile operator ****************** */
@@ -4344,20 +4458,23 @@ void IMAGE_OT_tile_remove(wmOperatorType *ot)
/* ********************* Fill tile operator ****************** */
-static int tile_fill_exec(bContext *C, wmOperator *op)
+static bool tile_fill_poll(bContext *C)
{
Image *ima = CTX_data_edit_image(C);
- float color[4];
- RNA_float_get_array(op->ptr, "color", color);
- int gen_type = RNA_enum_get(op->ptr, "generated_type");
- int width = RNA_int_get(op->ptr, "width");
- int height = RNA_int_get(op->ptr, "height");
- bool is_float = RNA_boolean_get(op->ptr, "float");
- int planes = RNA_boolean_get(op->ptr, "alpha") ? 32 : 24;
+ if (ima != NULL && ima->source == IMA_SRC_TILED) {
+ /* Filling secondary tiles is only allowed if the primary tile exists. */
+ return (ima->active_tile_index == 0) || BKE_image_has_ibuf(ima, NULL);
+ }
+ return false;
+}
+
+static int tile_fill_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = CTX_data_edit_image(C);
ImageTile *tile = BLI_findlink(&ima->tiles, ima->active_tile_index);
- if (!BKE_image_fill_tile(ima, tile, width, height, color, gen_type, planes, is_float)) {
+ if (!do_fill_tile(op->ptr, ima, tile)) {
return OPERATOR_CANCELLED;
}
@@ -4385,46 +4502,21 @@ static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
static void tile_fill_draw(bContext *UNUSED(C), wmOperator *op)
{
- uiLayout *split, *col[2];
- uiLayout *layout = op->layout;
PointerRNA ptr;
-
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
- /* copy of WM_operator_props_dialog_popup() layout */
-
- split = uiLayoutSplit(layout, 0.5f, false);
- col[0] = uiLayoutColumn(split, false);
- col[1] = uiLayoutColumn(split, false);
-
- uiItemL(col[0], IFACE_("Color"), ICON_NONE);
- uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
-
- uiItemL(col[0], IFACE_("Width"), ICON_NONE);
- uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
-
- uiItemL(col[0], IFACE_("Height"), ICON_NONE);
- uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
-
- uiItemL(col[0], "", ICON_NONE);
- uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
-
- uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
- uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
-
- uiItemL(col[0], "", ICON_NONE);
- uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
+ draw_fill_tile(&ptr, op->layout);
}
void IMAGE_OT_tile_fill(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Fill tile";
+ ot->name = "Fill Tile";
ot->description = "Fill the current tile with a generated image";
ot->idname = "IMAGE_OT_tile_fill";
/* api callbacks */
- ot->poll = tile_poll;
+ ot->poll = tile_fill_poll;
ot->exec = tile_fill_exec;
ot->invoke = tile_fill_invoke;
ot->ui = tile_fill_draw;
@@ -4432,25 +4524,5 @@ void IMAGE_OT_tile_fill(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- PropertyRNA *prop;
- static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- prop = RNA_def_float_color(
- ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
- RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
- RNA_def_property_float_array_default(prop, default_color);
- RNA_def_enum(ot->srna,
- "generated_type",
- rna_enum_image_generated_type_items,
- IMA_GENTYPE_BLANK,
- "Generated Type",
- "Fill the image with a grid for UV map testing");
- prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
- RNA_def_property_subtype(prop, PROP_PIXEL);
- prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
- RNA_def_property_subtype(prop, PROP_PIXEL);
-
- /* Only needed when filling the first tile. */
- RNA_def_boolean(
- ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
- RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
+ def_fill_tile(ot->srna);
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index f30c0e97cab..2f93be8ae38 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -464,14 +464,71 @@ static void IMAGE_GGT_gizmo2d(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo";
gzgt->idname = "IMAGE_GGT_gizmo2d";
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_xform_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_xform_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_xform_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_xform_draw_prepare;
+}
+
+static void IMAGE_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Translate Gizmo";
+ gzgt->idname = "IMAGE_GGT_gizmo2d_translate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_xform_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_xform_setup_no_cage;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_xform_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_xform_draw_prepare;
+}
+
+static void IMAGE_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Transform Gizmo Resize";
+ gzgt->idname = "IMAGE_GGT_gizmo2d_resize";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_resize_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_resize_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_resize_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_resize_draw_prepare;
+}
+
+static void IMAGE_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Transform Gizmo Resize";
+ gzgt->idname = "IMAGE_GGT_gizmo2d_rotate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
- gzgt->poll = ED_widgetgroup_gizmo2d_poll;
- gzgt->setup = ED_widgetgroup_gizmo2d_setup;
+ gzgt->poll = ED_widgetgroup_gizmo2d_rotate_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_rotate_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
- gzgt->refresh = ED_widgetgroup_gizmo2d_refresh;
- gzgt->draw_prepare = ED_widgetgroup_gizmo2d_draw_prepare;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_rotate_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_rotate_draw_prepare;
}
static void IMAGE_GGT_navigate(wmGizmoGroupType *gzgt)
@@ -485,6 +542,9 @@ static void image_widgets(void)
&(const struct wmGizmoMapType_Params){SPACE_IMAGE, RGN_TYPE_WINDOW});
WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d);
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d_translate);
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d_resize);
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d_rotate);
WM_gizmogrouptype_append_and_link(gzmap_type, IMAGE_GGT_navigate);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 486be952b2f..2c2989a284d 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2125,14 +2125,14 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_Surface:
data.icon = ICON_MOD_PHYSICS;
break;
- case eModifierType_Fluidsim:
+ case eModifierType_Fluidsim: /* deprecated, old fluid modifier */
data.icon = ICON_MOD_FLUIDSIM;
break;
case eModifierType_Multires:
data.icon = ICON_MOD_MULTIRES;
break;
- case eModifierType_Smoke:
- data.icon = ICON_MOD_SMOKE;
+ case eModifierType_Fluid:
+ data.icon = ICON_MOD_FLUID;
break;
case eModifierType_Solidify:
data.icon = ICON_MOD_SOLIDIFY;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 34bbf3a2a30..7b59b056264 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -1311,6 +1311,10 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
outliner_show_active(so, ar, te, id);
}
+ /* Also open back from the active_element (only done for the first found occurrence of ID
+ * though). */
+ outliner_show_active(so, ar, active_element, id);
+
/* Center view on first element found */
int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
int ytop = (active_element->ys + (size_y / 2));
@@ -2173,9 +2177,15 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
- if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
- SpaceOutliner *so = CTX_wm_space_outliner(C);
- return (so->outlinevis == SO_ID_ORPHANS);
+ if (sa != NULL) {
+ if (sa->spacetype == SPACE_TOPBAR) {
+ return true;
+ }
+
+ if (sa->spacetype == SPACE_OUTLINER) {
+ SpaceOutliner *so = CTX_wm_space_outliner(C);
+ return (so->outlinevis == SO_ID_ORPHANS);
+ }
}
return 0;
}
@@ -2242,6 +2252,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ ScrArea *sa = CTX_wm_area(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int num_tagged[INDEX_ID_MAX] = {0};
@@ -2268,7 +2279,9 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- outliner_cleanup_tree(soops);
+ if ((sa != NULL) && (sa->spacetype == SPACE_OUTLINER)) {
+ outliner_cleanup_tree(soops);
+ }
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index a42ab048907..731c8a3028e 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -35,6 +35,9 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -119,9 +122,27 @@ static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar)
ED_region_panels_init(wm, ar);
}
-static void userpref_main_region_draw(const bContext *C, ARegion *ar)
+static void userpref_main_region_layout(const bContext *C, ARegion *ar)
{
- ED_region_panels_ex(C, ar, NULL, U.space_data.section_active, true);
+ char id_lower[64];
+ const char *contexts[2] = {id_lower, NULL};
+
+ /* Avoid duplicating identifiers, use existing RNA enum. */
+ {
+ const EnumPropertyItem *items = rna_enum_preference_section_items;
+ int i = RNA_enum_from_value(items, U.space_data.section_active);
+ /* File is from the future. */
+ if (i == -1) {
+ i = 0;
+ }
+ const char *id = items[i].identifier;
+ BLI_assert(strlen(id) < sizeof(id_lower));
+ STRNCPY(id_lower, id);
+ BLI_str_tolower_ascii(id_lower, strlen(id_lower));
+ }
+
+ ED_region_panels_layout_ex(
+ C, ar, &ar->type->paneltypes, contexts, U.space_data.section_active, true, NULL);
}
static void userpref_operatortypes(void)
@@ -225,7 +246,8 @@ void ED_spacetype_userpref(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");
art->regionid = RGN_TYPE_WINDOW;
art->init = userpref_main_region_init;
- art->draw = userpref_main_region_draw;
+ art->layout = userpref_main_region_layout;
+ art->draw = ED_region_panels_draw;
art->listener = userpref_main_region_listener;
art->keymapflag = ED_KEYMAP_UI;
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 4542845f90c..193be7567bc 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -32,7 +32,7 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
- ../../../../intern/smoke/extern
+ ../../../../intern/mantaflow/extern
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
@@ -99,8 +99,8 @@ if(WITH_LANPR)
add_definitions(-DWITH_LANPR)
endif()
-if(WITH_MOD_SMOKE)
- add_definitions(-DWITH_SMOKE)
+if(WITH_MOD_FLUID)
+ add_definitions(-DWITH_FLUID)
endif()
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
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 d6d3a3dc563..504b10888e8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -466,7 +466,7 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
{
float point_local[2] = {UNPACK2(mval)};
sub_v2_v2(point_local, gz->matrix_basis[3]);
- mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC));
+ mul_v2_fl(point_local, 1.0f / gz->scale_final);
const float len_sq = len_squared_v2(point_local);
if (len_sq > 1.0) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
index 848accb8534..8cd5ed7a478 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
@@ -70,19 +70,17 @@ static bool WIDGETGROUP_tool_generic_poll(const bContext *C, wmGizmoGroupType *g
static wmGizmo *tool_generic_create_gizmo(const bContext *C, wmGizmoGroup *gzgroup)
{
- wmGizmo *gz;
+ wmGizmo *gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL);
+ gz->flag |= WM_GIZMO_OPERATOR_TOOL_INIT;
- if (gzgroup->type->idname == handle_normal_id) {
- gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL);
-
- UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
- UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
- unit_m4(gz->matrix_offset);
+ unit_m4(gz->matrix_offset);
- PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
- RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+ RNA_enum_set(gz->ptr, "icon", ICON_NONE);
+ if (gzgroup->type->idname == handle_normal_id) {
gz->scale_basis = 0.12f;
gz->matrix_offset[3][2] -= 12.0;
RNA_enum_set(gz->ptr,
@@ -91,17 +89,8 @@ static wmGizmo *tool_generic_create_gizmo(const bContext *C, wmGizmoGroup *gzgro
ED_GIZMO_BUTTON_SHOW_OUTLINE));
}
else {
- gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL);
-
- UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
- UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
-
- unit_m4(gz->matrix_offset);
gz->scale_basis = 0.16f * 3;
- PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
- RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
-
RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
/* Make the center low alpha. */
@@ -206,7 +195,8 @@ void VIEW3D_GGT_tool_generic_handle_normal(wmGizmoGroupType *gzgt)
gzgt->name = "Generic Tool Widget Normal";
gzgt->idname = handle_normal_id;
- gzgt->flag |= (WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP);
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -222,6 +212,8 @@ void VIEW3D_GGT_tool_generic_handle_free(wmGizmoGroupType *gzgt)
gzgt->name = "Generic Tool Widget Free";
gzgt->idname = handle_free_id;
+ /* Don't use 'WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK' here since this style of gizmo
+ * is better suited to being activated immediately. */
gzgt->flag |= (WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP);
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 5853574dced..6f39a8c3b9c 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
transform_convert_sculpt.c
transform_convert_sequencer.c
transform_convert_tracking.c
+ transform_draw_cursors.c
transform_generics.c
transform_gizmo_2d.c
transform_gizmo_3d.c
@@ -71,6 +72,7 @@ set(SRC
transform.h
transform_convert.h
+ transform_draw_cursors.h
transform_snap.h
)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 42adf1ee456..7112444655b 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -95,6 +95,7 @@
#include "transform.h"
#include "transform_convert.h"
+#include "transform_draw_cursors.h"
#include "transform_snap.h"
/* Disabling, since when you type you know what you are doing,
@@ -1684,285 +1685,6 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
return success;
}
-typedef enum {
- UP,
- DOWN,
- LEFT,
- RIGHT,
-} ArrowDirection;
-
-#define POS_INDEX 0
-/* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
- * private to this file - merwin
- */
-
-static void drawArrow(ArrowDirection d, short offset, short length, short size)
-{
- immBegin(GPU_PRIM_LINES, 6);
-
- switch (d) {
- case LEFT:
- offset = -offset;
- length = -length;
- size = -size;
- ATTR_FALLTHROUGH;
- case RIGHT:
- immVertex2f(POS_INDEX, offset, 0);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length - size, -size);
- immVertex2f(POS_INDEX, offset + length, 0);
- immVertex2f(POS_INDEX, offset + length - size, size);
- break;
-
- case DOWN:
- offset = -offset;
- length = -length;
- size = -size;
- ATTR_FALLTHROUGH;
- case UP:
- immVertex2f(POS_INDEX, 0, offset);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, -size, offset + length - size);
- immVertex2f(POS_INDEX, 0, offset + length);
- immVertex2f(POS_INDEX, size, offset + length - size);
- break;
- }
-
- immEnd();
-}
-
-static void drawArrowHead(ArrowDirection d, short size)
-{
- immBegin(GPU_PRIM_LINES, 4);
-
- switch (d) {
- case LEFT:
- size = -size;
- ATTR_FALLTHROUGH;
- case RIGHT:
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, -size);
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, size);
- break;
-
- case DOWN:
- size = -size;
- ATTR_FALLTHROUGH;
- case UP:
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, -size, -size);
- immVertex2f(POS_INDEX, 0, 0);
- immVertex2f(POS_INDEX, size, -size);
- break;
- }
-
- immEnd();
-}
-
-static void drawArc(float size, float angle_start, float angle_end, int segments)
-{
- float delta = (angle_end - angle_start) / segments;
- float angle;
- int a;
-
- immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
-
- for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
- immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
- }
- immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
-
- immEnd();
-}
-
-static bool helpline_poll(bContext *C)
-{
- ARegion *ar = CTX_wm_region(C);
-
- if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
- return 1;
- }
- return 0;
-}
-
-static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
-{
- TransInfo *t = (TransInfo *)customdata;
-
- if (t->helpline != HLP_NONE) {
- float cent[2];
- const float mval[3] = {
- x,
- y,
- 0.0f,
- };
- float tmval[2] = {
- (float)t->mval[0],
- (float)t->mval[1],
- };
-
- projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
- /* Offset the values for the area region. */
- const float offset[2] = {
- t->ar->winrct.xmin,
- t->ar->winrct.ymin,
- };
-
- for (int i = 0; i < 2; i++) {
- cent[i] += offset[i];
- tmval[i] += offset[i];
- }
-
- GPU_matrix_push();
-
- /* Dashed lines first. */
- if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
- BLI_assert(shdr_pos == POS_INDEX);
-
- GPU_line_width(1.0f);
-
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniformThemeColor(TH_VIEW_OVERLAY);
- immUniform1f("dash_width", 6.0f);
- immUniform1f("dash_factor", 0.5f);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2fv(POS_INDEX, cent);
- immVertex2f(POS_INDEX, tmval[0], tmval[1]);
- immEnd();
-
- immUnbindProgram();
- }
-
- /* And now, solid lines. */
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- UNUSED_VARS_NDEBUG(pos); /* silence warning */
- BLI_assert(pos == POS_INDEX);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- switch (t->helpline) {
- case HLP_SPRING:
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
- GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
-
- GPU_line_width(3.0f);
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
- break;
- case HLP_HARROW:
- immUniformThemeColor(TH_VIEW_OVERLAY);
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
- drawArrow(RIGHT, 5, 10, 5);
- drawArrow(LEFT, 5, 10, 5);
- break;
- case HLP_VARROW:
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
- break;
- case HLP_CARROW: {
- /* Draw arrow based on direction defined by custom-points. */
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
-
- const int *data = t->mouse.data;
- const float dx = data[2] - data[0], dy = data[3] - data[1];
- const float angle = -atan2f(dx, dy);
-
- GPU_matrix_push();
-
- GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
-
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
-
- GPU_matrix_pop();
- break;
- }
- case HLP_ANGLE: {
- float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
- float angle = atan2f(dy, dx);
- float dist = hypotf(dx, dy);
- float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
- float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
-
- immUniformThemeColor(TH_VIEW_OVERLAY);
-
- GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
-
- GPU_line_width(3.0f);
- drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
- drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
-
- GPU_matrix_push();
-
- GPU_matrix_translate_3f(
- cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
- GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
-
- drawArrowHead(DOWN, 5);
-
- GPU_matrix_pop();
-
- GPU_matrix_translate_3f(
- cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
- GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
-
- drawArrowHead(UP, 5);
- break;
- }
- case HLP_TRACKBALL: {
- unsigned char col[3], col2[3];
- UI_GetThemeColor3ubv(TH_GRID, col);
-
- GPU_matrix_translate_3fv(mval);
-
- GPU_line_width(3.0f);
-
- UI_make_axis_color(col, col2, 'X');
- immUniformColor3ubv(col2);
-
- drawArrow(RIGHT, 5, 10, 5);
- drawArrow(LEFT, 5, 10, 5);
-
- UI_make_axis_color(col, col2, 'Y');
- immUniformColor3ubv(col2);
-
- drawArrow(UP, 5, 10, 5);
- drawArrow(DOWN, 5, 10, 5);
- break;
- }
- }
-
- immUnbindProgram();
- GPU_matrix_pop();
- }
-}
-
static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *ar)
{
/* Don't show overlays when not the active view and when overlay is disabled: T57139 */
@@ -2380,38 +2102,62 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(
t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_IMAGE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_CLIP) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_NODE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_GRAPH) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
else if (t->spacetype == SPACE_ACTION) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ transform_draw_cursor_poll,
+ transform_draw_cursor_draw,
+ t);
}
createTransData(C, t); // make TransData structs from selection
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4b529765ab0..95506918d98 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -649,7 +649,7 @@ typedef struct TransInfo {
short index;
short *types[2];
/* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
- TransformOrientation *custom;
+ struct TransformOrientation *custom;
} orientation;
/** backup from view3d, to restore on end. */
short gizmo_flag;
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 331a3eea59f..16dfdd35c32 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -55,10 +55,8 @@ typedef struct TransDataObject {
* Object to object data transform table.
* Don't add these to transform data because we may want to include child objects
* which aren't being transformed.
- * - The key is object data #ID.
- * - The value is #XFormObjectData_Extra.
*/
- struct GHash *obdata_in_obmode_map;
+ struct XFormObjectData_Container *xds;
/**
* Transform
@@ -69,7 +67,6 @@ typedef struct TransDataObject {
} TransDataObject;
-static void trans_obdata_in_obmode_free_all(TransDataObject *tdo);
static void trans_obchild_in_obmode_free_all(TransDataObject *tdo);
static void freeTransObjectCustomData(TransInfo *t,
@@ -80,7 +77,7 @@ static void freeTransObjectCustomData(TransInfo *t,
custom_data->data = NULL;
if (t->options & CTX_OBMODE_XFORM_OBDATA) {
- trans_obdata_in_obmode_free_all(tdo);
+ ED_object_data_xform_container_destroy(tdo->xds);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
@@ -98,81 +95,18 @@ static void freeTransObjectCustomData(TransInfo *t,
* We need this to be detached from transform data because,
* unlike transforming regular objects, we need to transform the children.
*
+ * Nearly all of the logic here is in the 'ED_object_data_xform_container_*' API.
* \{ */
-struct XFormObjectData_Extra {
- Object *ob;
- float obmat_orig[4][4];
- struct XFormObjectData *xod;
-};
-
-static void trans_obdata_in_obmode_ensure_object(TransDataObject *tdo, Object *ob)
-{
- if (tdo->obdata_in_obmode_map == NULL) {
- tdo->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
- }
-
- void **xf_p;
- if (!BLI_ghash_ensure_p(tdo->obdata_in_obmode_map, ob->data, &xf_p)) {
- struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
- copy_m4_m4(xf->obmat_orig, ob->obmat);
- xf->ob = ob;
- /* Result may be NULL, that's OK. */
- xf->xod = ED_object_data_xform_create(ob->data);
- *xf_p = xf;
- }
-}
-
void trans_obdata_in_obmode_update_all(TransInfo *t)
{
TransDataObject *tdo = t->custom.type.data;
- if (tdo->obdata_in_obmode_map == NULL) {
+ if (tdo->xds == NULL) {
return;
}
struct Main *bmain = CTX_data_main(t->context);
- BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
-
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, tdo->obdata_in_obmode_map) {
- ID *id = BLI_ghashIterator_getKey(&gh_iter);
- struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
- if (xf->xod == NULL) {
- continue;
- }
-
- Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
- float imat[4][4], dmat[4][4];
- invert_m4_m4(imat, xf->obmat_orig);
- mul_m4_m4m4(dmat, imat, ob_eval->obmat);
- invert_m4(dmat);
-
- ED_object_data_xform_by_mat4(xf->xod, dmat);
- if (xf->ob->type == OB_ARMATURE) {
- /* TODO: none of the current flags properly update armatures, needs investigation. */
- DEG_id_tag_update(id, 0);
- }
- else {
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- }
- }
-}
-
-/** Callback for #GHash free. */
-static void trans_obdata_in_obmode_free_elem(void *xf_p)
-{
- struct XFormObjectData_Extra *xf = xf_p;
- if (xf->xod) {
- ED_object_data_xform_destroy(xf->xod);
- }
- MEM_freeN(xf);
-}
-
-static void trans_obdata_in_obmode_free_all(TransDataObject *tdo)
-{
- if (tdo->obdata_in_obmode_map != NULL) {
- BLI_ghash_free(tdo->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
- }
+ ED_object_data_xform_container_update_all(tdo->xds, bmain, t->depsgraph);
}
/** \} */
@@ -697,6 +631,10 @@ void createTransObject(bContext *C, TransInfo *t)
t->custom.type.data = tdo;
t->custom.type.free_cb = freeTransObjectCustomData;
+ if (t->options & CTX_OBMODE_XFORM_OBDATA) {
+ tdo->xds = ED_object_data_xform_container_create();
+ }
+
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
Object *ob = base->object;
@@ -729,7 +667,7 @@ void createTransObject(bContext *C, TransInfo *t)
if (t->options & CTX_OBMODE_XFORM_OBDATA) {
if ((td->flag & TD_SKIP) == 0) {
- trans_obdata_in_obmode_ensure_object(tdo, ob);
+ ED_object_data_xform_container_item_ensure(tdo->xds, ob);
}
}
@@ -797,7 +735,7 @@ void createTransObject(bContext *C, TransInfo *t)
ob_parent = ob_parent->parent;
}
if (parent_in_transdata) {
- trans_obdata_in_obmode_ensure_object(tdo, ob);
+ ED_object_data_xform_container_item_ensure(tdo->xds, ob);
}
}
}
diff --git a/source/blender/editors/transform/transform_draw.c b/source/blender/editors/transform/transform_draw.c
new file mode 100644
index 00000000000..e44442b7e49
--- /dev/null
+++ b/source/blender/editors/transform/transform_draw.c
@@ -0,0 +1,114 @@
+
+/* -------------------------------------------------------------------- */
+/** \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_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
new file mode 100644
index 00000000000..dc2ebdca56a
--- /dev/null
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -0,0 +1,344 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "BLI_math.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "BKE_context.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "transform.h"
+#include "transform_draw_cursors.h" /* Own include. */
+
+enum eArrowDirection {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+};
+
+struct ArrowDims {
+ int offset;
+ int length;
+ int size;
+};
+
+#define POS_INDEX 0
+/* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
+ * private to this file - merwin
+ */
+
+static void drawArrow(enum eArrowDirection dir, const struct ArrowDims *arrow_dims)
+{
+ int offset = arrow_dims->offset;
+ int length = arrow_dims->length;
+ int size = arrow_dims->size;
+
+ immBegin(GPU_PRIM_LINES, 6);
+
+ switch (dir) {
+ case LEFT:
+ offset = -offset;
+ length = -length;
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case RIGHT:
+ immVertex2f(POS_INDEX, offset, 0);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length - size, -size);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length - size, size);
+ break;
+
+ case DOWN:
+ offset = -offset;
+ length = -length;
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case UP:
+ immVertex2f(POS_INDEX, 0, offset);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, -size, offset + length - size);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, size, offset + length - size);
+ break;
+ }
+
+ immEnd();
+}
+
+static void drawArrowHead(enum eArrowDirection dir, int size)
+{
+ immBegin(GPU_PRIM_LINES, 4);
+
+ switch (dir) {
+ case LEFT:
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case RIGHT:
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, -size);
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, size);
+ break;
+
+ case DOWN:
+ size = -size;
+ ATTR_FALLTHROUGH;
+ case UP:
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, -size);
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, size, -size);
+ break;
+ }
+
+ immEnd();
+}
+
+static void drawArc(float angle_start, float angle_end, int segments, float size)
+{
+ float delta = (angle_end - angle_start) / segments;
+ float angle;
+ int a;
+
+ immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
+
+ for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
+ immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
+ }
+ immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
+
+ immEnd();
+}
+
+/**
+ * Poll callback for cursor drawing:
+ * #WM_paint_cursor_activate
+ */
+bool transform_draw_cursor_poll(bContext *C)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Cursor and help-line drawing, callback for:
+ * #WM_paint_cursor_activate
+ */
+void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customdata)
+{
+ TransInfo *t = (TransInfo *)customdata;
+
+ if (t->helpline != HLP_NONE) {
+ struct ArrowDims arrow_dims = {
+ .offset = 5 * UI_DPI_FAC,
+ .length = 10 * UI_DPI_FAC,
+ .size = 5 * UI_DPI_FAC,
+ };
+
+ float cent[2];
+ const float mval[3] = {x, y, 0.0f};
+ float tmval[2] = {
+ (float)t->mval[0],
+ (float)t->mval[1],
+ };
+
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ /* Offset the values for the area region. */
+ const float offset[2] = {
+ t->ar->winrct.xmin,
+ t->ar->winrct.ymin,
+ };
+
+ for (int i = 0; i < 2; i++) {
+ cent[i] += offset[i];
+ tmval[i] += offset[i];
+ }
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ GPU_matrix_push();
+
+ /* Dashed lines first. */
+ if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
+ const uint shdr_pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
+ BLI_assert(shdr_pos == POS_INDEX);
+
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", 6.0f * UI_DPI_FAC);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(POS_INDEX, cent);
+ immVertex2f(POS_INDEX, tmval[0], tmval[1]);
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ /* And now, solid lines. */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ UNUSED_VARS_NDEBUG(pos); /* silence warning */
+ BLI_assert(pos == POS_INDEX);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ switch (t->helpline) {
+ case HLP_SPRING:
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+ GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
+
+ GPU_line_width(3.0f);
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+ break;
+ case HLP_HARROW:
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+ drawArrow(RIGHT, &arrow_dims);
+ drawArrow(LEFT, &arrow_dims);
+ break;
+ case HLP_VARROW:
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+ break;
+ case HLP_CARROW: {
+ /* Draw arrow based on direction defined by custom-points. */
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+
+ const int *data = t->mouse.data;
+ const float dx = data[2] - data[0], dy = data[3] - data[1];
+ const float angle = -atan2f(dx, dy);
+
+ GPU_matrix_push();
+
+ GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
+
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+
+ GPU_matrix_pop();
+ break;
+ }
+ case HLP_ANGLE: {
+ float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
+ float angle = atan2f(dy, dx);
+ float dist = hypotf(dx, dy);
+ float delta_angle = min_ff(15.0f / (dist / UI_DPI_FAC), (float)M_PI / 4.0f);
+ float spacing_angle = min_ff(5.0f / (dist / UI_DPI_FAC), (float)M_PI / 12.0f);
+
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
+
+ GPU_line_width(3.0f);
+ drawArc(angle - delta_angle, angle - spacing_angle, 10, dist);
+ drawArc(angle + spacing_angle, angle + delta_angle, 10, dist);
+
+ GPU_matrix_push();
+
+ GPU_matrix_translate_3f(
+ cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
+
+ drawArrowHead(DOWN, arrow_dims.size);
+
+ GPU_matrix_pop();
+
+ GPU_matrix_translate_3f(
+ cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
+
+ drawArrowHead(UP, arrow_dims.size);
+ break;
+ }
+ case HLP_TRACKBALL: {
+ unsigned char col[3], col2[3];
+ UI_GetThemeColor3ubv(TH_GRID, col);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+
+ UI_make_axis_color(col, col2, 'X');
+ immUniformColor3ubv(col2);
+
+ drawArrow(RIGHT, &arrow_dims);
+ drawArrow(LEFT, &arrow_dims);
+
+ UI_make_axis_color(col, col2, 'Y');
+ immUniformColor3ubv(col2);
+
+ drawArrow(UP, &arrow_dims);
+ drawArrow(DOWN, &arrow_dims);
+ break;
+ }
+ }
+
+ immUnbindProgram();
+ GPU_matrix_pop();
+
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ }
+}
diff --git a/source/blender/editors/transform/transform_draw_cursors.h b/source/blender/editors/transform/transform_draw_cursors.h
new file mode 100644
index 00000000000..e7696bad5a7
--- /dev/null
+++ b/source/blender/editors/transform/transform_draw_cursors.h
@@ -0,0 +1,31 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#ifndef __TRANSFORM_DRAW_CURSORS_H__
+#define __TRANSFORM_DRAW_CURSORS_H__
+
+/* Callbacks for #WM_paint_cursor_activate */
+bool transform_draw_cursor_poll(struct bContext *C);
+void transform_draw_cursor_draw(struct bContext *C, int x, int y, void *customdata);
+
+#endif /* __TRANSFORM_DRAW_CURSORS_H__ */
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 4ae64c7ca5f..3f0032cc7cc 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -52,6 +52,18 @@
#include "transform.h" /* own include */
+/* -------------------------------------------------------------------- */
+/** \name Arrow / Cage Gizmo Group
+ *
+ * Defines public functions, not the gizmo it's self:
+ *
+ * - #ED_widgetgroup_gizmo2d_xform_setup
+ * - #ED_widgetgroup_gizmo2d_xform_refresh
+ * - #ED_widgetgroup_gizmo2d_xform_draw_prepare
+ * - #ED_widgetgroup_gizmo2d_xform_poll
+ *
+ * \{ */
+
/* axes as index */
enum {
MAN2D_AXIS_TRANS_X = 0,
@@ -61,8 +73,7 @@ enum {
};
typedef struct GizmoGroup2D {
- wmGizmo *translate_x, *translate_y;
-
+ wmGizmo *translate_xy[3];
wmGizmo *cage;
/* Current origin in view space, used to update widget origin for possible view changes */
@@ -70,37 +81,12 @@ typedef struct GizmoGroup2D {
float min[2];
float max[2];
+ bool no_cage;
+
} GizmoGroup2D;
/* **************** Utilities **************** */
-/* loop over axes */
-#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \
- { \
- wmGizmo *axis; \
- int axis_idx; \
- for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \
- axis = gizmo2d_get_axis_from_index(ggd, axis_idx);
-
-#define MAN2D_ITER_AXES_END \
- } \
- } \
- ((void)0)
-
-static wmGizmo *gizmo2d_get_axis_from_index(const GizmoGroup2D *ggd, const short axis_idx)
-{
- BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y));
-
- switch (axis_idx) {
- case MAN2D_AXIS_TRANS_X:
- return ggd->translate_x;
- case MAN2D_AXIS_TRANS_Y:
- return ggd->translate_y;
- }
-
- return NULL;
-}
-
static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
{
const float alpha = 0.6f;
@@ -131,11 +117,13 @@ static GizmoGroup2D *gizmogroup2d_init(wmGizmoGroup *gzgroup)
{
const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_2d", true);
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
GizmoGroup2D *ggd = MEM_callocN(sizeof(GizmoGroup2D), __func__);
- ggd->translate_x = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
- ggd->translate_y = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL);
RNA_enum_set(ggd->cage->ptr,
@@ -208,39 +196,54 @@ static int gizmo2d_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-void ED_widgetgroup_gizmo2d_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+void ED_widgetgroup_gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
gzgroup->customdata = ggd;
- MAN2D_ITER_AXES_BEGIN (axis, axis_idx) {
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
const float offset[3] = {0.0f, 0.2f};
- float color[4], color_hi[4];
- gizmo2d_get_axis_color(axis_idx, color, color_hi);
-
/* custom handler! */
- WM_gizmo_set_fn_custom_modal(axis, gizmo2d_modal);
- /* set up widget data */
- RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx);
- RNA_float_set(axis->ptr, "length", 0.8f);
- WM_gizmo_set_matrix_offset_location(axis, offset);
- WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
- WM_gizmo_set_scale(axis, U.gizmo_size);
- WM_gizmo_set_color(axis, color);
- WM_gizmo_set_color_highlight(axis, color_hi);
+ WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
+ WM_gizmo_set_scale(gz, U.gizmo_size);
+
+ if (i < 2) {
+ float color[4], color_hi[4];
+ gizmo2d_get_axis_color(i, color, color_hi);
+
+ /* set up widget data */
+ RNA_float_set(gz->ptr, "angle", -M_PI_2 * i);
+ RNA_float_set(gz->ptr, "length", 0.8f);
+ WM_gizmo_set_matrix_offset_location(gz, offset);
+ WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color_hi);
+ }
+ else {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ }
- /* assign operator */
- PointerRNA *ptr = WM_gizmo_operator_set(axis, 0, ot_translate, NULL);
- bool constraint[3] = {0};
- constraint[(axis_idx + 1) % 2] = 1;
- if (RNA_struct_find_property(ptr, "constraint_axis")) {
- RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ /* Assign operator. */
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, NULL);
+ if (i < 2) {
+ bool constraint[3] = {0};
+ constraint[(i + 1) % 2] = 1;
+ if (RNA_struct_find_property(ptr, "constraint_axis")) {
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ }
}
+
RNA_boolean_set(ptr, "release_confirm", 1);
}
- MAN2D_ITER_AXES_END;
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
@@ -286,23 +289,44 @@ void ED_widgetgroup_gizmo2d_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgro
}
}
-void ED_widgetgroup_gizmo2d_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+void ED_widgetgroup_gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ED_widgetgroup_gizmo2d_xform_setup(C, gzgroup);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ ggd->no_cage = true;
+}
+
+void ED_widgetgroup_gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup2D *ggd = gzgroup->customdata;
float origin[3];
gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
copy_v2_v2(ggd->origin, origin);
- bool show_cage = !equals_v2v2(ggd->min, ggd->max);
+ bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
+
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+ }
if (show_cage) {
ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
- ggd->translate_x->flag |= WM_GIZMO_HIDDEN;
- ggd->translate_y->flag |= WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ gz->flag |= WM_GIZMO_HIDDEN;
+ }
}
else {
ggd->cage->flag |= WM_GIZMO_HIDDEN;
- ggd->translate_x->flag &= ~WM_GIZMO_HIDDEN;
- ggd->translate_y->flag &= ~WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ gz->flag &= ~WM_GIZMO_HIDDEN;
+ }
}
if (show_cage) {
@@ -345,7 +369,7 @@ void ED_widgetgroup_gizmo2d_refresh(const bContext *C, wmGizmoGroup *gzgroup)
}
}
-void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+void ED_widgetgroup_gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *ar = CTX_wm_region(C);
GizmoGroup2D *ggd = gzgroup->customdata;
@@ -354,10 +378,10 @@ void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgrou
gizmo2d_origin_to_region(ar, origin);
- MAN2D_ITER_AXES_BEGIN (axis, axis_idx) {
- WM_gizmo_set_matrix_location(axis, origin);
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ WM_gizmo_set_matrix_location(gz, origin);
}
- MAN2D_ITER_AXES_END;
UI_view2d_view_to_region_m4(&ar->v2d, ggd->cage->matrix_space);
WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
@@ -369,7 +393,7 @@ void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgrou
* - Called on every redraw, better to do a more simple poll and check for selection in _refresh
* - UV editing only, could be expanded for other things.
*/
-bool ED_widgetgroup_gizmo2d_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+bool ED_widgetgroup_gizmo2d_xform_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
{
if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
return false;
@@ -404,3 +428,223 @@ bool ED_widgetgroup_gizmo2d_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzg
return false;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Handles
+ *
+ * Defines public functions, not the gizmo it's self:
+ *
+ * - #ED_widgetgroup_gizmo2d_resize_setup
+ * - #ED_widgetgroup_gizmo2d_resize_refresh
+ * - #ED_widgetgroup_gizmo2d_resize_draw_prepare
+ * - #ED_widgetgroup_gizmo2d_resize_poll
+ *
+ * \{ */
+
+typedef struct GizmoGroup_Resize2D {
+ wmGizmo *gizmo_xy[3];
+ float origin[2];
+} GizmoGroup_Resize2D;
+
+static GizmoGroup_Resize2D *gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_2d", true);
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
+
+ GizmoGroup_Resize2D *ggd = MEM_callocN(sizeof(GizmoGroup_Resize2D), __func__);
+
+ ggd->gizmo_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->gizmo_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->gizmo_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
+
+ return ggd;
+}
+
+void ED_widgetgroup_gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup_Resize2D *ggd = gzgroup->customdata;
+ float origin[3];
+ gizmo2d_calc_bounds(C, origin, NULL, NULL);
+ copy_v2_v2(ggd->origin, origin);
+}
+
+void ED_widgetgroup_gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ GizmoGroup_Resize2D *ggd = gzgroup->customdata;
+ float origin[3] = {UNPACK2(ggd->origin), 0.0f};
+
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+ }
+
+ gizmo2d_origin_to_region(ar, origin);
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
+ wmGizmo *gz = ggd->gizmo_xy[i];
+ WM_gizmo_set_matrix_location(gz, origin);
+ }
+}
+
+bool ED_widgetgroup_gizmo2d_resize_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ return ED_widgetgroup_gizmo2d_xform_poll(C, NULL);
+}
+
+void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
+ GizmoGroup_Resize2D *ggd = gizmogroup2d_resize_init(gzgroup);
+ gzgroup->customdata = ggd;
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
+ wmGizmo *gz = ggd->gizmo_xy[i];
+
+ /* custom handler! */
+ WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
+ WM_gizmo_set_scale(gz, U.gizmo_size);
+
+ if (i < 2) {
+ const float offset[3] = {0.0f, 0.2f};
+ float color[4], color_hi[4];
+ gizmo2d_get_axis_color(i, color, color_hi);
+
+ /* set up widget data */
+ RNA_float_set(gz->ptr, "angle", -M_PI_2 * i);
+ RNA_float_set(gz->ptr, "length", 0.8f);
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
+
+ WM_gizmo_set_matrix_offset_location(gz, offset);
+ WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color_hi);
+ }
+ else {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ }
+
+ /* Assign operator. */
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, NULL);
+ if (i < 2) {
+ bool constraint[3] = {0};
+ constraint[(i + 1) % 2] = 1;
+ if (RNA_struct_find_property(ptr, "constraint_axis")) {
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ }
+ }
+ RNA_boolean_set(ptr, "release_confirm", true);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rotate Handles
+ *
+ * Defines public functions, not the gizmo it's self:
+ *
+ * - #ED_widgetgroup_gizmo2d_rotate_setup
+ * - #ED_widgetgroup_gizmo2d_rotate_refresh
+ * - #ED_widgetgroup_gizmo2d_rotate_draw_prepare
+ * - #ED_widgetgroup_gizmo2d_rotate_poll
+ *
+ * \{ */
+
+typedef struct GizmoGroup_Rotate2D {
+ wmGizmo *gizmo;
+ float origin[2];
+} GizmoGroup_Rotate2D;
+
+static GizmoGroup_Rotate2D *gizmogroup2d_rotate_init(wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
+
+ GizmoGroup_Rotate2D *ggd = MEM_callocN(sizeof(GizmoGroup_Rotate2D), __func__);
+
+ ggd->gizmo = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
+
+ return ggd;
+}
+
+void ED_widgetgroup_gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
+ float origin[3];
+ gizmo2d_calc_bounds(C, origin, NULL, NULL);
+ copy_v2_v2(ggd->origin, origin);
+}
+
+void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
+ float origin[3] = {UNPACK2(ggd->origin), 0.0f};
+
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+ }
+
+ gizmo2d_origin_to_region(ar, origin);
+
+ wmGizmo *gz = ggd->gizmo;
+ WM_gizmo_set_matrix_location(gz, origin);
+}
+
+bool ED_widgetgroup_gizmo2d_rotate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ return ED_widgetgroup_gizmo2d_xform_poll(C, NULL);
+}
+
+void ED_widgetgroup_gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
+ GizmoGroup_Rotate2D *ggd = gizmogroup2d_rotate_init(gzgroup);
+ gzgroup->customdata = ggd;
+
+ /* Other setup functions iterate over axis. */
+ {
+ wmGizmo *gz = ggd->gizmo;
+
+ /* custom handler! */
+ WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
+ WM_gizmo_set_scale(gz, U.gizmo_size);
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
+
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ /* Make the center low alpha. */
+ WM_gizmo_set_line_width(gz, 2.0f);
+ RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ }
+
+ /* Assign operator. */
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, NULL);
+ RNA_boolean_set(ptr, "release_confirm", true);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index f19147baa89..b3c1fbd3aad 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -2046,7 +2046,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo";
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -2081,7 +2082,7 @@ void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
gzgt->idname = "VIEW3D_GGT_xform_gizmo_context";
gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_PERSISTENT |
- WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->poll = WIDGETGROUP_gizmo_poll_context;
gzgt->setup = WIDGETGROUP_gizmo_setup;
@@ -2289,7 +2290,8 @@ void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -2530,7 +2532,8 @@ void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index da6b0285a5c..fb33471cf3f 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -514,7 +514,8 @@ void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt)
gzgt->name = "3D View Extrude";
gzgt->idname = "VIEW3D_GGT_xform_extrude";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index f9f6a513f63..a188e2eb829 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -26,6 +26,8 @@
/* For enum. */
#include "DNA_space_types.h"
+struct SnapObjectParams;
+
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
const bool use_peel_object,
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index eb3d47ba1b5..1de4d05a721 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -1286,7 +1286,7 @@ static void uv_select_linked_multi(Scene *scene,
vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
if (vmap == NULL) {
- return;
+ continue;
}
stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");