diff options
Diffstat (limited to 'source/blender/blenkernel')
62 files changed, 1871 insertions, 2006 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 963e3158d46..9da17d777cd 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -249,6 +249,10 @@ typedef enum eAnimData_Recalc { ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM), } eAnimData_Recalc; +bool BKE_animsys_store_rna_setting(struct PointerRNA *ptr, + const char *rna_path, + const int array_index, + struct PathResolvedRNA *r_result); bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value); bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9855c2202cc..2acef7847bc 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -26,8 +26,8 @@ * * \note Use #STRINGIFY() rather than defining with quotes. */ -#define BLENDER_VERSION 282 -#define BLENDER_SUBVERSION 6 +#define BLENDER_VERSION 283 +#define BLENDER_SUBVERSION 2 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 17de53be42a..2862dda8ead 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -74,11 +74,11 @@ typedef struct ClothSolverResult { * own connectivity of the mesh based on the actual edges in the mesh. */ typedef struct Cloth { - struct ClothVertex *verts; /* The vertices that represent this cloth. */ - struct LinkNode *springs; /* The springs connecting the mesh. */ - unsigned int numsprings; /* The count of springs. */ - unsigned int mvert_num; /* The number of verts == m * n. */ - unsigned int tri_num; + struct ClothVertex *verts; /* The vertices that represent this cloth. */ + struct LinkNode *springs; /* The springs connecting the mesh. */ + unsigned int numsprings; /* The count of springs. */ + unsigned int mvert_num; /* The number of verts == m * n. */ + unsigned int primitive_num; /* Number of triangles for cloth and edges for hair. */ unsigned char old_solver_type; /* unused, only 1 solver here */ unsigned char pad2; short pad3; @@ -89,6 +89,7 @@ typedef struct Cloth { struct EdgeSet *edgeset; /* used for selfcollisions */ int last_frame; float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */ + struct MEdge *edges; /* Used for hair collisions. */ } Cloth; /** @@ -265,15 +266,6 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph, float step, float dt); -void cloth_find_point_contacts(struct Depsgraph *depsgraph, - struct Object *ob, - struct ClothModifierData *clmd, - float step, - float dt, - ColliderContacts **r_collider_contacts, - int *r_totcolliders); -void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders); - //////////////////////////////////////////////// ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 0d33d86ec16..47ed42cade9 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -142,6 +142,8 @@ bool BKE_collection_child_add(struct Main *bmain, struct Collection *parent, struct Collection *child); +bool BKE_collection_child_add_no_sync(struct Collection *parent, struct Collection *child); + bool BKE_collection_child_remove(struct Main *bmain, struct Collection *parent, struct Collection *child); diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 5d7a5094eb5..5bf697e5df9 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -125,7 +125,10 @@ void bvhtree_update_from_mvert(BVHTree *bvhtree, // move Collision modifier object inter-frame with step = [0,1] // defined in collisions.c -void collision_move_object(struct CollisionModifierData *collmd, float step, float prevstep); +void collision_move_object(struct CollisionModifierData *collmd, + const float step, + const float prevstep, + const bool moving_bvh); void collision_get_collider_velocity(float vel_old[3], float vel_new[3], diff --git a/source/blender/blenkernel/BKE_displist_tangent.h b/source/blender/blenkernel/BKE_displist_tangent.h new file mode 100644 index 00000000000..3af7c513f67 --- /dev/null +++ b/source/blender/blenkernel/BKE_displist_tangent.h @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#ifndef __BKE_DISPLIST_TANGENT_H__ +#define __BKE_DISPLIST_TANGENT_H__ + +/** \file + * \ingroup bke + */ + +void BKE_displist_tangent_calc(const DispList *dl, float (*fnormals)[3], float (**r_tangent)[4]); + +#endif /* __BKE_DISPLIST_TANGENT_H__ */ diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 1b9e318146e..80cb0f1482b 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -35,6 +35,7 @@ struct Depsgraph; struct EditMeshData; struct Mesh; struct MeshStatVis; +struct Object; struct Scene; /** @@ -65,18 +66,11 @@ typedef struct BMEditMesh { /*derivedmesh stuff*/ CustomData_MeshMasks lastDataMask; - unsigned char (*derivedVertColor)[4]; - int derivedVertColorLen; - unsigned char (*derivedFaceColor)[4]; - int derivedFaceColorLen; /*selection mode*/ short selectmode; short mat_nr; - /* Object this editmesh came from (if it came from one) */ - struct Object *ob; - /*temp variables for x-mirror editing*/ int mirror_cdlayer; /* -1 is invalid */ @@ -96,20 +90,14 @@ BMEditMesh *BKE_editmesh_from_object(struct Object *ob); void BKE_editmesh_free_derivedmesh(BMEditMesh *em); void BKE_editmesh_free(BMEditMesh *em); -void BKE_editmesh_color_free(BMEditMesh *em); -void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype); +float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph, + struct BMEditMesh *em, + struct Scene *scene, + struct Object *ob, + int *r_vert_len))[3]; float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]; -void BKE_editmesh_lnorspace_update(BMEditMesh *em); -void BKE_editmesh_ensure_autosmooth(BMEditMesh *em); +void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me); +void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me); struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em); -/* editderivedmesh.c */ -/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */ -void BKE_editmesh_statvis_calc(BMEditMesh *em, - struct EditMeshData *emd, - const struct MeshStatVis *statvis); - -float (*BKE_editmesh_vert_coords_alloc( - struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_vert_len))[3]; - #endif /* __BKE_EDITMESH_H__ */ diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 426e0ed4b0e..405b052f477 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -107,6 +107,7 @@ bool driver_get_variable_property(struct ChannelDriver *driver, int *r_index); bool BKE_driver_has_simple_expression(struct ChannelDriver *driver); +bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver); void BKE_driver_invalidate_expression(struct ChannelDriver *driver, bool expr_changed, bool varname_changed); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 94c2a94d420..2b02895043f 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -83,6 +83,8 @@ void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL(); typedef void (*IDPWalkFunc)(void *userData, IDProperty *idp); +void IDP_AssignID(IDProperty *prop, ID *id, const int flag); + /*-------- Group Functions -------*/ /** Sync values from one group to another, only where they match */ diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h index bd442c97000..153ad9bb915 100644 --- a/source/blender/blenkernel/BKE_lightprobe.h +++ b/source/blender/blenkernel/BKE_lightprobe.h @@ -29,6 +29,7 @@ struct LightProbe; struct Main; void BKE_lightprobe_init(struct LightProbe *probe); +void BKE_lightprobe_type_set(struct LightProbe *probe, const short lightprobe_type); void *BKE_lightprobe_add(struct Main *bmain, const char *name); void BKE_lightprobe_copy_data(struct Main *bmain, struct LightProbe *probe_dst, diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 90afec54561..570541eb990 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -177,7 +177,6 @@ int BKE_mesh_nurbs_displist_to_mdata(struct Object *ob, void BKE_mesh_from_nurbs_displist(struct Main *bmain, struct Object *ob, struct ListBase *dispbase, - const bool use_orco_uv, const char *obdata_name, bool temporary); void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 11f151af44d..b599e1e1b2c 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -545,7 +545,8 @@ void nodeRemoveNode(struct Main *bmain, struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree, const struct bNode *node_src, - const int flag); + const int flag, + const bool unique_name); /* Same as BKE_node_copy_ex() but stores pointers to a new node and its sockets in the source * node. diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index ec6ec027810..54cd172655e 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -66,7 +66,6 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_free(struct Object *ob); void BKE_object_free_derived_caches(struct Object *ob); -void BKE_object_free_derived_mesh_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index fdd3bd7cd86..db35fbde2c8 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -85,19 +85,33 @@ typedef enum ePaintMode { #define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PAINT_MODE_SCULPT_UV) /* overlay invalidation */ -typedef enum eOverlayControlFlags { +typedef enum ePaintOverlayControlFlags { PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY = 1, PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY = (1 << 2), PAINT_OVERLAY_INVALID_CURVE = (1 << 3), PAINT_OVERLAY_OVERRIDE_CURSOR = (1 << 4), PAINT_OVERLAY_OVERRIDE_PRIMARY = (1 << 5), PAINT_OVERLAY_OVERRIDE_SECONDARY = (1 << 6), -} eOverlayControlFlags; +} ePaintOverlayControlFlags; #define PAINT_OVERRIDE_MASK \ (PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \ PAINT_OVERLAY_OVERRIDE_CURSOR) +/* Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to + * flip or mirror transform values depending on where the vertex is and where the transform + * operation started to support XYZ symmetry on those operations in a predictable way. */ + +#define PAINT_SYMM_AREA_DEFAULT 0 + +typedef enum ePaintSymmetryAreas { + PAINT_SYMM_AREA_X = (1 << 0), + PAINT_SYMM_AREA_Y = (1 << 1), + PAINT_SYMM_AREA_Z = (1 << 2), +} ePaintSymmetryAreas; + +#define PAINT_SYMM_AREAS 8 + void BKE_paint_invalidate_overlay_tex(struct Scene *scene, struct ViewLayer *view_layer, const struct Tex *tex); @@ -105,8 +119,8 @@ void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct ViewLayer *view_layer, struct CurveMapping *curve); void BKE_paint_invalidate_overlay_all(void); -eOverlayControlFlags BKE_paint_get_overlay_flags(void); -void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag); +ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void); +void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag); void BKE_paint_set_overlay_override(enum eOverlayFlags flag); /* palettes */ @@ -211,6 +225,29 @@ struct SculptVertexPaintGeomMap { struct MeshElemMap *vert_to_poly; }; +/* Pose Brush IK Chain */ +typedef struct SculptPoseIKChainSegment { + float orig[3]; + float head[3]; + + float initial_orig[3]; + float initial_head[3]; + float len; + float rot[4]; + float *weights; + + /* Store a 4x4 transform matrix for each of the possible combinations of enabled XYZ symmetry + * axis. */ + float trans_mat[PAINT_SYMM_AREAS][4][4]; + float pivot_mat[PAINT_SYMM_AREAS][4][4]; + float pivot_mat_inv[PAINT_SYMM_AREAS][4][4]; +} SculptPoseIKChainSegment; + +typedef struct SculptPoseIKChain { + SculptPoseIKChainSegment *segments; + int tot_segments; +} SculptPoseIKChain; + /* Session data (mode-specific) */ typedef struct SculptSession { @@ -273,7 +310,10 @@ typedef struct SculptSession { /* Dynamic mesh preview */ int *preview_vert_index_list; int preview_vert_index_count; + + /* Pose Brush Preview */ float pose_origin[3]; + SculptPoseIKChain *pose_ik_chain_preview; /* Transform operator */ float pivot_pos[3]; diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 006915d6c45..d73e40291a0 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -173,6 +173,8 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene); bool BKE_scene_uses_blender_workbench(const struct Scene *scene); bool BKE_scene_uses_cycles(const struct Scene *scene); +void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src); + void BKE_scene_disable_color_management(struct Scene *scene); bool BKE_scene_check_color_management_enabled(const struct Scene *scene); bool BKE_scene_check_rigidbody_active(const struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 770318883c0..bc312c7bb2b 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -208,6 +208,7 @@ struct SeqEffectHandle { * * sequencer render functions * ********************************************************************** */ +double BKE_sequencer_rendersize_to_scale_factor(int size); struct ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown); struct ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context, @@ -412,7 +413,10 @@ bool BKE_sequence_base_shuffle_ex(struct ListBase *seqbasep, bool BKE_sequence_base_shuffle(struct ListBase *seqbasep, struct Sequence *test, struct Scene *evil_scene); -bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene); +bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, + struct Scene *evil_scene, + ListBase *markers, + const bool use_sync_markers); bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase); void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); struct Sequence *BKE_sequence_dupli_recursive(const struct Scene *scene_src, @@ -503,6 +507,7 @@ enum { SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT, SEQ_SIDE_BOTH, + SEQ_SIDE_NO_CHANGE, }; int BKE_sequencer_find_next_prev_edit(struct Scene *scene, int cfra, diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index cd48e4d7f3b..70aa028a2c7 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -58,7 +58,7 @@ typedef enum { struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, struct SubsurfModifierData *smd, - struct Scene *scene, + const struct Scene *scene, float (*vertCos)[3], SubsurfFlags flags); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index cd03f80d9ec..2885495c3b0 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -105,8 +105,8 @@ set(SRC intern/data_transfer.c intern/deform.c intern/displist.c + intern/displist_tangent.c intern/dynamicpaint.c - intern/editderivedmesh.c intern/editlattice.c intern/editmesh.c intern/editmesh_bvh.c @@ -272,6 +272,7 @@ set(SRC BKE_data_transfer.h BKE_deform.h BKE_displist.h + BKE_displist_tangent.h BKE_dynamicpaint.h BKE_editlattice.h BKE_editmesh.h @@ -424,6 +425,10 @@ if(WITH_AUDASPACE) list(APPEND INC_SYS ${AUDASPACE_C_INCLUDE_DIRS} ) + list(APPEND LIB + ${AUDASPACE_C_LIBRARIES} + ${AUDASPACE_PY_LIBRARIES} + ) endif() if(WITH_BULLET) @@ -436,6 +441,8 @@ if(WITH_BULLET) list(APPEND LIB bf_intern_rigidbody extern_bullet + + ${BULLET_LIBRARIES} ) add_definitions(-DWITH_BULLET) endif() @@ -490,6 +497,9 @@ if(WITH_CODEC_FFMPEG) list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS} ) + list(APPEND LIB + ${FFMPEG_LIBRARIES} + ) add_definitions(-DWITH_FFMPEG) remove_strict_c_flags_file( @@ -543,6 +553,9 @@ if(WITH_LZO) list(APPEND INC_SYS ${LZO_INCLUDE_DIR} ) + list(APPEND LIB + ${LZO_LIBRARIES} + ) add_definitions(-DWITH_SYSTEM_LZO) else() list(APPEND INC_SYS @@ -573,6 +586,9 @@ if(WITH_FFTW3) list(APPEND INC_SYS ${FFTW3_INCLUDE_DIRS} ) + list(APPEND LIB + ${FFTW3_LIBRARIES} + ) add_definitions(-DFFTW3=1) endif() @@ -599,6 +615,9 @@ if(WITH_OPENSUBDIV) list(APPEND INC_SYS ${OPENSUBDIV_INCLUDE_DIRS} ) + list(APPEND LIB + ${OPENSUBDIV_LIBRARIES} + ) add_definitions(-DWITH_OPENSUBDIV) endif() @@ -634,6 +653,9 @@ if(WITH_TBB) list(APPEND INC_SYS ${TBB_INCLUDE_DIRS} ) + list(APPEND LIB + ${TBB_LIBRARIES} + ) endif() # # Warnings as errors, this is too strict! diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 8be7a947a67..f9e7627a8dd 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -789,14 +789,6 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc } } -static void editmesh_update_statvis_color(const Scene *scene, Object *ob) -{ - BMEditMesh *em = BKE_editmesh_from_object(ob); - Mesh *me = ob->data; - BKE_mesh_runtime_ensure_edit_data(me); - BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis); -} - static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, const CustomData_MeshMasks *final_datamask, const bool sculpt_dyntopo, @@ -1494,7 +1486,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Modifier evaluation modes. */ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; - const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */ /* Modifier evaluation contexts for different types of modifiers. */ const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE}; @@ -1703,22 +1694,12 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, else if (!deformed_verts && mesh_cage) { /* cage should already have up to date normals */ mesh_final = mesh_cage; - - /* In this case, we should never have weight-modifying modifiers in stack... */ - if (do_init_statvis) { - editmesh_update_statvis_color(scene, ob); - } } else { /* this is just a copy of the editmesh, no need to calc normals */ mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap( em_input, &final_datamask, deformed_verts, mesh_input); deformed_verts = NULL; - - /* In this case, we should never have weight-modifying modifiers in stack... */ - if (do_init_statvis) { - editmesh_update_statvis_color(scene, ob); - } } if (deformed_verts) { @@ -1858,7 +1839,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph, BMEditMesh *em, CustomData_MeshMasks *dataMask) { - BLI_assert(em->ob->id.tag & LIB_TAG_COPIED_ON_WRITE); + BLI_assert(obedit->id.tag & LIB_TAG_COPIED_ON_WRITE); BKE_object_free_derived_caches(obedit); if (DEG_is_active(depsgraph)) { diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 32420e2e894..be6622e5d42 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1665,11 +1665,11 @@ void BKE_keyingsets_free(ListBase *list) /* ***************************************** */ /* Evaluation Data-Setting Backend */ -static bool animsys_store_rna_setting(PointerRNA *ptr, - /* typically 'fcu->rna_path', 'fcu->array_index' */ - const char *rna_path, - const int array_index, - PathResolvedRNA *r_result) +bool BKE_animsys_store_rna_setting(PointerRNA *ptr, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, + const int array_index, + PathResolvedRNA *r_result) { bool success = false; const char *path = rna_path; @@ -1880,7 +1880,7 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr, } PathResolvedRNA orig_anim_rna; /* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */ - if (animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { + if (BKE_animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { BKE_animsys_write_rna_setting(&orig_anim_rna, value); } } @@ -1910,7 +1910,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, continue; } PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); BKE_animsys_write_rna_setting(&anim_rna, curval); if (flush_to_original) { @@ -1944,7 +1944,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime * NOTE: for 'layering' option later on, we should check if we should remove old value * before adding new to only be done when drivers only changed. */ PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); ok = BKE_animsys_write_rna_setting(&anim_rna, curval); } @@ -2023,7 +2023,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); BKE_animsys_write_rna_setting(&anim_rna, curval); } @@ -3803,7 +3803,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* for each override, simply execute... */ for (aor = adt->overrides.first; aor; aor = aor->next) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { BKE_animsys_write_rna_setting(&anim_rna, aor->value); } } @@ -4125,7 +4125,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu // printf("\told val = %f\n", fcu->curval); PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { /* Evaluate driver, and write results to COW-domain destination */ const float ctime = DEG_get_ctime(depsgraph); const float curval = calculate_fcurve(&anim_rna, fcu, ctime); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index c588ee80c78..e4da10797ff 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2293,13 +2293,17 @@ void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll) * If vec is the Y vector from purely rotational mat, result should be exact. */ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll) { - float vecmat[3][3], vecmatinv[3][3], rollmat[3][3]; + float vecmat[3][3], vecmatinv[3][3], rollmat[3][3], q[4]; + /* Compute the orientation relative to the vector with zero roll. */ vec_roll_to_mat3(vec, 0.0f, vecmat); invert_m3_m3(vecmatinv, vecmat); mul_m3_m3m3(rollmat, vecmatinv, mat); - *r_roll = atan2f(rollmat[2][0], rollmat[2][2]); + /* Extract the twist angle as the roll value. */ + mat3_to_quat(q, rollmat); + + *r_roll = quat_split_swing_and_twist(q, 1, NULL, NULL); } /* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index 7c12747283c..cd950e05415 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -73,7 +73,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C) G.fileflags |= G_FILE_NO_UI; if (UNDO_DISK) { - success = BKE_blendfile_read(C, mfu->filename, NULL, 0); + success = BKE_blendfile_read(C, mfu->filename, &(const struct BlendFileReadParams){0}, NULL); } else { success = BKE_blendfile_read_from_memfile( diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index b5f2ca0f117..721eb9a2a37 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -893,9 +893,11 @@ void BKE_brush_debug_print_state(Brush *br) BR_TEST(add_col[0], f); BR_TEST(add_col[1], f); BR_TEST(add_col[2], f); + BR_TEST(add_col[3], f); BR_TEST(sub_col[0], f); BR_TEST(sub_col[1], f); BR_TEST(sub_col[2], f); + BR_TEST(sub_col[3], f); printf("\n"); @@ -926,7 +928,7 @@ void BKE_brush_sculpt_reset(Brush *br) br->curve_preset = BRUSH_CURVE_POW4; br->spacing = 5; break; - case SCULPT_TOOL_TOPOLOGY: + case SCULPT_TOOL_SLIDE_RELAX: br->spacing = 10; br->alpha = 1.0f; break; @@ -990,6 +992,7 @@ void BKE_brush_sculpt_reset(Brush *br) break; case SCULPT_TOOL_POSE: br->pose_smooth_iterations = 4; + br->pose_ik_segments = 1; br->flag &= ~BRUSH_ALPHA_PRESSURE; br->flag &= ~BRUSH_SPACE; br->flag &= ~BRUSH_SPACE_ATTEN; @@ -1006,6 +1009,11 @@ void BKE_brush_sculpt_reset(Brush *br) } /* Cursor colors */ + + /* Default Alpha */ + br->add_col[3] = 0.90f; + br->sub_col[3] = 0.90f; + switch (br->sculpt_tool) { case SCULPT_TOOL_DRAW: case SCULPT_TOOL_DRAW_SHARP: diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index c26800aefba..7332c3e0d43 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -190,22 +190,36 @@ static BVHTree *bvhtree_build_from_cloth(ClothModifierData *clmd, float epsilon) vt = cloth->tri; /* in the moment, return zero if no faces there */ - if (!cloth->tri_num) { + if (!cloth->primitive_num) { return NULL; } /* create quadtree with k=26 */ - bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26); + bvhtree = BLI_bvhtree_new(cloth->primitive_num, epsilon, 4, 26); /* fill tree */ - for (i = 0; i < cloth->tri_num; i++, vt++) { - float co[3][3]; + if (clmd->hairdata == NULL) { + for (i = 0; i < cloth->primitive_num; i++, vt++) { + float co[3][3]; - copy_v3_v3(co[0], verts[vt->tri[0]].xold); - copy_v3_v3(co[1], verts[vt->tri[1]].xold); - copy_v3_v3(co[2], verts[vt->tri[2]].xold); + copy_v3_v3(co[0], verts[vt->tri[0]].xold); + copy_v3_v3(co[1], verts[vt->tri[1]].xold); + copy_v3_v3(co[2], verts[vt->tri[2]].xold); - BLI_bvhtree_insert(bvhtree, i, co[0], 3); + BLI_bvhtree_insert(bvhtree, i, co[0], 3); + } + } + else { + MEdge *edges = cloth->edges; + + for (i = 0; i < cloth->primitive_num; i++) { + float co[2][3]; + + copy_v3_v3(co[0], verts[edges[i].v1].xold); + copy_v3_v3(co[1], verts[edges[i].v2].xold); + + BLI_bvhtree_insert(bvhtree, i, co[0], 2); + } } /* balance tree */ @@ -222,6 +236,8 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) ClothVertex *verts = cloth->verts; const MVertTri *vt; + BLI_assert(!(clmd->hairdata != NULL && self)); + if (self) { bvhtree = cloth->bvhselftree; } @@ -236,39 +252,59 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) vt = cloth->tri; /* update vertex position in bvh tree */ - if (verts && vt) { - for (i = 0; i < cloth->tri_num; i++, vt++) { - float co[3][3], co_moving[3][3]; - bool ret; - - /* copy new locations into array */ - if (moving) { - copy_v3_v3(co[0], verts[vt->tri[0]].txold); - copy_v3_v3(co[1], verts[vt->tri[1]].txold); - copy_v3_v3(co[2], verts[vt->tri[2]].txold); - - /* update moving positions */ - copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); - copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); - copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx); - - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); - } - else { - copy_v3_v3(co[0], verts[vt->tri[0]].tx); - copy_v3_v3(co[1], verts[vt->tri[1]].tx); - copy_v3_v3(co[2], verts[vt->tri[2]].tx); + if (clmd->hairdata == NULL) { + if (verts && vt) { + for (i = 0; i < cloth->primitive_num; i++, vt++) { + float co[3][3], co_moving[3][3]; + bool ret; + + /* copy new locations into array */ + if (moving) { + copy_v3_v3(co[0], verts[vt->tri[0]].txold); + copy_v3_v3(co[1], verts[vt->tri[1]].txold); + copy_v3_v3(co[2], verts[vt->tri[2]].txold); + + /* update moving positions */ + copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); + copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); + copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx); + + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); + } + else { + copy_v3_v3(co[0], verts[vt->tri[0]].tx); + copy_v3_v3(co[1], verts[vt->tri[1]].tx); + copy_v3_v3(co[2], verts[vt->tri[2]].tx); - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); - } + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); + } - /* check if tree is already full */ - if (ret == false) { - break; + /* check if tree is already full */ + if (ret == false) { + break; + } } + + BLI_bvhtree_update_tree(bvhtree); } + } + else { + if (verts) { + MEdge *edges = cloth->edges; + + for (i = 0; i < cloth->primitive_num; i++) { + float co[2][3]; - BLI_bvhtree_update_tree(bvhtree); + copy_v3_v3(co[0], verts[edges[i].v1].tx); + copy_v3_v3(co[1], verts[edges[i].v2].tx); + + if (!BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 2)) { + break; + } + } + + BLI_bvhtree_update_tree(bvhtree); + } } } @@ -900,7 +936,13 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) } /* save face information */ - clmd->clothObject->tri_num = looptri_num; + if (clmd->hairdata == NULL) { + clmd->clothObject->primitive_num = looptri_num; + } + else { + clmd->clothObject->primitive_num = mesh->totedge; + } + clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris"); if (clmd->clothObject->tri == NULL) { cloth_free_modifier(clmd); @@ -910,6 +952,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) } BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num); + clmd->clothObject->edges = mesh->medge; + /* Free the springs since they can't be correct if the vertices * changed. */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index ed306dfa4df..0014fd3e7c0 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -1065,6 +1065,11 @@ bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child return true; } +bool BKE_collection_child_add_no_sync(Collection *parent, Collection *child) +{ + return collection_child_add(parent, child, 0, true); +} + bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child) { if (!collection_child_remove(parent, child)) { diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 91d66e16dde..5db42618a9e 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_task.h" #include "BLI_threads.h" @@ -77,9 +78,11 @@ typedef struct SelfColDetectData { ***********************************/ /* step is limited from 0 (frame start position) to 1 (frame end position) */ -void collision_move_object(CollisionModifierData *collmd, float step, float prevstep) +void collision_move_object(CollisionModifierData *collmd, + const float step, + const float prevstep, + const bool moving_bvh) { - float oldx[3]; unsigned int i = 0; /* the collider doesn't move this frame */ @@ -92,13 +95,17 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev } for (i = 0; i < collmd->mvert_num; i++) { - interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep); - interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step); - sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx); + interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, prevstep); + interp_v3_v3v3(collmd->current_xnew[i].co, collmd->x[i].co, collmd->xnew[i].co, step); + sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co); } - bvhtree_update_from_mvert( - collmd->bvhtree, collmd->current_x, NULL, collmd->tri, collmd->tri_num, false); + bvhtree_update_from_mvert(collmd->bvhtree, + collmd->current_xnew, + collmd->current_x, + collmd->tri, + collmd->tri_num, + moving_bvh); } BVHTree *bvhtree_build_from_mvert(const MVert *mvert, @@ -187,17 +194,17 @@ BLI_INLINE int next_ind(int i) return (++i < 3) ? i : 0; } -static float compute_collision_point(float a1[3], - const float a2[3], - const float a3[3], - const float b1[3], - const float b2[3], - const float b3[3], - bool culling, - bool use_normal, - float r_a[3], - float r_b[3], - float r_vec[3]) +static float compute_collision_point_tri_tri(const float a1[3], + const float a2[3], + const float a3[3], + const float b1[3], + const float b2[3], + const float b3[3], + bool culling, + bool use_normal, + float r_a[3], + float r_b[3], + float r_vec[3]) { float a[3][3]; float b[3][3]; @@ -417,6 +424,179 @@ static float compute_collision_point(float a1[3], return dist; } +static float compute_collision_point_edge_tri(const float a1[3], + const float a2[3], + const float b1[3], + const float b2[3], + const float b3[3], + bool culling, + bool use_normal, + float r_a[3], + float r_b[3], + float r_vec[3]) +{ + float a[2][3]; + float b[3][3]; + float dist = FLT_MAX; + float tmp_co1[3], tmp_co2[3]; + float isect_a[3]; + bool isect = false; + float tmp, tmp_vec[3]; + float normal[3], cent[3]; + bool backside = false; + + copy_v3_v3(a[0], a1); + copy_v3_v3(a[1], a2); + + copy_v3_v3(b[0], b1); + copy_v3_v3(b[1], b2); + copy_v3_v3(b[2], b3); + + normal_tri_v3(normal, b[0], b[1], b[2]); + + /* Find intersection. */ + if (isect_line_segment_tri_v3(a[0], a[1], b[0], b[1], b[2], &tmp, NULL)) { + interp_v3_v3v3(isect_a, a[0], a[1], tmp); + isect = true; + } + + /* Determine collision side. */ + if (culling) { + if (isect) { + backside = true; + } + else { + mid_v3_v3v3v3(cent, b[0], b[1], b[2]); + + for (int i = 0; i < 2; i++) { + sub_v3_v3v3(tmp_vec, a[i], cent); + if (dot_v3v3(tmp_vec, normal) < 0.0f) { + backside = true; + break; + } + } + } + } + + if (isect) { + /* Edge intersection. */ + copy_v3_v3(r_a, isect_a); + copy_v3_v3(r_b, isect_a); + + copy_v3_v3(r_vec, normal); + + return 0.0f; + } + + if (backside) { + float maxdist = 0.0f; + bool found = false; + + /* Point projections. */ + for (int i = 0; i < 2; i++) { + if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) { + if (tmp > maxdist) { + maxdist = tmp; + copy_v3_v3(r_a, a[i]); + madd_v3_v3v3fl(r_b, a[i], normal, tmp); + found = true; + } + } + } + + /* Edge projections. */ + for (int i = 0; i < 3; i++) { + float dir[3]; + + sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]); + cross_v3_v3v3(dir, tmp_vec, normal); + + if (isect_line_plane_v3(tmp_co1, a[0], a[1], b[i], dir) && + point_in_slice_seg(tmp_co1, a[0], a[1]) && + point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) { + closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]); + sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2); + tmp = len_v3(tmp_vec); + + if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) { + maxdist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + found = true; + } + } + } + + /* If no point is found, will fallback onto regular proximity test below. */ + if (found) { + sub_v3_v3v3(r_vec, r_b, r_a); + + if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + + return 0.0f; + } + } + + /* Closest point. */ + for (int i = 0; i < 2; i++) { + closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]); + tmp = len_squared_v3v3(tmp_co1, a[i]); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, a[i]); + copy_v3_v3(r_b, tmp_co1); + } + } + + /* Closest edge. */ + if (!isect) { + for (int j = 0; j < 3; j++) { + isect_seg_seg_v3(a[0], a[1], b[j], b[next_ind(j)], tmp_co1, tmp_co2); + tmp = len_squared_v3v3(tmp_co1, tmp_co2); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + } + } + } + + if (isect) { + sub_v3_v3v3(r_vec, r_b, r_a); + dist = 0.0f; + } + else { + sub_v3_v3v3(r_vec, r_a, r_b); + dist = sqrtf(dist); + } + + if (culling && use_normal) { + copy_v3_v3(r_vec, normal); + } + else if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) { + return FLT_MAX; + } + + return dist; +} + // w3 is not perfect static void collision_compute_barycentric( const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3) @@ -488,6 +668,7 @@ static int cloth_collision_response_static(ClothModifierData *clmd, float v1[3], v2[3], relativeVelocity[3]; float magrelVel; float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + const bool is_hair = (clmd->hairdata != NULL); cloth1 = clmd->clothObject; @@ -503,32 +684,41 @@ static int cloth_collision_response_static(ClothModifierData *clmd, continue; } - /* Compute barycentric coordinates for both collision points. */ - collision_compute_barycentric(collpair->pa, - cloth1->verts[collpair->ap1].tx, - cloth1->verts[collpair->ap2].tx, - cloth1->verts[collpair->ap3].tx, - &w1, - &w2, - &w3); + /* Compute barycentric coordinates and relative "velocity" for both collision points. */ + if (is_hair) { + w2 = line_point_factor_v3( + collpair->pa, cloth1->verts[collpair->ap1].tx, cloth1->verts[collpair->ap2].tx); + + w1 = 1.0f - w2; + + interp_v3_v3v3(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w2); + } + else { + collision_compute_barycentric(collpair->pa, + cloth1->verts[collpair->ap1].tx, + cloth1->verts[collpair->ap2].tx, + cloth1->verts[collpair->ap3].tx, + &w1, + &w2, + &w3); + + collision_interpolateOnTriangle(v1, + cloth1->verts[collpair->ap1].tv, + cloth1->verts[collpair->ap2].tv, + cloth1->verts[collpair->ap3].tv, + w1, + w2, + w3); + } collision_compute_barycentric(collpair->pb, - collmd->current_x[collpair->bp1].co, - collmd->current_x[collpair->bp2].co, - collmd->current_x[collpair->bp3].co, + collmd->current_xnew[collpair->bp1].co, + collmd->current_xnew[collpair->bp2].co, + collmd->current_xnew[collpair->bp3].co, &u1, &u2, &u3); - /* Calculate relative "velocity". */ - collision_interpolateOnTriangle(v1, - cloth1->verts[collpair->ap1].tv, - cloth1->verts[collpair->ap2].tv, - cloth1->verts[collpair->ap3].tv, - w1, - w2, - w3); - collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, @@ -570,7 +760,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, vrel_t_pre, w1 * impulse); VECADDMUL(i2, vrel_t_pre, w2 * impulse); - VECADDMUL(i3, vrel_t_pre, w3 * impulse); + + if (!is_hair) { + VECADDMUL(i3, vrel_t_pre, w3 * impulse); + } } /* Apply velocity stopping impulse. */ @@ -582,8 +775,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i2, collpair->normal, w2 * impulse); cloth1->verts[collpair->ap2].impulse_count++; - VECADDMUL(i3, collpair->normal, w3 * impulse); - cloth1->verts[collpair->ap3].impulse_count++; + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); + cloth1->verts[collpair->ap3].impulse_count++; + } time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); @@ -603,7 +798,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, impulse); VECADDMUL(i2, collpair->normal, impulse); - VECADDMUL(i3, collpair->normal, impulse); + + if (!is_hair) { + VECADDMUL(i3, collpair->normal, impulse); + } } result = 1; @@ -621,11 +819,17 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, w1 * impulse); VECADDMUL(i2, collpair->normal, w2 * impulse); - VECADDMUL(i3, collpair->normal, w3 * impulse); + + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); + } cloth1->verts[collpair->ap1].impulse_count++; cloth1->verts[collpair->ap2].impulse_count++; - cloth1->verts[collpair->ap3].impulse_count++; + + if (!is_hair) { + cloth1->verts[collpair->ap3].impulse_count++; + } result = 1; } @@ -650,9 +854,11 @@ static int cloth_collision_response_static(ClothModifierData *clmd, cloth1->verts[collpair->ap2].impulse[j] = i2[j]; } - if (cloth1->verts[collpair->ap3].impulse_count > 0 && - ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) { - cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + if (!is_hair) { + if (cloth1->verts[collpair->ap3].impulse_count > 0 && + ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) { + cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + } } } } @@ -869,17 +1075,17 @@ static void cloth_collision(void *__restrict userdata, tri_b = &collmd->tri[data->overlap[index].indexB]; /* Compute distance and normal. */ - distance = compute_collision_point(verts1[tri_a->tri[0]].tx, - verts1[tri_a->tri[1]].tx, - verts1[tri_a->tri[2]].tx, - collmd->current_x[tri_b->tri[0]].co, - collmd->current_x[tri_b->tri[1]].co, - collmd->current_x[tri_b->tri[2]].co, - data->culling, - data->use_normal, - pa, - pb, - vect); + distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, + verts1[tri_a->tri[1]].tx, + verts1[tri_a->tri[2]].tx, + collmd->current_xnew[tri_b->tri[0]].co, + collmd->current_xnew[tri_b->tri[1]].co, + collmd->current_xnew[tri_b->tri[2]].co, + data->culling, + data->use_normal, + pa, + pb, + vect); if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { collpair[index].ap1 = tri_a->tri[0]; @@ -940,17 +1146,17 @@ static void cloth_selfcollision(void *__restrict userdata, } /* Compute distance and normal. */ - distance = compute_collision_point(verts1[tri_a->tri[0]].tx, - verts1[tri_a->tri[1]].tx, - verts1[tri_a->tri[2]].tx, - verts1[tri_b->tri[0]].tx, - verts1[tri_b->tri[1]].tx, - verts1[tri_b->tri[2]].tx, - false, - false, - pa, - pb, - vect); + distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, + verts1[tri_a->tri[1]].tx, + verts1[tri_a->tri[2]].tx, + verts1[tri_b->tri[0]].tx, + verts1[tri_b->tri[1]].tx, + verts1[tri_b->tri[2]].tx, + false, + false, + pa, + pb, + vect); if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { collpair[index].ap1 = tri_a->tri[0]; @@ -977,6 +1183,64 @@ static void cloth_selfcollision(void *__restrict userdata, } } +static void hair_collision(void *__restrict userdata, + const int index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + ColDetectData *data = (ColDetectData *)userdata; + + ClothModifierData *clmd = data->clmd; + CollisionModifierData *collmd = data->collmd; + CollPair *collpair = data->collisions; + const MVertTri *tri_coll; + const MEdge *edge_coll; + ClothVertex *verts1 = clmd->clothObject->verts; + float distance = 0.0f; + float epsilon1 = clmd->coll_parms->epsilon; + float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + float pa[3], pb[3], vect[3]; + + /* TODO: This is not efficient. Might be wise to instead build an array before iterating, to + * avoid walking the list every time. */ + edge_coll = &clmd->clothObject->edges[data->overlap[index].indexA]; + tri_coll = &collmd->tri[data->overlap[index].indexB]; + + /* Compute distance and normal. */ + distance = compute_collision_point_edge_tri(verts1[edge_coll->v1].tx, + verts1[edge_coll->v2].tx, + collmd->current_x[tri_coll->tri[0]].co, + collmd->current_x[tri_coll->tri[1]].co, + collmd->current_x[tri_coll->tri[2]].co, + data->culling, + data->use_normal, + pa, + pb, + vect); + + if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { + collpair[index].ap1 = edge_coll->v1; + collpair[index].ap2 = edge_coll->v2; + + collpair[index].bp1 = tri_coll->tri[0]; + collpair[index].bp2 = tri_coll->tri[1]; + collpair[index].bp3 = tri_coll->tri[2]; + + copy_v3_v3(collpair[index].pa, pa); + copy_v3_v3(collpair[index].pb, pb); + copy_v3_v3(collpair[index].vector, vect); + + normalize_v3_v3(collpair[index].normal, collpair[index].vector); + + collpair[index].distance = distance; + collpair[index].flag = 0; + + data->collided = true; + } + else { + collpair[index].flag = COLLISION_INACTIVE; + } +} + static void add_collision_object(ListBase *relations, Object *ob, int level, @@ -1117,7 +1381,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti col->ob = ob; col->collmd = cmd; /* make sure collider is properly set up */ - collision_move_object(cmd, 1.0, 0.0); + collision_move_object(cmd, 1.0, 0.0, true); BLI_addtail(cache, col); } } @@ -1142,6 +1406,7 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd, bool culling, bool use_normal) { + const bool is_hair = (clmd->hairdata != NULL); *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array"); ColDetectData data = { @@ -1157,7 +1422,8 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd, TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = true; - BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings); + BLI_task_parallel_range( + 0, numresult, &data, is_hair ? hair_collision : cloth_collision, &settings); return data.collided; } @@ -1302,8 +1568,14 @@ int cloth_bvh_collision( if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { bvhtree_update_from_cloth(clmd, false, false); - collobjs = BKE_collision_objects_create( - depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); + /* Enable self collision if this is a hair sim */ + const bool is_hair = (clmd->hairdata != NULL); + + collobjs = BKE_collision_objects_create(depsgraph, + is_hair ? NULL : ob, + clmd->coll_parms->group, + &numcollobj, + eModifierType_Collision); if (collobjs) { coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts"); @@ -1319,7 +1591,7 @@ int cloth_bvh_collision( } /* Move object to position (step) in time. */ - collision_move_object(collmd, step + dt, step); + collision_move_object(collmd, step + dt, step, false); overlap_obj[i] = BLI_bvhtree_overlap( cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL); @@ -1468,286 +1740,3 @@ void collision_get_collider_velocity(float vel_old[3], /* XXX assume constant velocity of the collider for now */ copy_v3_v3(vel_old, vel_new); } - -BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], - const float p2[3], - const float v0[3], - const float v1[3], - const float v2[3], - float r_nor[3], - float *r_lambda, - float r_w[3]) -{ - float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3]; - float nor_v0p2, nor_p1p2; - - sub_v3_v3v3(edge1, v1, v0); - sub_v3_v3v3(edge2, v2, v0); - cross_v3_v3v3(r_nor, edge1, edge2); - normalize_v3(r_nor); - - sub_v3_v3v3(v0p2, p2, v0); - nor_v0p2 = dot_v3v3(v0p2, r_nor); - madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2); - interp_weights_tri_v3(r_w, v0, v1, v2, p2face); - - sub_v3_v3v3(p1p2, p2, p1); - nor_p1p2 = dot_v3v3(p1p2, r_nor); - *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f); - - return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f; -} - -static CollPair *cloth_point_collpair(float p1[3], - const float p2[3], - const MVert *mverts, - int bp1, - int bp2, - int bp3, - int index_cloth, - int index_coll, - float epsilon, - CollPair *collpair) -{ - const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co; - float lambda /*, distance1 */, distance2; - float facenor[3], v1p1[3], v1p2[3]; - float w[3]; - - if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) { - return collpair; - } - - sub_v3_v3v3(v1p1, p1, co1); - // distance1 = dot_v3v3(v1p1, facenor); - sub_v3_v3v3(v1p2, p2, co1); - distance2 = dot_v3v3(v1p2, facenor); - // if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f)) - if (distance2 > epsilon) { - return collpair; - } - - collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */ - collpair->face2 = index_coll; - collpair->ap1 = index_cloth; - collpair->ap2 = collpair->ap3 = -1; /* unused */ - collpair->bp1 = bp1; - collpair->bp2 = bp2; - collpair->bp3 = bp3; - - /* note: using the second point here, which is - * the current updated position that needs to be corrected - */ - copy_v3_v3(collpair->pa, p2); - collpair->distance = distance2; - mul_v3_v3fl(collpair->vector, facenor, -distance2); - - interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w); - - copy_v3_v3(collpair->normal, facenor); - collpair->time = lambda; - collpair->flag = 0; - - collpair++; - return collpair; -} - -/* Determines collisions on overlap, - * collisions are written to collpair[i] and collision+number_collision_found is returned. */ -static CollPair *cloth_point_collision(ModifierData *md1, - ModifierData *md2, - BVHTreeOverlap *overlap, - float epsilon, - CollPair *collpair, - float UNUSED(dt)) -{ - ClothModifierData *clmd = (ClothModifierData *)md1; - CollisionModifierData *collmd = (CollisionModifierData *)md2; - /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */ - ClothVertex *vert = NULL; - const MVertTri *vt; - const MVert *mverts = collmd->current_x; - - vert = &clmd->clothObject->verts[overlap->indexA]; - vt = &collmd->tri[overlap->indexB]; - - collpair = cloth_point_collpair(vert->tx, - vert->x, - mverts, - vt->tri[0], - vt->tri[1], - vt->tri[2], - overlap->indexA, - overlap->indexB, - epsilon, - collpair); - - return collpair; -} - -static void cloth_points_objcollisions_nearcheck(ClothModifierData *clmd, - CollisionModifierData *collmd, - CollPair **collisions, - CollPair **collisions_index, - int numresult, - BVHTreeOverlap *overlap, - float epsilon, - double dt) -{ - int i; - - /* can return 2 collisions in total */ - *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array"); - *collisions_index = *collisions; - - for (i = 0; i < numresult; i++) { - *collisions_index = cloth_point_collision( - (ModifierData *)clmd, (ModifierData *)collmd, overlap + i, epsilon, *collisions_index, dt); - } -} - -void cloth_find_point_contacts(Depsgraph *depsgraph, - Object *ob, - ClothModifierData *clmd, - float step, - float dt, - ColliderContacts **r_collider_contacts, - int *r_totcolliders) -{ - Cloth *cloth = clmd->clothObject; - BVHTree *cloth_bvh; - unsigned int i = 0, mvert_num = 0; - ClothVertex *verts = NULL; - - ColliderContacts *collider_contacts; - - Object **collobjs = NULL; - unsigned int numcollobj = 0; - - verts = cloth->verts; - mvert_num = cloth->mvert_num; - - //////////////////////////////////////////////////////////// - // static collisions - //////////////////////////////////////////////////////////// - - /* Check we do have collision objects to test against, before doing anything else. */ - collobjs = BKE_collision_objects_create( - depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); - if (!collobjs) { - *r_collider_contacts = NULL; - *r_totcolliders = 0; - return; - } - - // create temporary cloth points bvh - cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6); - /* fill tree */ - for (i = 0; i < mvert_num; i++) { - float co[6]; - - copy_v3_v3(&co[0 * 3], verts[i].x); - copy_v3_v3(&co[1 * 3], verts[i].tx); - - BLI_bvhtree_insert(cloth_bvh, i, co, 2); - } - /* balance tree */ - BLI_bvhtree_balance(cloth_bvh); - - /* move object to position (step) in time */ - for (i = 0; i < numcollobj; i++) { - Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( - collob, eModifierType_Collision); - if (!collmd->bvhtree) { - continue; - } - - /* move object to position (step) in time */ - collision_move_object(collmd, step + dt, step); - } - - collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair"); - - // check all collision objects - for (i = 0; i < numcollobj; i++) { - ColliderContacts *ct = collider_contacts + i; - Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( - collob, eModifierType_Collision); - BVHTreeOverlap *overlap; - unsigned int result = 0; - float epsilon; - - ct->ob = collob; - ct->collmd = collmd; - ct->collisions = NULL; - ct->totcollisions = 0; - - if (!collmd->bvhtree) { - continue; - } - - /* search for overlapping collision pairs */ - overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL); - epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree); - - // go to next object if no overlap is there - if (result && overlap) { - CollPair *collisions_index; - - /* check if collisions really happen (costly near check) */ - cloth_points_objcollisions_nearcheck( - clmd, collmd, &ct->collisions, &collisions_index, result, overlap, epsilon, dt); - ct->totcollisions = (int)(collisions_index - ct->collisions); - - /* Resolve nearby collisions. */ -#if 0 - ret += cloth_points_objcollisions_resolve( - clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt); -#endif - } - - if (overlap) { - MEM_freeN(overlap); - } - } - - BKE_collision_objects_free(collobjs); - - BLI_bvhtree_free(cloth_bvh); - - //////////////////////////////////////////////////////////// - // update positions - // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] - //////////////////////////////////////////////////////////// - - // verts come from clmd - for (i = 0; i < mvert_num; i++) { - if (clmd->sim_parms->vgroup_mass > 0) { - if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { - continue; - } - } - - add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv); - } - //////////////////////////////////////////////////////////// - - *r_collider_contacts = collider_contacts; - *r_totcolliders = numcollobj; -} - -void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders) -{ - if (collider_contacts) { - int i; - for (i = 0; i < totcolliders; i++) { - ColliderContacts *ct = collider_contacts + i; - if (ct->collisions) { - MEM_freeN(ct->collisions); - } - } - MEM_freeN(collider_contacts); - } -} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c397fbcf115..a17a09297c5 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2062,36 +2062,21 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t bConstraintTarget *ct = targets->first; if (VALID_CONS_TARGET(ct)) { - if (data->mix_mode == TRANSLIKE_MIX_REPLACE) { - /* just copy the entire transform matrix of the target */ - copy_m4_m4(cob->matrix, ct->matrix); - } - else { - float old_loc[3], old_rot[3][3], old_size[3]; - float new_loc[3], new_rot[3][3], new_size[3]; - - /* Separate matrices so they can be combined in a way that avoids shear. */ - mat4_to_loc_rot_size(old_loc, old_rot, old_size, cob->matrix); - mat4_to_loc_rot_size(new_loc, new_rot, new_size, ct->matrix); - - switch (data->mix_mode) { - case TRANSLIKE_MIX_BEFORE: - mul_v3_m4v3(new_loc, ct->matrix, old_loc); - mul_m3_m3m3(new_rot, new_rot, old_rot); - mul_v3_v3(new_size, old_size); - break; + switch (data->mix_mode) { + case TRANSLIKE_MIX_REPLACE: + copy_m4_m4(cob->matrix, ct->matrix); + break; - case TRANSLIKE_MIX_AFTER: - mul_v3_m4v3(new_loc, cob->matrix, new_loc); - mul_m3_m3m3(new_rot, old_rot, new_rot); - mul_v3_v3(new_size, old_size); - break; + case TRANSLIKE_MIX_BEFORE: + mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix); + break; - default: - BLI_assert(false); - } + case TRANSLIKE_MIX_AFTER: + mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix); + break; - loc_rot_size_to_mat4(cob->matrix, new_loc, new_rot, new_size); + default: + BLI_assert(!"Unknown Copy Transforms mix mode"); } } } @@ -2555,6 +2540,9 @@ static void actcon_new_data(void *cdata) /* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */ data->type = 20; + + /* Set the mix mode to After Original with anti-shear scale handling. */ + data->mix_mode = ACTCON_MIX_AFTER; } static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -2695,18 +2683,28 @@ static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), } } -static void actcon_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets) +static void actcon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { + bActionConstraint *data = con->data; bConstraintTarget *ct = targets->first; if (VALID_CONS_TARGET(ct)) { - float temp[4][4]; + switch (data->mix_mode) { + case ACTCON_MIX_BEFORE: + mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix); + break; - /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix - * function has already taken care of everything else. - */ - copy_m4_m4(temp, cob->matrix); - mul_m4_m4m4(cob->matrix, temp, ct->matrix); + case ACTCON_MIX_AFTER: + mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix); + break; + + case ACTCON_MIX_AFTER_FULL: + mul_m4_m4m4(cob->matrix, cob->matrix, ct->matrix); + break; + + default: + BLI_assert(!"Unknown Action mix mode"); + } } } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 12bb7b573bd..4f0ff8bdcd3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1805,91 +1805,88 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp) } } else { - short dnr; - - /* bevel now in three parts, for proper vertex normals */ - /* part 1, back */ - - if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; - } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->flag = DL_BACK_CURVE; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - dangle = ((float)M_PI_2 / (dnr - 1)); - angle = -(nr - 1) * dangle; - - for (a = 0; a < nr; a++) { + /* The general case for nonzero extrusion or an incomplete loop. */ + dl = MEM_callocN(sizeof(DispList), "makebevelcurve"); + if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { + /* The full loop. */ + nr = 4 * cu->bevresol + 6; + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + } + else if ((cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) { + /* Half the loop. */ + nr = 2 * (cu->bevresol + 1) + ((cu->ext1 == 0.0f) ? 1 : 2); + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + } + else { + /* One quarter of the loop (just front or back). */ + nr = (cu->ext1 == 0.0f) ? cu->bevresol + 2 : cu->bevresol + 3; + dl->flag = (cu->flag & CU_FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE; + } + + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve"); + BLI_addtail(disp, dl); + /* Use a different type depending on whether the loop is complete or not. */ + dl->type = ((cu->flag & (CU_FRONT | CU_BACK)) == 0) ? DL_POLY : DL_SEGM; + dl->parts = 1; + dl->nr = nr; + + fp = dl->verts; + dangle = (float)M_PI_2 / (cu->bevresol + 1); + angle = 0.0; + + /* Build the back section. */ + if (cu->flag & CU_BACK || !(cu->flag & CU_FRONT)) { + angle = (float)M_PI_2 * 3.0f; + for (a = 0; a < cu->bevresol + 2; a++) { fp[0] = 0.0; fp[1] = (float)(cosf(angle) * (cu->ext2)); fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; angle += dangle; fp += 3; } + if ((cu->ext1 != 0.0f) && !(cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) { + /* Add the extrusion if we're only building the back. */ + fp[0] = 0.0; + fp[1] = cu->ext2; + fp[2] = cu->ext1; + } } - /* part 2, sidefaces */ - if (cu->ext1 != 0.0f) { - nr = 2; - - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->nr = nr; - - fp = dl->verts; - fp[1] = cu->ext2; - fp[2] = -cu->ext1; - fp[4] = cu->ext2; - fp[5] = cu->ext1; - - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - dl = MEM_dupallocN(dl); - dl->verts = MEM_dupallocN(dl->verts); - BLI_addtail(disp, dl); - - fp = dl->verts; - fp[1] = -fp[1]; - fp[2] = -fp[2]; - fp[4] = -fp[4]; - fp[5] = -fp[5]; + /* Build the front section. */ + if (cu->flag & CU_FRONT || !(cu->flag & CU_BACK)) { + if ((cu->ext1 != 0.0f) && !(cu->flag & CU_BACK) && (cu->flag & CU_FRONT)) { + /* Add the extrusion if we're only building the back. */ + fp[0] = 0.0; + fp[1] = cu->ext2; + fp[2] = -cu->ext1; + fp += 3; + } + /* Don't duplicate the last back vertex. */ + angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0; + for (a = 0; a < cu->bevresol + 2; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; } } - /* part 3, front */ - if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; + /* Build the other half only if we're building the full loop. */ + if (!(cu->flag & (CU_FRONT | CU_BACK))) { + for (a = 0; a < cu->bevresol + 1; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->flag = DL_FRONT_CURVE; - dl->parts = 1; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - angle = 0.0; - dangle = ((float)M_PI_2 / (dnr - 1)); - for (a = 0; a < nr; a++) { + angle = (float)M_PI; + for (a = 0; a < cu->bevresol + 1; a++) { fp[0] = 0.0; fp[1] = (float)(cosf(angle) * (cu->ext2)); - fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; angle += dangle; fp += 3; } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index a964cab3fa5..79dcdd15bf7 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -345,7 +345,7 @@ void defvert_normalize_lock_single(MDeformVert *dvert, else if (dvert->totweight == 1) { MDeformWeight *dw = dvert->dw; if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) { - if (def_nr_lock != 0) { + if (def_nr_lock != dw->def_nr) { dw->weight = 1.0f; } } diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c new file mode 100644 index 00000000000..4ac8d47feba --- /dev/null +++ b/source/blender/blenkernel/intern/displist_tangent.c @@ -0,0 +1,279 @@ +/* + * 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. + */ + +/** \file + * \ingroup bke + */ + +#include "BLI_math.h" +#include "BLI_task.h" + +#include "BKE_displist.h" +#include "BKE_displist_tangent.h" + +#include "MEM_guardedalloc.h" + +/* interface */ +#include "mikktspace.h" + +typedef struct { + const DispList *dl; + float (*tangent)[4]; /* destination */ + /** Face normal for flat shading. */ + float (*fnormals)[3]; + /** Use by surfaces. Size of the surface in faces. */ + int u_len, v_len; +} SGLSLDisplistToTangent; + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name DL_INDEX3 tangents + * \{ */ + +static int dl3_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + + return dlt->dl->parts; +} + +static int dl3_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ + UNUSED_VARS(pContext, face_num); + + return 3; +} + +static void dl3_ts_GetPosition(const SMikkTSpaceContext *pContext, + float r_co[3], + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + const float(*verts)[3] = (float(*)[3])dlt->dl->verts; + const int(*idx)[3] = (int(*)[3])dlt->dl->index; + + copy_v3_v3(r_co, verts[idx[face_num][vert_index]]); +} + +static void dl3_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext, + float r_uv[2], + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + const int(*idx)[3] = (int(*)[3])dlt->dl->index; + + r_uv[0] = idx[face_num][vert_index] / (float)(dlt->dl->nr - 1); + r_uv[1] = 0.0f; +} + +static void dl3_ts_GetNormal(const SMikkTSpaceContext *pContext, + float r_no[3], + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + UNUSED_VARS(face_num, vert_index); + + copy_v3_v3(r_no, dlt->dl->nors); +} + +static void dl3_ts_SetTSpace(const SMikkTSpaceContext *pContext, + const float fvTangent[3], + const float fSign, + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + UNUSED_VARS(face_num, vert_index); + + copy_v3_v3(dlt->tangent[0], fvTangent); + dlt->tangent[0][3] = fSign; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name DL_SURF tangents + * \{ */ + +static int dlsurf_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + + return dlt->v_len * dlt->u_len; +} + +static int dlsurf_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ + UNUSED_VARS(pContext, face_num); + + return 4; +} + +static int face_to_vert_index(SGLSLDisplistToTangent *dlt, + const int face_num, + const int vert_index) +{ + int u = face_num % dlt->u_len; + int v = face_num / dlt->u_len; + + if (vert_index == 0) { + u += 1; + } + else if (vert_index == 1) { + u += 1; + v += 1; + } + else if (vert_index == 2) { + v += 1; + } + + /* Cyclic correction. */ + u = u % dlt->dl->nr; + v = v % dlt->dl->parts; + + return v * dlt->dl->nr + u; +} + +static void dlsurf_ts_GetPosition(const SMikkTSpaceContext *pContext, + float r_co[3], + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + const float(*verts)[3] = (float(*)[3])dlt->dl->verts; + + copy_v3_v3(r_co, verts[face_to_vert_index(dlt, face_num, vert_index)]); +} + +static void dlsurf_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext, + float r_uv[2], + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + + int idx = face_to_vert_index(dlt, face_num, vert_index); + + /* Note: For some reason the shading U and V are swapped compared to the + * one described in the surface format. */ + r_uv[0] = (idx / dlt->dl->nr) / (float)(dlt->v_len); + r_uv[1] = (idx % dlt->dl->nr) / (float)(dlt->u_len); + + if (r_uv[0] == 0.0f && ELEM(vert_index, 1, 2)) { + r_uv[0] = 1.0f; + } + if (r_uv[1] == 0.0f && ELEM(vert_index, 0, 1)) { + r_uv[1] = 1.0f; + } +} + +static void dlsurf_ts_GetNormal(const SMikkTSpaceContext *pContext, + float r_no[3], + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + const float(*nors)[3] = (float(*)[3])dlt->dl->nors; + + if (dlt->fnormals) { + copy_v3_v3(r_no, dlt->fnormals[face_num]); + } + else { + copy_v3_v3(r_no, nors[face_to_vert_index(dlt, face_num, vert_index)]); + } +} + +static void dlsurf_ts_SetTSpace(const SMikkTSpaceContext *pContext, + const float fvTangent[3], + const float fSign, + const int face_num, + const int vert_index) +{ + SGLSLDisplistToTangent *dlt = pContext->m_pUserData; + UNUSED_VARS(face_num, vert_index); + + float *r_tan = dlt->tangent[face_num * 4 + vert_index]; + copy_v3_v3(r_tan, fvTangent); + r_tan[3] = fSign; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Entry point + * \{ */ + +void BKE_displist_tangent_calc(const DispList *dl, float (*fnormals)[3], float (**r_tangent)[4]) +{ + if (dl->type == DL_INDEX3) { + /* INDEX3 have only one tangent so we don't need actual allocation. */ + BLI_assert(*r_tangent != NULL); + + SGLSLDisplistToTangent mesh2tangent = { + .tangent = *r_tangent, + .dl = dl, + }; + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + sContext.m_pUserData = &mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = dl3_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = dl3_ts_GetNumVertsOfFace; + sInterface.m_getPosition = dl3_ts_GetPosition; + sInterface.m_getTexCoord = dl3_ts_GetTextureCoordinate; + sInterface.m_getNormal = dl3_ts_GetNormal; + sInterface.m_setTSpaceBasic = dl3_ts_SetTSpace; + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } + else if (dl->type == DL_SURF) { + SGLSLDisplistToTangent mesh2tangent = { + .dl = dl, + .u_len = dl->nr - ((dl->flag & DL_CYCL_U) ? 0 : 1), + .v_len = dl->parts - ((dl->flag & DL_CYCL_V) ? 0 : 1), + .fnormals = fnormals, + }; + + int loop_len = mesh2tangent.u_len * mesh2tangent.v_len * 4; + + if (*r_tangent == NULL) { + *r_tangent = MEM_mallocN(sizeof(float[4]) * loop_len, "displist tangents"); + } + mesh2tangent.tangent = *r_tangent; + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + sContext.m_pUserData = &mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = dlsurf_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = dlsurf_ts_GetNumVertsOfFace; + sInterface.m_getPosition = dlsurf_ts_GetPosition; + sInterface.m_getTexCoord = dlsurf_ts_GetTextureCoordinate; + sInterface.m_getNormal = dlsurf_ts_GetNormal; + sInterface.m_setTSpaceBasic = dlsurf_ts_SetTSpace; + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } + else { + /* Unsupported. */ + BLI_assert(0); + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 74a523bfbdc..a70e5b67a15 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -6285,7 +6285,11 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph, PART_FLUID_SPRAY, PART_FLUID_BUBBLE, PART_FLUID_FOAM, - PART_FLUID_TRACER) && + PART_FLUID_TRACER, + PART_FLUID_SPRAYFOAM, + PART_FLUID_SPRAYBUBBLE, + PART_FLUID_FOAMBUBBLE, + PART_FLUID_SPRAYFOAMBUBBLE) && psys_check_enabled(brushObj, brush->psys, for_render)) { /* Paint a particle system */ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c deleted file mode 100644 index 2df3d2f0fe9..00000000000 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * 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) 2005 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup bke - * - * basic design: - * - * the bmesh derivedmesh exposes the mesh as triangles. it stores pointers - * to three loops per triangle. the derivedmesh stores a cache of tessellations - * for each face. this cache will smartly update as needed (though at first - * it'll simply be more brute force). keeping track of face/edge counts may - * be a small problem. - * - * this won't be the most efficient thing, considering that internal edges and - * faces of tessellations are exposed. looking up an edge by index in particular - * is likely to be a little slow. - */ - -#include "atomic_ops.h" - -#include "BLI_math.h" -#include "BLI_jitter_2d.h" -#include "BLI_bitmap.h" -#include "BLI_task.h" - -#include "BKE_cdderivedmesh.h" -#include "BKE_deform.h" -#include "BKE_mesh.h" -#include "BKE_mesh_iterators.h" -#include "BKE_editmesh.h" -#include "BKE_editmesh_bvh.h" -#include "BKE_editmesh_cache.h" -#include "BKE_editmesh_tangent.h" - -#include "DNA_scene_types.h" -#include "DNA_object_types.h" -#include "DNA_mesh_types.h" - -#include "MEM_guardedalloc.h" - -/* -------------------------------------------------------------------- */ -/* StatVis Functions */ - -static void axis_from_enum_v3(float v[3], const char axis) -{ - zero_v3(v); - if (axis < 3) { - v[axis] = 1.0f; - } - else { - v[axis - 3] = -1.0f; - } -} - -static void statvis_calc_overhang(BMEditMesh *em, - const float (*polyNos)[3], - /* values for calculating */ - const float min, - const float max, - const char axis, - /* result */ - unsigned char (*r_face_colors)[4]) -{ - BMIter iter; - BMesh *bm = em->bm; - BMFace *f; - float dir[3]; - int index; - const float minmax_irange = 1.0f / (max - min); - bool is_max; - - /* fallback */ - unsigned char col_fallback[4] = {64, 64, 64, 255}; /* gray */ - unsigned char col_fallback_max[4] = {0, 0, 0, 255}; /* max color */ - - BLI_assert(min <= max); - - axis_from_enum_v3(dir, axis); - - if (LIKELY(em->ob)) { - mul_transposed_mat3_m4_v3(em->ob->obmat, dir); - normalize_v3(dir); - } - - /* fallback max */ - { - float fcol[3]; - BKE_defvert_weight_to_rgb(fcol, 1.0f); - rgb_float_to_uchar(col_fallback_max, fcol); - } - - /* now convert into global space */ - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) { - float fac = angle_normalized_v3v3(polyNos ? polyNos[index] : f->no, dir) / (float)M_PI; - - /* remap */ - if ((is_max = (fac <= max)) && (fac >= min)) { - float fcol[3]; - fac = (fac - min) * minmax_irange; - fac = 1.0f - fac; - CLAMP(fac, 0.0f, 1.0f); - BKE_defvert_weight_to_rgb(fcol, fac); - rgb_float_to_uchar(r_face_colors[index], fcol); - } - else { - const unsigned char *fallback = is_max ? col_fallback_max : col_fallback; - copy_v4_v4_uchar(r_face_colors[index], fallback); - } - } -} - -/* so we can use jitter values for face interpolation */ -static void uv_from_jitter_v2(float uv[2]) -{ - uv[0] += 0.5f; - uv[1] += 0.5f; - if (uv[0] + uv[1] > 1.0f) { - uv[0] = 1.0f - uv[0]; - uv[1] = 1.0f - uv[1]; - } - - CLAMP(uv[0], 0.0f, 1.0f); - CLAMP(uv[1], 0.0f, 1.0f); -} - -static void statvis_calc_thickness(BMEditMesh *em, - const float (*vertexCos)[3], - /* values for calculating */ - const float min, - const float max, - const int samples, - /* result */ - unsigned char (*r_face_colors)[4]) -{ - const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */ - float *face_dists = (float *)r_face_colors; /* cheating */ - const bool use_jit = samples < 32; - float jit_ofs[32][2]; - BMesh *bm = em->bm; - const int tottri = em->tottri; - const float minmax_irange = 1.0f / (max - min); - int i; - - struct BMLoop *(*looptris)[3] = em->looptris; - - /* fallback */ - const unsigned char col_fallback[4] = {64, 64, 64, 255}; - - struct BMBVHTree *bmtree; - - BLI_assert(min <= max); - - copy_vn_fl(face_dists, em->bm->totface, max); - - if (use_jit) { - int j; - BLI_assert(samples < 32); - BLI_jitter_init(jit_ofs, samples); - - for (j = 0; j < samples; j++) { - uv_from_jitter_v2(jit_ofs[j]); - } - } - - BM_mesh_elem_index_ensure(bm, BM_FACE); - if (vertexCos) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false); - - for (i = 0; i < tottri; i++) { - BMFace *f_hit; - BMLoop **ltri = looptris[i]; - const int index = BM_elem_index_get(ltri[0]->f); - const float *cos[3]; - float ray_co[3]; - float ray_no[3]; - - if (vertexCos) { - cos[0] = vertexCos[BM_elem_index_get(ltri[0]->v)]; - cos[1] = vertexCos[BM_elem_index_get(ltri[1]->v)]; - cos[2] = vertexCos[BM_elem_index_get(ltri[2]->v)]; - } - else { - cos[0] = ltri[0]->v->co; - cos[1] = ltri[1]->v->co; - cos[2] = ltri[2]->v->co; - } - - normal_tri_v3(ray_no, cos[2], cos[1], cos[0]); - -#define FACE_RAY_TEST_ANGLE \ - f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL); \ - if (f_hit && dist < face_dists[index]) { \ - float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); \ - angle_fac = 1.0f - angle_fac; \ - angle_fac = angle_fac * angle_fac * angle_fac; \ - angle_fac = 1.0f - angle_fac; \ - dist /= angle_fac; \ - if (dist < face_dists[index]) { \ - face_dists[index] = dist; \ - } \ - } \ - (void)0 - - if (use_jit) { - int j; - for (j = 0; j < samples; j++) { - float dist = face_dists[index]; - interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]); - madd_v3_v3fl(ray_co, ray_no, eps_offset); - - FACE_RAY_TEST_ANGLE; - } - } - else { - float dist = face_dists[index]; - mid_v3_v3v3v3(ray_co, cos[0], cos[1], cos[2]); - madd_v3_v3fl(ray_co, ray_no, eps_offset); - - FACE_RAY_TEST_ANGLE; - } - } - - BKE_bmbvh_free(bmtree); - - /* convert floats into color! */ - for (i = 0; i < bm->totface; i++) { - float fac = face_dists[i]; - - /* important not '<=' */ - if (fac < max) { - float fcol[3]; - fac = (fac - min) * minmax_irange; - fac = 1.0f - fac; - CLAMP(fac, 0.0f, 1.0f); - BKE_defvert_weight_to_rgb(fcol, fac); - rgb_float_to_uchar(r_face_colors[i], fcol); - } - else { - copy_v4_v4_uchar(r_face_colors[i], col_fallback); - } - } -} - -static void statvis_calc_intersect(BMEditMesh *em, - const float (*vertexCos)[3], - /* result */ - unsigned char (*r_face_colors)[4]) -{ - BMesh *bm = em->bm; - int i; - - /* fallback */ - // const char col_fallback[4] = {64, 64, 64, 255}; - float fcol[3]; - unsigned char col[3]; - - struct BMBVHTree *bmtree; - BVHTreeOverlap *overlap; - unsigned int overlap_len; - - memset(r_face_colors, 64, sizeof(int) * em->bm->totface); - - BM_mesh_elem_index_ensure(bm, BM_FACE); - if (vertexCos) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false); - - overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len); - - /* same for all faces */ - BKE_defvert_weight_to_rgb(fcol, 1.0f); - rgb_float_to_uchar(col, fcol); - - if (overlap) { - for (i = 0; i < overlap_len; i++) { - BMFace *f_hit_pair[2] = { - em->looptris[overlap[i].indexA][0]->f, - em->looptris[overlap[i].indexB][0]->f, - }; - int j; - - for (j = 0; j < 2; j++) { - BMFace *f_hit = f_hit_pair[j]; - int index; - - index = BM_elem_index_get(f_hit); - - copy_v3_v3_uchar(r_face_colors[index], col); - } - } - MEM_freeN(overlap); - } - - BKE_bmbvh_free(bmtree); -} - -static void statvis_calc_distort(BMEditMesh *em, - const float (*vertexCos)[3], - const float (*polyNos)[3], - /* values for calculating */ - const float min, - const float max, - /* result */ - unsigned char (*r_face_colors)[4]) -{ - BMIter iter; - BMesh *bm = em->bm; - BMFace *f; - const float *f_no; - int index; - const float minmax_irange = 1.0f / (max - min); - - /* fallback */ - const unsigned char col_fallback[4] = {64, 64, 64, 255}; - - /* now convert into global space */ - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) { - float fac; - - if (f->len == 3) { - fac = -1.0f; - } - else { - BMLoop *l_iter, *l_first; - if (vertexCos) { - f_no = polyNos[index]; - } - else { - f_no = f->no; - } - - fac = 0.0f; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - float no_corner[3]; - if (vertexCos) { - normal_tri_v3(no_corner, - vertexCos[BM_elem_index_get(l_iter->prev->v)], - vertexCos[BM_elem_index_get(l_iter->v)], - vertexCos[BM_elem_index_get(l_iter->next->v)]); - } - else { - BM_loop_calc_face_normal_safe(l_iter, no_corner); - } - /* simple way to detect (what is most likely) concave */ - if (dot_v3v3(f_no, no_corner) < 0.0f) { - negate_v3(no_corner); - } - fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner)); - } while ((l_iter = l_iter->next) != l_first); - fac *= 2.0f; - } - - /* remap */ - if (fac >= min) { - float fcol[3]; - fac = (fac - min) * minmax_irange; - CLAMP(fac, 0.0f, 1.0f); - BKE_defvert_weight_to_rgb(fcol, fac); - rgb_float_to_uchar(r_face_colors[index], fcol); - } - else { - copy_v4_v4_uchar(r_face_colors[index], col_fallback); - } - } -} - -static void statvis_calc_sharp(BMEditMesh *em, - const float (*vertexCos)[3], - /* values for calculating */ - const float min, - const float max, - /* result */ - unsigned char (*r_vert_colors)[4]) -{ - float *vert_angles = (float *)r_vert_colors; /* cheating */ - BMIter iter; - BMesh *bm = em->bm; - BMEdge *e; - // float f_no[3]; - const float minmax_irange = 1.0f / (max - min); - int i; - - /* fallback */ - const unsigned char col_fallback[4] = {64, 64, 64, 255}; - - (void)vertexCos; /* TODO */ - - copy_vn_fl(vert_angles, em->bm->totvert, -M_PI); - - /* first assign float values to verts */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - float angle = BM_edge_calc_face_angle_signed(e); - float *col1 = &vert_angles[BM_elem_index_get(e->v1)]; - float *col2 = &vert_angles[BM_elem_index_get(e->v2)]; - *col1 = max_ff(*col1, angle); - *col2 = max_ff(*col2, angle); - } - - /* convert floats into color! */ - for (i = 0; i < bm->totvert; i++) { - float fac = vert_angles[i]; - - /* important not '<=' */ - if (fac > min) { - float fcol[3]; - fac = (fac - min) * minmax_irange; - CLAMP(fac, 0.0f, 1.0f); - BKE_defvert_weight_to_rgb(fcol, fac); - rgb_float_to_uchar(r_vert_colors[i], fcol); - } - else { - copy_v4_v4_uchar(r_vert_colors[i], col_fallback); - } - } -} - -void BKE_editmesh_statvis_calc(BMEditMesh *em, EditMeshData *emd, const MeshStatVis *statvis) -{ - switch (statvis->type) { - case SCE_STATVIS_OVERHANG: { - BKE_editmesh_color_ensure(em, BM_FACE); - statvis_calc_overhang(em, - emd ? emd->polyNos : NULL, - statvis->overhang_min / (float)M_PI, - statvis->overhang_max / (float)M_PI, - statvis->overhang_axis, - em->derivedFaceColor); - break; - } - case SCE_STATVIS_THICKNESS: { - const float scale = 1.0f / mat4_to_scale(em->ob->obmat); - BKE_editmesh_color_ensure(em, BM_FACE); - statvis_calc_thickness(em, - emd ? emd->vertexCos : NULL, - statvis->thickness_min * scale, - statvis->thickness_max * scale, - statvis->thickness_samples, - em->derivedFaceColor); - break; - } - case SCE_STATVIS_INTERSECT: { - BKE_editmesh_color_ensure(em, BM_FACE); - statvis_calc_intersect(em, emd ? emd->vertexCos : NULL, em->derivedFaceColor); - break; - } - case SCE_STATVIS_DISTORT: { - BKE_editmesh_color_ensure(em, BM_FACE); - - if (emd) { - BKE_editmesh_cache_ensure_poly_normals(em, emd); - } - - statvis_calc_distort(em, - emd ? emd->vertexCos : NULL, - emd ? emd->polyNos : NULL, - statvis->distort_min, - statvis->distort_max, - em->derivedFaceColor); - break; - } - case SCE_STATVIS_SHARP: { - BKE_editmesh_color_ensure(em, BM_VERT); - statvis_calc_sharp(em, - emd ? emd->vertexCos : NULL, - statvis->sharp_min, - statvis->sharp_max, - /* in this case they are vertex colors */ - em->derivedVertColor); - break; - } - } -} - -/* -------------------------------------------------------------------- */ -/* Editmesh Vert Coords */ - -struct CageUserData { - int totvert; - float (*cos_cage)[3]; - BLI_bitmap *visit_bitmap; -}; - -static void cage_mapped_verts_callback(void *userData, - int index, - const float co[3], - const float UNUSED(no_f[3]), - const short UNUSED(no_s[3])) -{ - struct CageUserData *data = userData; - - if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) { - BLI_BITMAP_ENABLE(data->visit_bitmap, index); - copy_v3_v3(data->cos_cage[index], co); - } -} - -float (*BKE_editmesh_vert_coords_alloc( - struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_vert_len))[3] -{ - Mesh *cage; - BLI_bitmap *visit_bitmap; - struct CageUserData data; - float(*cos_cage)[3]; - - cage = editbmesh_get_eval_cage(depsgraph, scene, em->ob, em, &CD_MASK_BAREMESH); - cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage"); - - /* when initializing cage verts, we only want the first cage coordinate for each vertex, - * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */ - visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__); - - data.totvert = em->bm->totvert; - data.cos_cage = cos_cage; - data.visit_bitmap = visit_bitmap; - - BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP); - - MEM_freeN(visit_bitmap); - - if (r_vert_len) { - *r_vert_len = em->bm->totvert; - } - - return cos_cage; -} diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index b135574a650..9b67a4fb925 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -33,6 +33,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" #include "BKE_object.h" BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate) @@ -55,11 +56,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em) em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL; em_copy->bb_cage = NULL; - em_copy->derivedVertColor = NULL; - em_copy->derivedVertColorLen = 0; - em_copy->derivedFaceColor = NULL; - em_copy->derivedFaceColorLen = 0; - em_copy->bm = BM_mesh_copy(em->bm); /* The tessellation is NOT calculated on the copy here, @@ -163,8 +159,6 @@ void BKE_editmesh_free(BMEditMesh *em) { BKE_editmesh_free_derivedmesh(em); - BKE_editmesh_color_free(em); - if (em->looptris) { MEM_freeN(em->looptris); } @@ -174,44 +168,57 @@ void BKE_editmesh_free(BMEditMesh *em) } } -void BKE_editmesh_color_free(BMEditMesh *em) +struct CageUserData { + int totvert; + float (*cos_cage)[3]; + BLI_bitmap *visit_bitmap; +}; + +static void cage_mapped_verts_callback(void *userData, + int index, + const float co[3], + const float UNUSED(no_f[3]), + const short UNUSED(no_s[3])) { - if (em->derivedVertColor) { - MEM_freeN(em->derivedVertColor); - } - if (em->derivedFaceColor) { - MEM_freeN(em->derivedFaceColor); - } - em->derivedVertColor = NULL; - em->derivedFaceColor = NULL; + struct CageUserData *data = userData; - em->derivedVertColorLen = 0; - em->derivedFaceColorLen = 0; + if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) { + BLI_BITMAP_ENABLE(data->visit_bitmap, index); + copy_v3_v3(data->cos_cage[index], co); + } } -void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype) +float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph, + BMEditMesh *em, + struct Scene *scene, + Object *ob, + int *r_vert_len))[3] { - switch (htype) { - case BM_VERT: - if (em->derivedVertColorLen != em->bm->totvert) { - BKE_editmesh_color_free(em); - em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert, - __func__); - em->derivedVertColorLen = em->bm->totvert; - } - break; - case BM_FACE: - if (em->derivedFaceColorLen != em->bm->totface) { - BKE_editmesh_color_free(em); - em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface, - __func__); - em->derivedFaceColorLen = em->bm->totface; - } - break; - default: - BLI_assert(0); - break; + Mesh *cage; + BLI_bitmap *visit_bitmap; + struct CageUserData data; + float(*cos_cage)[3]; + + cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH); + cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage"); + + /* when initializing cage verts, we only want the first cage coordinate for each vertex, + * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */ + visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__); + + data.totvert = em->bm->totvert; + data.cos_cage = cos_cage; + data.visit_bitmap = visit_bitmap; + + BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP); + + MEM_freeN(visit_bitmap); + + if (r_vert_len) { + *r_vert_len = em->bm->totvert; } + + return cos_cage; } float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3] @@ -219,7 +226,7 @@ float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3] return BM_mesh_vert_coords_alloc(em->bm, r_vert_len); } -void BKE_editmesh_lnorspace_update(BMEditMesh *em) +void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me) { BMesh *bm = em->bm; @@ -231,7 +238,6 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em) * with related sharp edges (and hence autosmooth is 'lost'). * Not sure how critical this is, and how to fix that issue? */ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { - Mesh *me = em->ob->data; if (me->flag & ME_AUTOSMOOTH) { BM_edges_sharp_from_angle_set(bm, me->smoothresh); } @@ -241,12 +247,11 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em) } /* If autosmooth not already set, set it */ -void BKE_editmesh_ensure_autosmooth(BMEditMesh *em) +void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me) { - Mesh *me = em->ob->data; if (!(me->flag & ME_AUTOSMOOTH)) { me->flag |= ME_AUTOSMOOTH; - BKE_editmesh_lnorspace_update(em); + BKE_editmesh_lnorspace_update(em, me); } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 3876033eaaa..833b8409f7d 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1171,16 +1171,16 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha */ void sort_time_fcurve(FCurve *fcu) { - bool ok = true; /* keep adjusting order of beztriples until nothing moves (bubble-sort) */ - while (ok) { - ok = 0; + if (fcu->bezt) { + BezTriple *bezt; + uint a; - /* currently, will only be needed when there are beztriples */ - if (fcu->bezt) { - BezTriple *bezt; - unsigned int a; + bool ok = true; + while (ok) { + ok = 0; + /* currently, will only be needed when there are beztriples */ /* loop over ALL points to adjust position in array and recalculate handles */ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { @@ -1191,20 +1191,22 @@ void sort_time_fcurve(FCurve *fcu) SWAP(BezTriple, *bezt, *(bezt + 1)); ok = 1; } - - /* if either one of both of the points exceeds crosses over the keyframe time... */ - if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) { - /* swap handles if they have switched sides for some reason */ - swap_v2_v2(bezt->vec[0], bezt->vec[2]); - } - else { - /* clamp handles */ - CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]); - CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]); - } } } } + + for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { + /* if either one of both of the points exceeds crosses over the keyframe time... */ + if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) { + /* swap handles if they have switched sides for some reason */ + swap_v2_v2(bezt->vec[0], bezt->vec[2]); + } + else { + /* clamp handles */ + CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]); + CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]); + } + } } } @@ -2140,20 +2142,34 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) /* Driver Expression Evaluation --------------- */ +/* Index constants for the expression parameter array. */ +enum { + /* Index of the 'frame' variable. */ + VAR_INDEX_FRAME = 0, + /* Index of the first user-defined driver variable. */ + VAR_INDEX_CUSTOM +}; + static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver) { /* Prepare parameter names. */ int names_len = BLI_listbase_count(&driver->variables); - const char **names = BLI_array_alloca(names, names_len + 1); - int i = 0; + const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM); + int i = VAR_INDEX_CUSTOM; - names[i++] = "frame"; + names[VAR_INDEX_FRAME] = "frame"; for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) { names[i++] = dvar->name; } - return BLI_expr_pylike_parse(driver->expression, names, names_len + 1); + return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM); +} + +static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr) +{ + /* Check if the 'frame' parameter is actually used. */ + return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME); } static bool driver_evaluate_simple_expr(ChannelDriver *driver, @@ -2163,10 +2179,10 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver, { /* Prepare parameter values. */ int vars_len = BLI_listbase_count(&driver->variables); - double *vars = BLI_array_alloca(vars, vars_len + 1); - int i = 0; + double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM); + int i = VAR_INDEX_CUSTOM; - vars[i++] = time; + vars[VAR_INDEX_FRAME] = time; for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) { vars[i++] = driver_get_variable_value(driver, dvar); @@ -2174,7 +2190,8 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver, /* Evaluate expression. */ double result_val; - eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val); + eExprPyLike_EvalStatus status = BLI_expr_pylike_eval( + expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val); const char *message; switch (status) { @@ -2243,6 +2260,44 @@ bool BKE_driver_has_simple_expression(ChannelDriver *driver) return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple); } +/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive + * time dependencies nor special exceptions in the depsgraph evaluation. */ +static bool python_driver_exression_depends_on_time(const char *expression) +{ + if (expression[0] == '\0') { + /* Empty expression depends on nothing. */ + return false; + } + if (strchr(expression, '(') != NULL) { + /* Function calls are considered dependent on a time. */ + return true; + } + if (strstr(expression, "frame") != NULL) { + /* Variable `frame` depends on time. */ + /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */ + return true; + } + /* Possible indirect time relation s should be handled via variable targets. */ + return false; +} + +/* Check if the expression in the driver may depend on the current frame. */ +bool BKE_driver_expression_depends_on_time(ChannelDriver *driver) +{ + if (driver->type != DRIVER_TYPE_PYTHON) { + return false; + } + + if (BKE_driver_has_simple_expression(driver)) { + /* Simple expressions can be checked exactly. */ + return driver_check_simple_expr_depends_on_time(driver->expr_simple); + } + else { + /* Otherwise, heuristically scan the expression string for certain patterns. */ + return python_driver_exression_depends_on_time(driver->expression); + } +} + /* Reset cached compiled expression data */ void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed, diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 96be64dea75..f19137bf796 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -85,6 +85,9 @@ /** Time step default value for nice appearance. */ #define DT_DEFAULT 0.1f +/** Max value for phi initialization */ +#define PHI_MAX 9999.0f + static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need_lock); #ifdef WITH_FLUID @@ -330,22 +333,22 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) { char temp_dir[FILE_MAX]; int flags = mds->cache_flag; - - /* Ensure cache directory is not relative */ const char *relbase = modifier_path_relbase_from_global(ob); - BLI_path_abs(mds->cache_directory, relbase); if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) { flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } @@ -354,6 +357,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) { flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } @@ -362,6 +366,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) { flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } @@ -372,6 +377,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) FLUID_DOMAIN_OUTDATED_PARTICLES); BLI_path_join( temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } @@ -381,6 +387,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) { flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL); + BLI_path_abs(temp_dir, relbase); if (BLI_exists(temp_dir)) { BLI_delete(temp_dir, true, true); } @@ -612,7 +619,7 @@ typedef struct ObstaclesFromDMData { bool has_velocity; float *vert_vel; float *velocity_x, *velocity_y, *velocity_z; - int *num_objects; + float *num_objects; float *distances_map; } ObstaclesFromDMData; @@ -623,10 +630,10 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata, ObstaclesFromDMData *data = userdata; FluidDomainSettings *mds = data->mds; - /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */ - const float surface_distance = 2.0f; // 0.867f; - /* Note: Use larger surface distance to cover larger area with obvel. Manta will use these obvels - * and extrapolate them (inside and outside obstacle) */ + /* Distance between two opposing vertices in a unit cube. + * I.e. the unit cube diagonal or sqrt(3). + * This value is our nearest neighbour search distance. */ + const float surface_distance = 1.732; for (int x = mds->res_min[0]; x < mds->res_max[0]; x++) { for (int y = mds->res_min[1]; y < mds->res_max[1]; y++) { @@ -640,7 +647,7 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata, surface_distance; /* find_nearest uses squared distance */ bool has_inc_obj = false; - /* find the nearest point on the mesh */ + /* Find the nearest point on the mesh. */ if (BLI_bvhtree_find_nearest( data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) { @@ -698,15 +705,9 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata, } else { /* Apply (i.e. add) effector object velocity */ - data->velocity_x[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ? - hit_vel[0] * data->mes->vel_multi : - hit_vel[0]; - data->velocity_y[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ? - hit_vel[1] * data->mes->vel_multi : - hit_vel[1]; - data->velocity_z[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ? - hit_vel[2] * data->mes->vel_multi : - hit_vel[2]; + data->velocity_x[index] += hit_vel[0]; + data->velocity_y[index] += hit_vel[1]; + data->velocity_z[index] += hit_vel[2]; # ifdef DEBUG_PRINT /* Debugging: Print object velocities. */ printf("adding effector object vel: [%f, %f, %f], dx is: %f\n", @@ -745,7 +746,7 @@ static void obstacles_from_mesh(Object *coll_ob, float *velocity_x, float *velocity_y, float *velocity_z, - int *num_objects, + float *num_objects, float dt) { if (!mes->mesh) { @@ -918,32 +919,21 @@ static void update_obstacles(Depsgraph *depsgraph, float *vel_x_guide = manta_get_guide_velocity_x(mds->fluid); float *vel_y_guide = manta_get_guide_velocity_y(mds->fluid); float *vel_z_guide = manta_get_guide_velocity_z(mds->fluid); - float *vel_x_orig = manta_get_velocity_x(mds->fluid); - float *vel_y_orig = manta_get_velocity_y(mds->fluid); - float *vel_z_orig = manta_get_velocity_z(mds->fluid); - float *density = manta_smoke_get_density(mds->fluid); - float *fuel = manta_smoke_get_fuel(mds->fluid); - float *flame = manta_smoke_get_flame(mds->fluid); - float *r = manta_smoke_get_color_r(mds->fluid); - float *g = manta_smoke_get_color_g(mds->fluid); - float *b = manta_smoke_get_color_b(mds->fluid); float *phi_obs_in = manta_get_phiobs_in(mds->fluid); float *phi_guide_in = manta_get_phiguide_in(mds->fluid); - int *obstacles = manta_smoke_get_obstacle(mds->fluid); - int *num_obstacles = manta_get_num_obstacle(mds->fluid); - int *num_guides = manta_get_num_guide(mds->fluid); + float *num_obstacles = manta_get_num_obstacle(mds->fluid); + float *num_guides = manta_get_num_guide(mds->fluid); uint z; - float tmp = 0; /* Grid reset before writing again. */ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { /* Use big value that's not inf to initialize levelset grids. */ if (phi_obs_in) { - phi_obs_in[z] = FLT_MAX; + phi_obs_in[z] = PHI_MAX; } if (phi_guide_in) { - phi_guide_in[z] = FLT_MAX; + phi_guide_in[z] = PHI_MAX; } if (num_obstacles) { num_obstacles[z] = 0; @@ -1019,44 +1009,6 @@ static void update_obstacles(Depsgraph *depsgraph, } BKE_collision_objects_free(coll_ob_array); - - /* Obstacle cells should not contain any velocity from the smoke simulation. */ - for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { - if (obstacles[z] & 2) /* Mantaflow convention: FlagObstacle. */ - { - if (vel_x_orig && vel_y_orig && vel_z_orig) { - vel_x_orig[z] = 0.0f; - vel_y_orig[z] = 0.0f; - vel_z_orig[z] = 0.0f; - } - if (density) { - density[z] = 0.0f; - } - if (fuel) { - fuel[z] = 0.0f; - flame[z] = 0.0f; - } - if (r) { - r[z] = 0.0f; - g[z] = 0.0f; - b[z] = 0.0f; - } - } - /* Average velocities from multiple obstacles in one cell. */ - if (num_obstacles && num_obstacles[z]) { - tmp = 1.0f / num_obstacles[z]; - vel_x[z] *= tmp; - vel_y[z] *= tmp; - vel_z[z] *= tmp; - } - /* Average velocities from multiple guides in one cell. */ - if (num_guides && num_guides[z]) { - tmp = 1.0f / num_guides[z]; - vel_x_guide[z] *= tmp; - vel_y_guide[z] *= tmp; - vel_z_guide[z] *= tmp; - } - } } /** \} */ @@ -1067,10 +1019,8 @@ static void update_obstacles(Depsgraph *depsgraph, typedef struct EmissionMap { float *influence; - float *influence_high; float *velocity; float *distances; - float *distances_high; int min[3], max[3], res[3]; int hmin[3], hmax[3], hres[3]; int total_cells, valid; @@ -1127,7 +1077,7 @@ static void clamp_bounds_in_domain(FluidDomainSettings *mds, } } -static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) +static void em_allocateData(EmissionMap *em, bool use_velocity) { int i, res[3]; @@ -1149,23 +1099,6 @@ static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) /* Initialize to infinity. */ memset(em->distances, 0x7f7f7f7f, sizeof(float) * em->total_cells); - /* Allocate high resolution map if required. */ - if (hires_mul > 1) { - int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul); - - for (i = 0; i < 3; i++) { - em->hmin[i] = em->min[i] * hires_mul; - em->hmax[i] = em->max[i] * hires_mul; - em->hres[i] = em->res[i] * hires_mul; - } - - em->influence_high = MEM_calloc_arrayN( - total_cells_high, sizeof(float), "manta_flow_influence_high"); - em->distances_high = MEM_malloc_arrayN( - total_cells_high, sizeof(float), "manta_flow_distances_high"); - /* Initialize to infinity. */ - memset(em->distances_high, 0x7f7f7f7f, sizeof(float) * total_cells_high); - } em->valid = true; } @@ -1174,22 +1107,15 @@ static void em_freeData(EmissionMap *em) if (em->influence) { MEM_freeN(em->influence); } - if (em->influence_high) { - MEM_freeN(em->influence_high); - } if (em->velocity) { MEM_freeN(em->velocity); } if (em->distances) { MEM_freeN(em->distances); } - if (em->distances_high) { - MEM_freeN(em->distances_high); - } } -static void em_combineMaps( - EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size) +static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int additive, float sample_size) { int i, x, y, z; @@ -1209,7 +1135,7 @@ static void em_combineMaps( } } /* allocate output map */ - em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier); + em_allocateData(output, (em1.velocity || em2->velocity)); /* base resolution inputs */ for (x = output->min[0]; x < output->max[0]; x++) { @@ -1265,48 +1191,6 @@ static void em_combineMaps( } } - /* initialize high resolution input if available */ - if (output->influence_high) { - for (x = output->hmin[0]; x < output->hmax[0]; x++) { - for (y = output->hmin[1]; y < output->hmax[1]; y++) { - for (z = output->hmin[2]; z < output->hmax[2]; z++) { - int index_out = manta_get_index(x - output->hmin[0], - output->hres[0], - y - output->hmin[1], - output->hres[1], - z - output->hmin[2]); - - /* initialize with first input if in range */ - if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] && - z >= em1.hmin[2] && z < em1.hmax[2]) { - int index_in = manta_get_index( - x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]); - /* values */ - output->influence_high[index_out] = em1.influence_high[index_in]; - } - - /* apply second input if in range */ - if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] && - z >= em2->hmin[2] && z < em2->hmax[2]) { - int index_in = manta_get_index( - x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]); - - /* values */ - if (additive) { - output->influence_high[index_out] += em2->distances_high[index_in] * sample_size; - } - else { - output->distances_high[index_out] = MAX2(em2->distances_high[index_in], - output->distances_high[index_out]); - } - output->distances_high[index_out] = MIN2(em2->distances_high[index_in], - output->distances_high[index_out]); - } - } // high res loop - } - } - } - /* free original data */ em_freeData(&em1); } @@ -1314,17 +1198,13 @@ static void em_combineMaps( typedef struct EmitFromParticlesData { FluidFlowSettings *mfs; KDTree_3d *tree; - int hires_multiplier; EmissionMap *em; float *particle_vel; - float hr; - int *min, *max, *res; float solid; float smooth; - float hr_smooth; } EmitFromParticlesData; static void emit_from_particles_task_cb(void *__restrict userdata, @@ -1334,62 +1214,26 @@ static void emit_from_particles_task_cb(void *__restrict userdata, EmitFromParticlesData *data = userdata; FluidFlowSettings *mfs = data->mfs; EmissionMap *em = data->em; - const int hires_multiplier = data->hires_multiplier; for (int x = data->min[0]; x < data->max[0]; x++) { for (int y = data->min[1]; y < data->max[1]; y++) { - /* Take low res samples where possible. */ - if (hires_multiplier <= 1 || - !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { - /* Get low res space coordinates. */ - float inv_multiplier = 1.0f / hires_multiplier; - const int lx = x * inv_multiplier; - const int ly = y * inv_multiplier; - const int lz = z * inv_multiplier; - - const int index = manta_get_index( - lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); - const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - - /* Find particle distance from the kdtree. */ - KDTreeNearest_3d nearest; - const float range = data->solid + data->smooth; - BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); - - if (nearest.dist < range) { - em->influence[index] = (nearest.dist < data->solid) ? - 1.0f : - (1.0f - (nearest.dist - data->solid) / data->smooth); - /* Uses particle velocity as initial velocity for smoke. */ - if (mfs->flags & FLUID_FLOW_INITVELOCITY && - (mfs->psys->part->phystype != PART_PHYS_NO)) { - madd_v3_v3fl( - &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], mfs->vel_multi); - } - } - } - - /* Take high res samples if required. */ - if (hires_multiplier > 1) { - /* get low res space coordinates */ - const float lx = ((float)x) * data->hr; - const float ly = ((float)y) * data->hr; - const float lz = ((float)z) * data->hr; - - const int index = manta_get_index( - x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); - const float ray_start[3] = { - lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; - - /* Find particle distance from the kdtree. */ - KDTreeNearest_3d nearest; - const float range = data->solid + data->hr_smooth; - BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); - - if (nearest.dist < range) { - em->influence_high[index] = (nearest.dist < data->solid) ? - 1.0f : - (1.0f - (nearest.dist - data->solid) / data->smooth); + const int index = manta_get_index( + x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]); + const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f}; + + /* Find particle distance from the kdtree. */ + KDTreeNearest_3d nearest; + const float range = data->solid + data->smooth; + BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); + + if (nearest.dist < range) { + em->influence[index] = (nearest.dist < data->solid) ? + 1.0f : + (1.0f - (nearest.dist - data->solid) / data->smooth); + /* Uses particle velocity as initial velocity for smoke. */ + if (mfs->flags & FLUID_FLOW_INITVELOCITY && (mfs->psys->part->phystype != PART_PHYS_NO)) { + madd_v3_v3fl( + &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], mfs->vel_multi); } } } @@ -1419,7 +1263,6 @@ static void emit_from_particles(Object *flow_ob, /* radius based flow */ const float solid = mfs->particle_size * 0.5f; const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */ - int hires_multiplier = 1; KDTree_3d *tree = NULL; sim.depsgraph = depsgraph; @@ -1456,12 +1299,6 @@ static void emit_from_particles(Object *flow_ob, /* setup particle radius emission if enabled */ if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) { tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild); - - /* check need for high resolution map */ - if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = mds->noise_scale; - } - bounds_margin = (int)ceil(solid + smooth); } @@ -1509,7 +1346,7 @@ static void emit_from_particles(Object *flow_ob, /* set emission map */ clamp_bounds_in_domain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt); - em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier); + em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY); if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) { for (p = 0; p < valid_particles; p++) { @@ -1544,16 +1381,12 @@ static void emit_from_particles(Object *flow_ob, } else if (valid_particles > 0) { // FLUID_FLOW_USE_PART_SIZE int min[3], max[3], res[3]; - const float hr = 1.0f / ((float)hires_multiplier); - /* Slightly adjust high res anti-alias smoothness based on number of divisions - * to allow smaller details but yet not differing too much from the low res size. */ - const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f); /* setup loop bounds */ for (int i = 0; i < 3; i++) { - min[i] = em->min[i] * hires_multiplier; - max[i] = em->max[i] * hires_multiplier; - res[i] = em->res[i] * hires_multiplier; + min[i] = em->min[i]; + max[i] = em->max[i]; + res[i] = em->res[i]; } BLI_kdtree_3d_balance(tree); @@ -1561,8 +1394,6 @@ static void emit_from_particles(Object *flow_ob, EmitFromParticlesData data = { .mfs = mfs, .tree = tree, - .hires_multiplier = hires_multiplier, - .hr = hr, .em = em, .particle_vel = particle_vel, .min = min, @@ -1570,7 +1401,6 @@ static void emit_from_particles(Object *flow_ob, .res = res, .solid = solid, .smooth = smooth, - .hr_smooth = hr_smooth, }; TaskParallelSettings settings; @@ -1602,13 +1432,14 @@ static void update_mesh_distances(int index, float surface_thickness, int use_plane_init) { - float min_dist = FLT_MAX; + float min_dist = PHI_MAX; - /* Ensure that planes get initialized correctly. */ + /* a) Planar initialization */ if (use_plane_init) { BVHTreeNearest nearest = {0}; nearest.index = -1; - nearest.dist_sq = surface_thickness; + nearest.dist_sq = surface_thickness * + surface_thickness; /* find_nearest uses squared distance */ if (BLI_bvhtree_find_nearest( tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) { @@ -1616,12 +1447,14 @@ static void update_mesh_distances(int index, sub_v3_v3v3(ray, ray_start, nearest.co); min_dist = len_v3(ray); min_dist = (-1.0f) * fabsf(min_dist); - mesh_distances[index] = MIN2(mesh_distances[index], min_dist); + mesh_distances[index] = min_dist; } return; } - /* First pass: Ray-casts in 26 directions + /* b) Volumetric initialization: Ray-casts around mesh object. */ + + /* Ray-casts in 26 directions. * (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */ float ray_dirs[26][3] = { {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, @@ -1633,15 +1466,16 @@ static void update_mesh_distances(int index, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}}; size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0]; - /* Count for ray misses (no face hit) and cases where ray direction matches face normal - * direction. */ + /* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face + * normal direction. From this information it can be derived whether a cell is inside or outside + * the mesh. */ int miss_cnt = 0, dir_cnt = 0; - min_dist = FLT_MAX; + min_dist = PHI_MAX; for (int i = 0; i < ray_cnt; i++) { BVHTreeRayHit hit_tree = {0}; hit_tree.index = -1; - hit_tree.dist = FLT_MAX; + hit_tree.dist = PHI_MAX; normalize_v3(ray_dirs[i]); BLI_bvhtree_ray_cast(tree_data->tree, @@ -1652,14 +1486,13 @@ static void update_mesh_distances(int index, tree_data->raycast_callback, tree_data); - /* Ray did not hit mesh. Current point definitely not inside mesh. Inside mesh all rays have to - * hit. */ + /* Ray did not hit mesh. + * Current point definitely not inside mesh. Inside mesh as all rays have to hit. */ if (hit_tree.index == -1) { miss_cnt++; - continue; } - /* Ray and normal are in pointing opposite directions. */ + /* Ray and normal are pointing in opposite directions. */ if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) { dir_cnt++; } @@ -1669,7 +1502,8 @@ static void update_mesh_distances(int index, } } - /* Point lies inside mesh. Use negative sign for distance value. */ + /* Point lies inside mesh. Use negative sign for distance value. + * This "if statement" has 2 conditions that can be true for points outside mesh. */ if (!(miss_cnt > 0 || dir_cnt == ray_cnt)) { min_dist = (-1.0f) * fabsf(min_dist); } @@ -1677,45 +1511,13 @@ static void update_mesh_distances(int index, /* Update global distance array but ensure that older entries are not overridden. */ mesh_distances[index] = MIN2(mesh_distances[index], min_dist); - /* Second pass: Use nearest neighbor search on mesh surface. */ - BVHTreeNearest nearest = {0}; - nearest.index = -1; - nearest.dist_sq = 5; - - if (BLI_bvhtree_find_nearest( - tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) { - float ray[3] = {0}; - sub_v3_v3v3(ray, nearest.co, ray_start); - min_dist = len_v3(ray); - // CLAMP(min_dist, 0.5, min_dist); - - BVHTreeRayHit hit_tree = {0}; - hit_tree.index = -1; - hit_tree.dist = FLT_MAX; - - normalize_v3(ray); - BLI_bvhtree_ray_cast( - tree_data->tree, ray_start, ray, 0.0f, &hit_tree, tree_data->raycast_callback, tree_data); - - /* Only proceed if casted ray hit the mesh surface. */ - if (hit_tree.index != -1) { - - /* Ray and normal are in pointing same directions: Point must lie inside mesh. */ - if (dot_v3v3(ray, hit_tree.no) > 0) { - min_dist = (-1.0f) * fabsf(min_dist); - } - - /* Update distance value with more accurate one from this nearest neighbor search. - * Skip if new value would be outside and current value has inside value already. */ - if (!(min_dist > 0 && mesh_distances[index] <= 0)) { - mesh_distances[index] = min_dist; - } - } - } - + /* Subtract optional surface thickness value and virtually increase the object size. */ if (surface_thickness) { mesh_distances[index] -= surface_thickness; } + + /* Sanity check: Ensure that distances don't explode. */ + CLAMP(mesh_distances[index], -PHI_MAX, PHI_MAX); } static void sample_mesh(FluidFlowSettings *mfs, @@ -1743,16 +1545,23 @@ static void sample_mesh(FluidFlowSettings *mfs, BVHTreeNearest nearest = {0}; float volume_factor = 0.0f; - float sample_str = 0.0f; + float emission_strength = 0.0f; hit.index = -1; - hit.dist = FLT_MAX; + hit.dist = PHI_MAX; nearest.index = -1; - nearest.dist_sq = mfs->surface_distance * - mfs->surface_distance; /* find_nearest uses squared distance */ - /* Check volume collision */ - if (mfs->volume_density) { + /* Distance between two opposing vertices in a unit cube. + * I.e. the unit cube diagonal or sqrt(3). + * This value is our nearest neighbour search distance. */ + const float surface_distance = 1.732; + nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance. */ + + bool is_gas_flow = (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE || + mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE); + + /* Emission inside the flow object. */ + if (is_gas_flow && mfs->volume_density) { if (BLI_bvhtree_ray_cast(tree_data->tree, ray_start, ray_dir, @@ -1761,14 +1570,13 @@ static void sample_mesh(FluidFlowSettings *mfs, tree_data->raycast_callback, tree_data) != -1) { float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2]; - /* If ray and hit face normal are facing same direction - * hit point is inside a closed mesh. */ + /* If ray and hit face normal are facing same direction hit point is inside a closed mesh. */ if (dot >= 0) { - /* Also cast a ray in opposite direction to make sure - * point is at least surrounded by two faces */ + /* Also cast a ray in opposite direction to make sure point is at least surrounded by two + * faces. */ negate_v3(ray_dir); hit.index = -1; - hit.dist = FLT_MAX; + hit.dist = PHI_MAX; BLI_bvhtree_ray_cast(tree_data->tree, ray_start, @@ -1784,48 +1592,36 @@ static void sample_mesh(FluidFlowSettings *mfs, } } - /* find the nearest point on the mesh */ + /* Find the nearest point on the mesh. */ if (BLI_bvhtree_find_nearest( tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) { float weights[3]; int v1, v2, v3, f_index = nearest.index; float n1[3], n2[3], n3[3], hit_normal[3]; - /* emit from surface based on distance */ - if (mfs->surface_distance) { - sample_str = sqrtf(nearest.dist_sq) / mfs->surface_distance; - CLAMP(sample_str, 0.0f, 1.0f); - sample_str = pow(1.0f - sample_str, 0.5f); - } - else { - sample_str = 0.0f; - } - - /* calculate barycentric weights for nearest point */ + /* Calculate barycentric weights for nearest point. */ v1 = mloop[mlooptri[f_index].tri[0]].v; v2 = mloop[mlooptri[f_index].tri[1]].v; v3 = mloop[mlooptri[f_index].tri[2]].v; interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); + /* Initial velocity of flow object. */ if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) { - /* apply normal directional velocity */ + /* Apply normal directional velocity. */ if (mfs->vel_normal) { - /* interpolate vertex normal vectors to get nearest point normal */ + /* Interpolate vertex normal vectors to get nearest point normal. */ normal_short_to_float_v3(n1, mvert[v1].no); normal_short_to_float_v3(n2, mvert[v2].no); normal_short_to_float_v3(n3, mvert[v3].no); interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights); normalize_v3(hit_normal); - /* apply normal directional and random velocity - * - TODO: random disabled for now since it doesn't really work well - * as pressure calc smoothens it out. */ + + /* Apply normal directional velocity. */ velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f; velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f; velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f; - /* TODO: for fire emitted from mesh surface we can use - * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */ } - /* apply object velocity */ + /* Apply object velocity. */ if (has_velocity && mfs->vel_multi) { float hit_vel[3]; interp_v3_v3v3v3( @@ -1843,50 +1639,59 @@ static void sample_mesh(FluidFlowSettings *mfs, velocity_map[index * 3 + 2] += mfs->vel_coord[2]; } - /* apply vertex group influence if used */ - if (defgrp_index != -1 && dvert) { - float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] + - defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] + - defvert_find_weight(&dvert[v3], defgrp_index) * weights[2]; - sample_str *= weight_mask; - } - - /* apply emission texture */ - if ((mfs->flags & FLUID_FLOW_TEXTUREEMIT) && mfs->noise_texture) { - float tex_co[3] = {0}; - TexResult texres; + /* Compute emission strength for smoke flow. */ + if (is_gas_flow) { + /* Emission from surface is based on UI configurable distance value. */ + if (mfs->surface_distance) { + emission_strength = sqrtf(nearest.dist_sq) / mfs->surface_distance; + CLAMP(emission_strength, 0.0f, 1.0f); + emission_strength = pow(1.0f - emission_strength, 0.5f); + } + else { + emission_strength = 0.0f; + } - if (mfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) { - tex_co[0] = ((x - flow_center[0]) / base_res[0]) / mfs->texture_size; - tex_co[1] = ((y - flow_center[1]) / base_res[1]) / mfs->texture_size; - tex_co[2] = ((z - flow_center[2]) / base_res[2] - mfs->texture_offset) / mfs->texture_size; + /* Apply vertex group influence if it is being used. */ + if (defgrp_index != -1 && dvert) { + float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] + + defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] + + defvert_find_weight(&dvert[v3], defgrp_index) * weights[2]; + emission_strength *= weight_mask; } - else if (mloopuv) { - const float *uv[3]; - uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv; - uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv; - uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv; - - interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights); - - /* map between -1.0f and 1.0f */ - tex_co[0] = tex_co[0] * 2.0f - 1.0f; - tex_co[1] = tex_co[1] * 2.0f - 1.0f; - tex_co[2] = mfs->texture_offset; + + /* Apply emission texture. */ + if ((mfs->flags & FLUID_FLOW_TEXTUREEMIT) && mfs->noise_texture) { + float tex_co[3] = {0}; + TexResult texres; + + if (mfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) { + tex_co[0] = ((x - flow_center[0]) / base_res[0]) / mfs->texture_size; + tex_co[1] = ((y - flow_center[1]) / base_res[1]) / mfs->texture_size; + tex_co[2] = ((z - flow_center[2]) / base_res[2] - mfs->texture_offset) / + mfs->texture_size; + } + else if (mloopuv) { + const float *uv[3]; + uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv; + uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv; + uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv; + + interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights); + + /* Map texure coord between -1.0f and 1.0f. */ + tex_co[0] = tex_co[0] * 2.0f - 1.0f; + tex_co[1] = tex_co[1] * 2.0f - 1.0f; + tex_co[2] = mfs->texture_offset; + } + texres.nor = NULL; + BKE_texture_get_value(NULL, mfs->noise_texture, tex_co, &texres, false); + emission_strength *= texres.tin; } - texres.nor = NULL; - BKE_texture_get_value(NULL, mfs->noise_texture, tex_co, &texres, false); - sample_str *= texres.tin; } } - /* multiply initial velocity by emitter influence */ - if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) { - mul_v3_fl(&velocity_map[index * 3], sample_str); - } - - /* apply final influence based on volume factor */ - influence_map[index] = MAX2(volume_factor, sample_str); + /* Apply final influence value but also consider volume initialization factor. */ + influence_map[index] = MAX2(volume_factor, emission_strength); } typedef struct EmitFromDMData { @@ -1900,9 +1705,6 @@ typedef struct EmitFromDMData { int defgrp_index; BVHTreeFromMesh *tree; - int hires_multiplier; - float hr; - EmissionMap *em; bool has_velocity; float *vert_vel; @@ -1917,23 +1719,17 @@ static void emit_from_mesh_task_cb(void *__restrict userdata, { EmitFromDMData *data = userdata; EmissionMap *em = data->em; - const int hires_multiplier = data->hires_multiplier; for (int x = data->min[0]; x < data->max[0]; x++) { for (int y = data->min[1]; y < data->max[1]; y++) { - /* take low res samples where possible */ - if (hires_multiplier <= 1 || - !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { - /* get low res space coordinates */ - const int lx = x / hires_multiplier; - const int ly = y / hires_multiplier; - const int lz = z / hires_multiplier; - - const int index = manta_get_index( - lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); - const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - - /* Emission for smoke and fire. Result in em->influence. Also, calculate invels */ + const int index = manta_get_index( + x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]); + const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f}; + + /* Compute emission only for flow objects that produce fluid (i.e. skip outflow objects). + * Result in em->influence. Also computes initial velocities. Result in em->velocity. */ + if ((data->mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) || + (data->mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW)) { sample_mesh(data->mfs, data->mvert, data->mloop, @@ -1950,59 +1746,18 @@ static void emit_from_mesh_task_cb(void *__restrict userdata, data->has_velocity, data->defgrp_index, data->dvert, - (float)lx, - (float)ly, - (float)lz); - - /* Calculate levelset from meshes. Result in em->distances */ - update_mesh_distances(index, - em->distances, - data->tree, - ray_start, - data->mfs->surface_distance, - data->mfs->flags & FLUID_FLOW_USE_PLANE_INIT); + (float)x, + (float)y, + (float)z); } - /* take high res samples if required */ - if (hires_multiplier > 1) { - /* get low res space coordinates */ - const float lx = ((float)x) * data->hr; - const float ly = ((float)y) * data->hr; - const float lz = ((float)z) * data->hr; - - const int index = manta_get_index( - x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); - const float ray_start[3] = { - lx + 0.5f * data->hr, - ly + 0.5f * data->hr, - lz + 0.5f * data->hr, - }; - - /* Emission for smoke and fire high. Result in em->influence_high */ - if (data->mfs->type == FLUID_FLOW_TYPE_SMOKE || data->mfs->type == FLUID_FLOW_TYPE_FIRE || - data->mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) { - sample_mesh(data->mfs, - data->mvert, - data->mloop, - data->mlooptri, - data->mloopuv, - em->influence_high, - NULL, - index, - data->mds->base_res, - data->flow_center, - data->tree, - ray_start, - data->vert_vel, - data->has_velocity, - data->defgrp_index, - data->dvert, - /* x,y,z needs to be always lowres */ - lx, - ly, - lz); - } - } + /* Calculate levelset values from meshes. Result in em->distances. */ + update_mesh_distances(index, + em->distances, + data->tree, + ray_start, + data->mfs->surface_distance, + data->mfs->flags & FLUID_FLOW_USE_PLANE_INIT); } } } @@ -2026,11 +1781,9 @@ static void emit_from_mesh( int defgrp_index = mfs->vgroup_density - 1; float flow_center[3] = {0}; int min[3], max[3], res[3]; - int hires_multiplier = 1; - /* copy mesh for thread safety because we modify it, - * main issue is its VertArray being modified, then replaced and freed - */ + /* Copy mesh for thread safety as we modify it. + * Main issue is its VertArray being modified, then replaced and freed. */ me = BKE_mesh_copy_for_eval(mfs->mesh, true); /* Duplicate vertices to modify. */ @@ -2062,23 +1815,22 @@ static void emit_from_mesh( } } - /* Transform mesh vertices to - * domain grid space for fast lookups */ + /* Transform mesh vertices to domain grid space for fast lookups */ for (i = 0; i < numverts; i++) { float n[3]; - /* vert pos */ + /* Vertex position. */ mul_m4_v3(flow_ob->obmat, mvert[i].co); manta_pos_to_cell(mds, mvert[i].co); - /* vert normal */ + /* Vertex normal. */ normal_short_to_float_v3(n, mvert[i].no); mul_mat3_m4_v3(flow_ob->obmat, n); mul_mat3_m4_v3(mds->imat, n); normalize_v3(n); normal_float_to_short_v3(mvert[i].no, n); - /* vert velocity */ + /* Vertex velocity. */ if (mfs->flags & FLUID_FLOW_INITVELOCITY) { float co[3]; add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift); @@ -2089,31 +1841,26 @@ static void emit_from_mesh( copy_v3_v3(&mfs->verts_old[i * 3], co); } - /* calculate emission map bounds */ + /* Calculate emission map bounds. */ em_boundInsert(em, mvert[i].co); } mul_m4_v3(flow_ob->obmat, flow_center); manta_pos_to_cell(mds, flow_center); - /* check need for high resolution map */ - if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = mds->noise_scale; - } - - /* set emission map */ - clamp_bounds_in_domain( - mds, em->min, em->max, NULL, NULL, (int)ceil(mfs->surface_distance), dt); - em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier); + /* Set emission map. + * Use 3 cell diagonals as margin (3 * 1.732 = 5.196). */ + int bounds_margin = (int)ceil(5.196); + clamp_bounds_in_domain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt); + em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY); - /* setup loop bounds */ + /* Setup loop bounds. */ for (i = 0; i < 3; i++) { - min[i] = em->min[i] * hires_multiplier; - max[i] = em->max[i] * hires_multiplier; - res[i] = em->res[i] * hires_multiplier; + min[i] = em->min[i]; + max[i] = em->max[i]; + res[i] = em->res[i]; } if (BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) { - const float hr = 1.0f / ((float)hires_multiplier); EmitFromDMData data = { .mds = mds, @@ -2125,8 +1872,6 @@ static void emit_from_mesh( .dvert = dvert, .defgrp_index = defgrp_index, .tree = &tree_data, - .hires_multiplier = hires_multiplier, - .hr = hr, .em = em, .has_velocity = has_velocity, .vert_vel = vert_vel, @@ -2141,7 +1886,7 @@ static void emit_from_mesh( settings.min_iter_per_thread = 2; BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings); } - /* free bvh tree */ + /* Free bvh tree. */ free_bvhtree_from_mesh(&tree_data); if (vert_vel) { @@ -2457,60 +2202,55 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs, float *phi_in, float *emission_in) { - /* add inflow */ + /* Set levelset value for liquid inflow. + * Ensure that distance value is "joined" into the levelset. */ if (phi_in) { - phi_in[index] = distance_value; + phi_in[index] = MIN2(distance_value, phi_in[index]); } - /* save emission value for manta inflow */ + /* Set emission value for smoke inflow. + * Ensure that emission value is "maximised". */ if (emission_in) { - emission_in[index] = emission_value; + emission_in[index] = MAX2(emission_value, emission_in[index]); } - /* add smoke inflow */ + /* Set inflow for smoke from here on. */ int absolute_flow = (mfs->flags & FLUID_FLOW_ABSOLUTE); float dens_old = (density) ? density[index] : 0.0; // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */ float dens_flow = (mfs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * mfs->density; float fuel_flow = (fuel) ? emission_value * mfs->fuel_amount : 0.0f; - /* add heat */ + /* Set heat inflow. */ if (heat && heat_in) { if (emission_value > 0.0f) { heat_in[index] = ADD_IF_LOWER(heat[index], mfs->temperature); - /* Scale inflow by dt/frame-length. - * This is to ensure that adaptive steps don't apply too much emission. */ - } - else { - heat_in[index] = heat[index]; } } - /* set density and fuel - absolute mode */ + /* Set density and fuel - absolute mode. */ if (absolute_flow) { if (density && density_in) { - density_in[index] = density[index]; if (mfs->type != FLUID_FLOW_TYPE_FIRE && dens_flow > density[index]) { - density_in[index] = dens_flow; + /* Use MAX2 to preserve values from other emitters at this cell. */ + density_in[index] = MAX2(dens_flow, density_in[index]); } } if (fuel && fuel_in) { - fuel_in[index] = fuel[index]; if (mfs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow && fuel_flow > fuel[index]) { - fuel_in[index] = fuel_flow; + /* Use MAX2 to preserve values from other emitters at this cell. */ + fuel_in[index] = MAX2(fuel_flow, fuel_in[index]); } } } - /* set density and fuel - additive mode */ + /* Set density and fuel - additive mode. */ else { if (density && density_in) { - density_in[index] = density[index]; if (mfs->type != FLUID_FLOW_TYPE_FIRE) { density_in[index] += dens_flow; CLAMP(density_in[index], 0.0f, 1.0f); } } if (fuel && fuel_in) { - fuel_in[index] = fuel[index]; if (mfs->type != FLUID_FLOW_TYPE_SMOKE && mfs->fuel_amount) { fuel_in[index] += fuel_flow; CLAMP(fuel_in[index], 0.0f, 10.0f); @@ -2518,12 +2258,8 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs, } } - /* set color */ + /* Set color. */ if (color_r && color_r_in) { - color_r_in[index] = color_r[index]; - color_g_in[index] = color_g[index]; - color_b_in[index] = color_b[index]; - if (dens_flow) { float total_dens = density[index] / (dens_old + dens_flow); color_r_in[index] = (color_r[index] + mfs->color[0] * dens_flow) * total_dens; @@ -2532,7 +2268,7 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs, } } - /* set fire reaction coordinate */ + /* Set fire reaction coordinate. */ if (fuel && fuel_in) { /* Instead of using 1.0 for all new fuel add slight falloff to reduce flow blocky-ness. */ float value = 1.0f - pow2f(1.0f - emission_value); @@ -2542,9 +2278,6 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs, react_in[index] = value * f + (1.0f - f) * react[index]; CLAMP(react_in[index], 0.0f, value); } - else { - react_in[index] = react[index]; - } } } @@ -2666,37 +2399,49 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, flowobjs = BKE_collision_objects_create( depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Fluid); - /* Update all flow related flags and ensure that corresponding grids get initialized */ + /* Update all flow related flags and ensure that corresponding grids get initialized. */ update_flowsflags(mds, flowobjs, numflowobj); - /* init emission maps for each flow */ + /* Initialize emission maps for each flow. */ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "manta_flow_maps"); - /* Prepare flow emission maps */ + /* Prepare flow emission maps. */ for (flow_index = 0; flow_index < numflowobj; flow_index++) { Object *flowobj = flowobjs[flow_index]; FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, eModifierType_Fluid); - /* Check for initialized smoke object */ + /* Check for initialized smoke object. */ if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { FluidFlowSettings *mfs = mmd2->flow; int subframes = mfs->subframes; EmissionMap *em = &emaps[flow_index]; + /* Optimization: No need to compute emission value if it won't be applied. */ + if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && !is_first_frame) { + continue; + } + /* Optimization: Skip flow object if it does not "belong" to this domain type. */ + if (mfs->type == FLUID_FLOW_TYPE_LIQUID && mds->type == FLUID_DOMAIN_TYPE_GAS) { + continue; + } + if ((mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE || + mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) && + mds->type == FLUID_DOMAIN_TYPE_LIQUID) { + continue; + } + /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual * frame length */ float adaptframe_length = time_per_frame / frame_length; /* Adaptive frame length as percentage */ CLAMP(adaptframe_length, 0.0f, 1.0f); - /* Further splitting because of emission subframe: If no subframes present, sample_size is 1 - */ + /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */ float sample_size = 1.0f / (float)(subframes + 1); - int hires_multiplier = 1; /* First frame cannot have any subframes because there is (obviously) no previous frame from - * where subframes could come from */ + * where subframes could come from. */ if (is_first_frame) { subframes = 0; } @@ -2707,7 +2452,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, /* Emission loop. When not using subframes this will loop only once. */ for (subframe = subframes; subframe >= 0; subframe--) { - /* Temporary emission map used when subframes are enabled, i.e. at least one subframe */ + /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */ EmissionMap em_temp = {NULL}; /* Set scene time */ @@ -2718,22 +2463,22 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, scene->r.cfra = frame - 1; } /* Last frame in this loop (subframe == suframes). Can be real end frame or in between - * frames (adaptive frame) */ + * frames (adaptive frame). */ else { /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene - * subframe parameter */ + * subframe parameter. */ if (time_per_frame < frame_length) { scene->r.subframe = adaptframe_length; scene->r.cfra = frame - 1; } /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe - * parameter to 0 and advance current scene frame */ + * parameter to 0 and advance current scene frame. */ else { scene->r.subframe = 0.0f; scene->r.cfra = frame; } } - /* Sanity check: subframe portion must be between 0 and 1 */ + /* Sanity check: subframe portion must be between 0 and 1. */ CLAMP(scene->r.subframe, 0.0f, 1.0f); # ifdef DEBUG_PRINT /* Debugging: Print subframe information. */ @@ -2748,11 +2493,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, /* Update frame time, this is considering current subframe fraction * BLI_mutex_lock() called in manta_step(), so safe to update subframe here * TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) - * as subframes don't work with the latter yet */ + * as subframes don't work with the latter yet. */ BKE_object_modifier_update_subframe( depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid); - /* Emission from particles */ + /* Emission from particles. */ if (mfs->source == FLUID_FLOW_SOURCE_PARTICLES) { if (subframes) { emit_from_particles(flowobj, mds, mfs, &em_temp, depsgraph, scene, subframe_dt); @@ -2760,12 +2505,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, else { emit_from_particles(flowobj, mds, mfs, em, depsgraph, scene, subframe_dt); } - - if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) { - hires_multiplier = 1; - } } - /* Emission from mesh */ + /* Emission from mesh. */ else if (mfs->source == FLUID_FLOW_SOURCE_MESH) { if (subframes) { emit_from_mesh(flowobj, mds, mfs, &em_temp, subframe_dt); @@ -2779,11 +2520,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, } /* If this we emitted with temp emission map in this loop (subframe emission), we combine - * the temp map with the original emission map */ + * the temp map with the original emission map. */ if (subframes) { - /* Combine emission maps */ - em_combineMaps( - em, &em_temp, hires_multiplier, !(mfs->flags & FLUID_FLOW_ABSOLUTE), sample_size); + /* Combine emission maps. */ + em_combineMaps(em, &em_temp, !(mfs->flags & FLUID_FLOW_ABSOLUTE), sample_size); em_freeData(&em_temp); } } @@ -2798,7 +2538,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, dt); # endif - /* Adjust domain size if needed. Only do this once for every frame */ + /* Adjust domain size if needed. Only do this once for every frame. */ if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { adaptive_domain_adjust(mds, ob, emaps, numflowobj, dt); } @@ -2827,28 +2567,29 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, float *velz_initial = manta_get_in_velocity_z(mds->fluid); uint z; - /* Grid reset before writing again */ + /* Grid reset before writing again. */ for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { if (phi_in) { - phi_in[z] = FLT_MAX; + phi_in[z] = PHI_MAX; } if (phiout_in) { - phiout_in[z] = FLT_MAX; + phiout_in[z] = PHI_MAX; } + /* Sync smoke inflow grids with their counterparts (simulation grids). */ if (density_in) { - density_in[z] = 0.0f; + density_in[z] = density[z]; } if (heat_in) { - heat_in[z] = 0.0f; + heat_in[z] = heat[z]; } if (color_r_in) { - color_r_in[z] = 0.0f; - color_g_in[z] = 0.0f; - color_b_in[z] = 0.0f; + color_r_in[z] = color_r[z]; + color_g_in[z] = color_b[z]; + color_b_in[z] = color_g[z]; } if (fuel_in) { - fuel_in[z] = 0.0f; - react_in[z] = 0.0f; + fuel_in[z] = fuel[z]; + react_in[z] = react[z]; } if (emission_in) { emission_in[z] = 0.0f; @@ -2860,13 +2601,13 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, } } - /* Apply emission data */ + /* Apply emission data for every flow object. */ for (flow_index = 0; flow_index < numflowobj; flow_index++) { Object *flowobj = flowobjs[flow_index]; FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, eModifierType_Fluid); - // check for initialized flow object + /* Check for initialized flow object. */ if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { FluidFlowSettings *mfs = mmd2->flow; EmissionMap *em = &emaps[flow_index]; @@ -2877,28 +2618,29 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, int gx, gy, gz, ex, ey, ez, dx, dy, dz; size_t e_index, d_index; - // loop through every emission map cell + /* Loop through every emission map cell. */ for (gx = em->min[0]; gx < em->max[0]; gx++) { for (gy = em->min[1]; gy < em->max[1]; gy++) { for (gz = em->min[2]; gz < em->max[2]; gz++) { - /* get emission map index */ + /* Compute emission map index. */ ex = gx - em->min[0]; ey = gy - em->min[1]; ez = gz - em->min[2]; e_index = manta_get_index(ex, em->res[0], ey, em->res[1], ez); - /* get domain index */ + /* Get domain index. */ dx = gx - mds->res_min[0]; dy = gy - mds->res_min[1]; dz = gz - mds->res_min[2]; d_index = manta_get_index(dx, mds->res[0], dy, mds->res[1], dz); - /* make sure emission cell is inside the new domain boundary */ + /* Make sure emission cell is inside the new domain boundary. */ if (dx < 0 || dy < 0 || dz < 0 || dx >= mds->res[0] || dy >= mds->res[1] || dz >= mds->res[2]) { continue; } - if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { // outflow + /* Delete fluid in outflow regions. */ + if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { apply_outflow_fields(d_index, distance_map[e_index], density_in, @@ -2910,10 +2652,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, color_b_in, phiout_in); } - else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && mmd2->time > 2) { + /* Do not apply inflow after the first frame when in geometry mode. */ + else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && !is_first_frame) { apply_inflow_fields(mfs, 0.0f, - FLT_MAX, + PHI_MAX, d_index, density_in, density, @@ -2932,8 +2675,9 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, phi_in, emission_in); } + /* Main inflow application. */ else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW || - mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) { // inflow + mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) { /* only apply inflow if enabled */ if (mfs->flags & FLUID_FLOW_USE_INFLOW) { apply_inflow_fields(mfs, @@ -2956,7 +2700,6 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, color_b, phi_in, emission_in); - /* initial velocity */ if (mfs->flags & FLUID_FLOW_INITVELOCITY) { velx_initial[d_index] = velocity_map[e_index * 3]; vely_initial[d_index] = velocity_map[e_index * 3 + 1]; @@ -2964,14 +2707,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, } } } - } // low res loop + } } - } - - // free emission maps + } /* End of flow emission map loop. */ em_freeData(em); - - } // end emission + } /* End of flow object loop. */ } BKE_collision_objects_free(flowobjs); @@ -3161,7 +2901,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj // if reading raw data directly from manta, normalize now, otherwise omit this, ie when reading // from files - { + if (!manta_liquid_mesh_from_file(mds->fluid)) { // normalize to unit cube around 0 mverts->co[0] -= ((float)mds->res[0] * mds->mesh_scale) * 0.5f; mverts->co[1] -= ((float)mds->res[1] * mds->mesh_scale) * 0.5f; @@ -3715,12 +3455,14 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Read mesh cache. */ if (with_liquid && with_mesh) { - has_mesh = manta_read_mesh(mds->fluid, mmd, mesh_frame); + /* Update mesh data from file is faster than via Python (manta_read_mesh()). */ + has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame); } /* Read particles cache. */ if (with_liquid && with_particles) { - has_particles = manta_read_particles(mds->fluid, mmd, particles_frame); + /* Update particle data from file is faster than via Python (manta_read_particles()). */ + has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame); } /* Read guide cache. */ @@ -3758,12 +3500,23 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } /* Read data cache only */ else { - /* Read config and realloc fluid object if needed. */ - if (manta_read_config(mds->fluid, mmd, data_frame) && manta_needs_realloc(mds->fluid, mmd)) { - BKE_fluid_reallocate_fluid(mds, mds->res, 1); + if (with_smoke) { + /* Read config and realloc fluid object if needed. */ + if (manta_read_config(mds->fluid, mmd, data_frame) && + manta_needs_realloc(mds->fluid, mmd)) { + BKE_fluid_reallocate_fluid(mds, mds->res, 1); + } + /* Read data cache */ + has_data = manta_read_data(mds->fluid, mmd, data_frame); + } + if (with_liquid) { + if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) { + has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame); + } + else { + has_data = manta_read_data(mds->fluid, mmd, data_frame); + } } - /* Read data cache */ - has_data = manta_read_data(mds->fluid, mmd, data_frame); } } @@ -3857,15 +3610,47 @@ struct Mesh *BKE_fluid_modifier_do( BLI_rw_mutex_unlock(mmd->domain->fluid_mutex); } + /* Optimization: Do not update viewport during bakes (except in replay mode) + * Reason: UI is locked and updated liquid / smoke geometry is not visible anyways. */ + bool needs_viewport_update = false; + if (mmd->domain) { + FluidDomainSettings *mds = mmd->domain; + + /* Always update viewport in cache replay mode. */ + if (mds->cache_type == FLUID_DOMAIN_CACHE_REPLAY || + mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + needs_viewport_update = true; + } + /* In other cache modes, only update the viewport when no bake is going on. */ + else { + bool with_mesh; + with_mesh = mds->flags & FLUID_DOMAIN_USE_MESH; + bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide; + baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA; + baking_noise = mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE; + baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH; + baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES; + baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE; + + if (with_mesh && !baking_data && !baking_noise && !baking_mesh && !baking_particles && + !baking_guide) { + needs_viewport_update = true; + } + } + } + Mesh *result = NULL; if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { - /* Return generated geometry depending on domain type. */ - if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) { - result = create_liquid_geometry(mmd->domain, me, ob); - } - if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { - result = create_smoke_geometry(mmd->domain, me, ob); + if (needs_viewport_update) { + /* Return generated geometry depending on domain type. */ + if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) { + result = create_liquid_geometry(mmd->domain, me, ob); + } + if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { + result = create_smoke_geometry(mmd->domain, me, ob); + } } + /* Clear flag outside of locked block (above). */ mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA; mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE; @@ -4190,7 +3975,7 @@ void BKE_fluid_particle_system_create(struct Main *bmain, part->type = psys_type; part->totpart = 0; - part->draw_size = 0.01f; // make fluid particles more subtle in viewport + part->draw_size = 0.01f; /* Make fluid particles more subtle in viewport. */ part->draw_col = PART_DRAW_COL_VEL; psys->part = part; psys->pointcache = BKE_ptcache_add(&psys->ptcaches); @@ -4212,7 +3997,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ for (psys = ob->particlesystem.first; psys; psys = next_psys) { next_psys = psys->next; - if (psys->part->type & particle_type) { + if (psys->part->type == particle_type) { /* clear modifier */ pmmd = psys_get_modifier(ob, psys); BLI_remlink(&ob->modifiers, pmmd); @@ -4319,7 +4104,6 @@ void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, in BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_LEFT, 0); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_TOP, 0); BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BOTTOM, 0); - BKE_fluid_particles_set(settings, FLUID_DOMAIN_PARTICLE_FLIP, 0); object->dt = OB_SOLID; } @@ -4565,7 +4349,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) mmd->domain->particle_number = 2; mmd->domain->particle_minimum = 8; mmd->domain->particle_maximum = 16; - mmd->domain->particle_radius = 1.5f; + mmd->domain->particle_radius = 1.0f; mmd->domain->particle_band_width = 3.0f; mmd->domain->fractions_threshold = 0.05f; @@ -4624,9 +4408,9 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) mmd->domain->cache_flag = 0; mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR; mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT; - mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_UNI; - mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_UNI; - mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_UNI; + mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_OPENVDB; + mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_OPENVDB; + mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_OPENVDB; modifier_path_init(mmd->domain->cache_directory, sizeof(mmd->domain->cache_directory), FLUID_DOMAIN_DIR_DEFAULT); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f72bb4b4cd4..8eb5cca1ad0 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -494,7 +494,7 @@ bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, s gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); /* initialize triangle memory to dummy data */ - gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); + gps->triangles = NULL; gps->flag |= GP_STROKE_RECALC_GEOMETRY; gps->tot_triangles = 0; @@ -939,9 +939,15 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M gpl->actframe = gpf; } else { - /* unresolved errogenous situation! */ - CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame"); - /* gpl->actframe should still be NULL */ + /* If delete first frame, need to find one. */ + if (gpl->frames.first != NULL) { + gpl->actframe = gpl->frames.first; + } + else { + /* unresolved errogenous situation! */ + CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame"); + /* gpl->actframe should still be NULL */ + } } } else { diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index fe087256d25..bc0c54ed96e 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -862,6 +862,14 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob) const bool time_remap = BKE_gpencil_has_time_modifiers(ob); int cfra_eval = (int)DEG_get_ctime(depsgraph); + /* Clear any previous evaluated data. */ + if (ob->runtime.gpencil_tot_layers > 0) { + for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) { + bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i]; + BKE_gpencil_free_frame_runtime_data(gpf_eval); + } + } + /* Create array of evaluated frames equal to number of layers. */ ob->runtime.gpencil_tot_layers = BLI_listbase_count(&gpd->layers); CLAMP_MIN(ob->runtime.gpencil_tot_layers, 1); diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 1125047be32..e3b27236616 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -461,6 +461,21 @@ static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) return newp; } +void IDP_AssignID(IDProperty *prop, ID *id, const int flag) +{ + BLI_assert(prop->type == IDP_ID); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && IDP_Id(prop) != NULL) { + id_us_min(IDP_Id(prop)); + } + + prop->data.pointer = id; + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(IDP_Id(prop)); + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 6d6e5166e1c..be354b04157 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -441,10 +441,9 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s BLI_listbase_clear(&ima_dst->anims); BLI_duplicatelist(&ima_dst->tiles, &ima_src->tiles); - LISTBASE_FOREACH (ImageTile *, tile, &ima_dst->tiles) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - tile->gputexture[i] = NULL; - } + + for (int i = 0; i < TEXTARGET_COUNT; i++) { + ima_dst->gputexture[i] = NULL; } if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { @@ -510,11 +509,9 @@ bool BKE_image_scale(Image *image, int width, int height) bool BKE_image_has_opengl_texture(Image *ima) { - LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - if (tile->gputexture[i] != NULL) { - return true; - } + for (int i = 0; i < TEXTARGET_COUNT; i++) { + if (ima->gputexture[i] != NULL) { + return true; } } return false; @@ -1348,6 +1345,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) /* bw */ switch (imtype) { + case R_IMF_IMTYPE_BMP: case R_IMF_IMTYPE_PNG: case R_IMF_IMTYPE_JPEG90: case R_IMF_IMTYPE_TARGA: @@ -3293,9 +3291,16 @@ void BKE_image_init_imageuser(Image *ima, ImageUser *iuser) static void image_free_tile(Image *ima, ImageTile *tile) { for (int i = 0; i < TEXTARGET_COUNT; i++) { - if (tile->gputexture[i] != NULL) { - GPU_texture_free(tile->gputexture[i]); - tile->gputexture[i] = NULL; + /* Only two textures depends on all tiles, so if this is a secondary tile we can keep the other + * two. */ + if (tile != ima->tiles.first && + !(ELEM(i, TEXTARGET_TEXTURE_2D_ARRAY, TEXTARGET_TEXTURE_TILE_MAPPING))) { + continue; + } + + if (ima->gputexture[i] != NULL) { + GPU_texture_free(ima->gputexture[i]); + ima->gputexture[i] = NULL; } } @@ -3560,6 +3565,16 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la BLI_strncpy(tile->label, label, sizeof(tile->label)); } + /* Reallocate GPU tile array. */ + if (ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY]); + ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY] = NULL; + } + if (ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING]); + ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING] = NULL; + } + return tile; } @@ -3877,7 +3892,12 @@ static void image_initialize_after_load(Image *ima, ImageUser *iuser, ImBuf *UNU BKE_image_tag_time(ima); ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser); - tile->ok = IMA_OK_LOADED; + /* Images should never get loaded if the corresponding tile does not exist, + * but we should at least not crash if it happens due to a bug elsewhere. */ + BLI_assert(tile != NULL); + if (tile != NULL) { + tile->ok = IMA_OK_LOADED; + } } static int imbuf_alpha_flags_for_image(Image *ima) @@ -4750,14 +4770,14 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser) return false; } - ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser); - if (iuser) { if (iuser->ok == 0) { return false; } } - else if (tile == NULL) { + + ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser); + if (tile == NULL) { return false; } else if (tile->ok == 0) { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index bda1cac80e4..12a90906d1f 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -340,6 +340,23 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas FOREACH_FINALIZE_VOID; } +/* Used by both real Collection data-blocks, and the fake horror of master collection from Scene. + */ +static void library_foreach_collection(LibraryForeachIDData *data, Collection *collection) +{ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + FOREACH_CALLBACK_INVOKE(data, cob->ob, IDWALK_CB_USER); + } + for (CollectionChild *child = collection->children.first; child; child = child->next) { + FOREACH_CALLBACK_INVOKE(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER); + } + for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) { + FOREACH_CALLBACK_INVOKE(data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_ID_as_subdata_link(ID **id_pp, LibraryIDLinkCallback callback, void *user_data, @@ -484,14 +501,7 @@ static void library_foreach_ID_link(Main *bmain, SEQ_END; } - for (CollectionObject *cob = scene->master_collection->gobject.first; cob; - cob = cob->next) { - CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); - } - for (CollectionChild *child = scene->master_collection->children.first; child; - child = child->next) { - CALLBACK_INVOKE(child->collection, IDWALK_CB_USER); - } + library_foreach_collection(&data, scene->master_collection); if (scene->master_collection->lanpr) { CALLBACK_INVOKE(scene->master_collection->lanpr->target, IDWALK_CB_USER); @@ -804,15 +814,7 @@ static void library_foreach_ID_link(Main *bmain, case ID_GR: { Collection *collection = (Collection *)id; - for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { - CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); - } - for (CollectionChild *child = collection->children.first; child; child = child->next) { - CALLBACK_INVOKE(child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER); - } - for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) { - CALLBACK_INVOKE(parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK); - } + library_foreach_collection(&data, collection); break; } diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index 06f1ee5050b..3cba3aa9611 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -41,6 +41,30 @@ void BKE_lightprobe_init(LightProbe *probe) MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id); } +void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type) +{ + probe->type = lightprobe_type; + + switch (probe->type) { + case LIGHTPROBE_TYPE_GRID: + probe->distinf = 0.3f; + probe->falloff = 1.0f; + probe->clipsta = 0.01f; + break; + case LIGHTPROBE_TYPE_PLANAR: + probe->distinf = 0.1f; + probe->falloff = 0.5f; + probe->clipsta = 0.001f; + break; + case LIGHTPROBE_TYPE_CUBE: + probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID; + break; + default: + BLI_assert(!"LightProbe type not configured."); + break; + } +} + void *BKE_lightprobe_add(Main *bmain, const char *name) { LightProbe *probe; diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 2ade368284c..fba84aaad42 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -522,7 +522,6 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase) { - Curve *cu = ob->data; Mesh *mesh; MVert *allvert; MEdge *alledge; @@ -530,7 +529,6 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase) MPoly *allpoly; MLoopUV *alluv = NULL; int totvert, totedge, totloop, totpoly; - bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0; if (BKE_mesh_nurbs_displist_to_mdata(ob, dispbase, @@ -540,7 +538,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase) &totedge, &allloop, &allpoly, - (use_orco_uv) ? &alluv : NULL, + &alluv, &totloop, &totpoly) != 0) { /* Error initializing mdata. This often happens when curve is empty */ @@ -580,12 +578,8 @@ Mesh *BKE_mesh_new_nomain_from_curve(Object *ob) } /* this may fail replacing ob->data, be sure to check ob->type */ -void BKE_mesh_from_nurbs_displist(Main *bmain, - Object *ob, - ListBase *dispbase, - const bool use_orco_uv, - const char *obdata_name, - bool temporary) +void BKE_mesh_from_nurbs_displist( + Main *bmain, Object *ob, ListBase *dispbase, const char *obdata_name, bool temporary) { Object *ob1; Mesh *me_eval = ob->runtime.mesh_eval; @@ -609,7 +603,7 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, &totedge, &allloop, &allpoly, - (use_orco_uv) ? &alluv : NULL, + &alluv, &totloop, &totpoly) != 0) { /* Error initializing */ @@ -706,14 +700,13 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, void BKE_mesh_from_nurbs(Main *bmain, Object *ob) { Curve *cu = (Curve *)ob->data; - bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0; ListBase disp = {NULL, NULL}; if (ob->runtime.curve_cache) { disp = ob->runtime.curve_cache->disp; } - BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false); + BKE_mesh_from_nurbs_displist(bmain, ob, &disp, cu->id.name, false); } typedef struct EdgeLink { @@ -1023,8 +1016,6 @@ static void curve_to_mesh_eval_ensure(Object *object) static Mesh *mesh_new_from_curve_type_object(Object *object) { Curve *curve = object->data; - const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0; - Object *temp_object = object_for_curve_to_mesh_create(object); Curve *temp_curve = (Curve *)temp_object->data; @@ -1039,12 +1030,8 @@ static Mesh *mesh_new_from_curve_type_object(Object *object) temp_curve->editnurb = NULL; /* Convert to mesh. */ - BKE_mesh_from_nurbs_displist(NULL, - temp_object, - &temp_object->runtime.curve_cache->disp, - uv_from_orco, - curve->id.name + 2, - true); + BKE_mesh_from_nurbs_displist( + NULL, temp_object, &temp_object->runtime.curve_cache->disp, curve->id.name + 2, true); /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did * not have any segments or otherwise would have generated an empty mesh. */ diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index fa03aec3e08..4aa5bfa04ab 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -866,7 +866,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, tot_elem = mesh->totedge; break; case ME_FSEL: - tot_elem = mesh->totface; + tot_elem = mesh->totpoly; break; } diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index a539aa45cf6..23fa8dd60d5 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1289,13 +1289,9 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) int i, j, numGrids, highGridSize, lowGridSize; const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - /* create subsurf DM from original mesh at high level */ - if (ob->derivedDeform) { - cddm = CDDM_copy(ob->derivedDeform); - } - else { - cddm = CDDM_from_mesh(me); - } + /* Create subsurf DM from original mesh at high level. */ + /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */ + cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, &CD_MASK_BAREMESH); highdm = subsurf_dm_create_local(scene, @@ -1369,12 +1365,8 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) DerivedMesh *cddm, *subdm; const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - if (ob->derivedDeform) { - cddm = CDDM_copy(ob->derivedDeform); - } - else { - cddm = CDDM_from_mesh(me); - } + /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */ + cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, &CD_MASK_BAREMESH); subdm = subsurf_dm_create_local(scene, diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 09581debd99..7aa8837d139 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1499,6 +1499,10 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) fcu->bezt->vec[1][0] = strip->start; fcu->bezt->vec[1][1] = strip->influence; + + /* Respect User Preferences for default interpolation and handles. */ + fcu->bezt->h1 = fcu->bezt->h2 = U.keyhandles_new; + fcu->bezt->ipo = U.ipo_new; } } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index be28ca26459..75e0d044c7c 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1089,7 +1089,11 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, /* keep socket listorder identical, for copying links */ /* ntree is the target tree */ -bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag) +/* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */ +bNode *BKE_node_copy_ex(bNodeTree *ntree, + const bNode *node_src, + const int flag, + const bool unique_name) { bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); bNodeSocket *sock_dst, *sock_src; @@ -1098,7 +1102,9 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag) *node_dst = *node_src; /* can be called for nodes outside a node tree (e.g. clipboard) */ if (ntree) { - nodeUniqueName(ntree, node_dst); + if (unique_name) { + nodeUniqueName(ntree, node_dst); + } BLI_addtail(&ntree->nodes, node_dst); } @@ -1186,7 +1192,7 @@ static void node_set_new_pointers(bNode *node_src, bNode *new_node) bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag) { - bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag); + bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true); node_set_new_pointers(node_src, new_node); return new_node; } @@ -1516,7 +1522,7 @@ void BKE_node_tree_copy_data(Main *UNUSED(bmain), GHash *new_pointers = BLI_ghash_ptr_new("BKE_node_tree_copy_data"); for (const bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) { - bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata); + bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true); BLI_ghash_insert(new_pointers, (void *)node_src, new_node); /* Store mapping to inputs. */ bNodeSocket *new_input_sock = new_node->inputs.first; @@ -1595,7 +1601,7 @@ void BKE_node_tree_copy_data(Main *UNUSED(bmain), bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user) { bNodeTree *ntree_copy; - const int flag = do_id_user ? LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN : 0; + const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN; BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, flag); return ntree_copy; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 10553e73d8d..90205286a72 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -430,7 +430,6 @@ void BKE_object_free_derived_caches(Object *ob) MEM_SAFE_FREE(ob->runtime.bb); object_update_from_subsurf_ccg(ob); - BKE_object_free_derived_mesh_caches(ob); /* Restore initial pointer. */ if (ob->runtime.mesh_orig != NULL) { @@ -457,20 +456,6 @@ void BKE_object_free_derived_caches(Object *ob) DRW_gpencil_freecache(ob); } -void BKE_object_free_derived_mesh_caches(struct Object *ob) -{ - if (ob->derivedFinal) { - ob->derivedFinal->needsFree = 1; - ob->derivedFinal->release(ob->derivedFinal); - ob->derivedFinal = NULL; - } - if (ob->derivedDeform) { - ob->derivedDeform->needsFree = 1; - ob->derivedDeform->release(ob->derivedDeform); - ob->derivedDeform = NULL; - } -} - void BKE_object_free_caches(Object *object) { ModifierData *md; @@ -804,6 +789,8 @@ static const char *get_obdata_defname(int type) return DATA_("Empty"); case OB_GPENCIL: return DATA_("GPencil"); + case OB_LIGHTPROBE: + return DATA_("LightProbe"); default: CLOG_ERROR(&LOG, "Internal error, bad type: %d", type); return DATA_("Empty"); @@ -1323,7 +1310,7 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) { copy_v3_v3(ob_tar->loc, ob_src->loc); copy_v3_v3(ob_tar->rot, ob_src->rot); - copy_v3_v3(ob_tar->quat, ob_src->quat); + copy_v4_v4(ob_tar->quat, ob_src->quat); copy_v3_v3(ob_tar->rotAxis, ob_src->rotAxis); ob_tar->rotAngle = ob_src->rotAngle; ob_tar->rotmode = ob_src->rotmode; @@ -1425,9 +1412,6 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata); - ob_dst->derivedDeform = NULL; - ob_dst->derivedFinal = NULL; - BLI_listbase_clear((ListBase *)&ob_dst->drawdata); BLI_listbase_clear(&ob_dst->pc_ids); @@ -2330,40 +2314,38 @@ static void give_parvert(Object *par, int nr, float vec[3]) int count = 0; const int numVerts = me_eval->totvert; - if (nr < numVerts) { - if (em && me_eval->runtime.is_original) { - if (em->bm->elem_table_dirty & BM_VERT) { + if (em && me_eval->runtime.is_original) { + if (em->bm->elem_table_dirty & BM_VERT) { #ifdef VPARENT_THREADING_HACK - BLI_mutex_lock(&vparent_lock); - if (em->bm->elem_table_dirty & BM_VERT) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - BLI_mutex_unlock(&vparent_lock); -#else - BLI_assert(!"Not safe for threading"); + BLI_mutex_lock(&vparent_lock); + if (em->bm->elem_table_dirty & BM_VERT) { BM_mesh_elem_table_ensure(em->bm, BM_VERT); -#endif } + BLI_mutex_unlock(&vparent_lock); +#else + BLI_assert(!"Not safe for threading"); + BM_mesh_elem_table_ensure(em->bm, BM_VERT); +#endif } + } - if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) && - !(em && me_eval->runtime.is_original)) { - const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); - /* Get the average of all verts with (original index == nr). */ - for (int i = 0; i < numVerts; i++) { - if (index[i] == nr) { - add_v3_v3(vec, me_eval->mvert[i].co); - count++; - } - } - } - else { - if (nr < numVerts) { - add_v3_v3(vec, me_eval->mvert[nr].co); + if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) && + !(em && me_eval->runtime.is_original)) { + const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); + /* Get the average of all verts with (original index == nr). */ + for (int i = 0; i < numVerts; i++) { + if (index[i] == nr) { + add_v3_v3(vec, me_eval->mvert[i].co); count++; } } } + else { + if (nr < numVerts) { + add_v3_v3(vec, me_eval->mvert[nr].co); + count++; + } + } if (count == 0) { /* keep as 0, 0, 0 */ diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 21ca5e6d6a6..366fd0950fa 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -163,9 +163,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL; #else BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_mesh : NULL; - if (em && em->ob != ob) { - em = NULL; - } #endif CustomData_MeshMasks cddata_masks = scene->customdata_mask; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 584f1ab1b0c..46c2f735761 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -79,7 +79,7 @@ const char PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255}; const char PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255}; const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; -static eOverlayControlFlags overlay_flags = 0; +static ePaintOverlayControlFlags overlay_flags = 0; void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex) { @@ -120,7 +120,7 @@ void BKE_paint_invalidate_overlay_all(void) PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY | PAINT_OVERLAY_INVALID_CURVE); } -eOverlayControlFlags BKE_paint_get_overlay_flags(void) +ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void) { return overlay_flags; } @@ -143,7 +143,7 @@ void BKE_paint_set_overlay_override(eOverlayFlags flags) } } -void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag) +void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag) { overlay_flags &= ~(flag); } @@ -1019,15 +1019,12 @@ static void sculptsession_free_pbvh(Object *object) ss->pbvh = NULL; } - if (ss->pmap) { - MEM_freeN(ss->pmap); - ss->pmap = NULL; - } + MEM_SAFE_FREE(ss->pmap); - if (ss->pmap_mem) { - MEM_freeN(ss->pmap_mem); - ss->pmap_mem = NULL; - } + MEM_SAFE_FREE(ss->pmap_mem); + + MEM_SAFE_FREE(ss->preview_vert_index_list); + ss->preview_vert_index_count = 0; } void BKE_sculptsession_bm_to_me_for_render(Object *object) @@ -1096,6 +1093,14 @@ void BKE_sculptsession_free(Object *ob) MEM_freeN(ss->preview_vert_index_list); } + if (ss->pose_ik_chain_preview) { + for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) { + MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments[i].weights); + } + MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments); + MEM_SAFE_FREE(ss->pose_ik_chain_preview); + } + BKE_sculptsession_free_vwpaint_data(ob->sculpt); MEM_freeN(ss); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index ded38cf562f..97fcef4fd27 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3246,22 +3246,24 @@ static void psys_cache_edit_paths_iter(void *__restrict iter_data_v, } } else { + /* HACK(fclem): Instead of setting the color we pass the select state in the red channel. + * This is then picked up in DRW and the gpu shader will do the color interpolation. */ if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) { if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) { - copy_v3_v3(ca->col, iter_data->sel_col); + ca->col[0] = 1.0f; } else { keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); - interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime); + ca->col[0] = 1.0f - keytime; } } else { if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) { keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); - interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime); + ca->col[0] = keytime; } else { - copy_v3_v3(ca->col, iter_data->nosel_col); + ca->col[0] = 0.0f; } } } @@ -3565,7 +3567,9 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob, psys->totpart = 0; psys->flag = PSYS_CURRENT; - psys->cfra = BKE_scene_frame_to_ctime(scene, CFRA + 1); + if (scene != NULL) { + psys->cfra = BKE_scene_frame_to_ctime(scene, CFRA + 1); + } DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); @@ -3582,14 +3586,47 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob return; } - /* clear all other appearances of this pointer (like on manta flow modifier) */ + /* Clear particle system in fluid modifier. */ if ((md = modifiers_findByType(ob, eModifierType_Fluid))) { FluidModifierData *mmd = (FluidModifierData *)md; + + /* Clear particle system pointer in flow settings. */ if ((mmd->type == MOD_FLUID_TYPE_FLOW) && mmd->flow && mmd->flow->psys) { if (mmd->flow->psys == psys) { mmd->flow->psys = NULL; } } + /* Clear particle flag in domain settings when removing particle system manually. */ + if (mmd->type == MOD_FLUID_TYPE_DOMAIN) { + if (psys->part->type == PART_FLUID_FLIP) { + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP; + } + if (psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_SPRAYFOAM || + psys->part->type == PART_FLUID_SPRAYBUBBLE || + psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) { + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY; + } + if (psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_SPRAYFOAM || + psys->part->type == PART_FLUID_FOAMBUBBLE || + psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) { + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM; + } + if (psys->part->type == PART_FLUID_BUBBLE || psys->part->type == PART_FLUID_FOAMBUBBLE || + psys->part->type == PART_FLUID_SPRAYBUBBLE || + psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) { + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE; + } + if (psys->part->type == PART_FLUID_TRACER) { + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER; + } + + /* Disable combined export if combined particle system was deleted. */ + if (psys->part->type == PART_FLUID_SPRAYFOAM || psys->part->type == PART_FLUID_SPRAYBUBBLE || + psys->part->type == PART_FLUID_FOAMBUBBLE || + psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) { + mmd->domain->sndparticle_combined_export = SNDPARTICLE_COMBINED_EXPORT_OFF; + } + } } if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) { diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 34f2aa73817..172940760f9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4137,6 +4137,34 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ } } +static bool particles_has_flip(short parttype) +{ + return (parttype == PART_FLUID_FLIP); +} + +static bool particles_has_tracer(short parttype) +{ + return (parttype == PART_FLUID_TRACER); +} + +static bool particles_has_spray(short parttype) +{ + return ((parttype == PART_FLUID_SPRAY) || (parttype == PART_FLUID_SPRAYFOAM) || + (parttype == PART_FLUID_SPRAYFOAMBUBBLE)); +} + +static bool particles_has_bubble(short parttype) +{ + return ((parttype == PART_FLUID_BUBBLE) || (parttype == PART_FLUID_FOAMBUBBLE) || + (parttype == PART_FLUID_SPRAYFOAMBUBBLE)); +} + +static bool particles_has_foam(short parttype) +{ + return ((parttype == PART_FLUID_FOAM) || (parttype == PART_FLUID_SPRAYFOAM) || + (parttype == PART_FLUID_SPRAYFOAMBUBBLE)); +} + static void particles_fluid_step(ParticleSimulationData *sim, int cfra, const bool use_render_params) @@ -4173,15 +4201,15 @@ static void particles_fluid_step(ParticleSimulationData *sim, float min[3], max[3], size[3], cell_size_scaled[3], max_size; /* Sanity check: parts also enabled in fluid domain? */ - if ((part->type == PART_FLUID_FLIP && + if ((particles_has_flip(part->type) && (mds->particle_type & FLUID_DOMAIN_PARTICLE_FLIP) == 0) || - (part->type == PART_FLUID_SPRAY && + (particles_has_spray(part->type) && (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) == 0) || - (part->type == PART_FLUID_BUBBLE && + (particles_has_bubble(part->type) && (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) == 0) || - (part->type == PART_FLUID_FOAM && + (particles_has_foam(part->type) && (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) == 0) || - (part->type == PART_FLUID_TRACER && + (particles_has_tracer(part->type) && (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) == 0)) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), @@ -4194,23 +4222,23 @@ static void particles_fluid_step(ParticleSimulationData *sim, if (part->type == PART_FLUID_FLIP) { tottypepart = totpart = manta_liquid_get_num_flip_particles(mds->fluid); } - if ((part->type == PART_FLUID_SPRAY) || (part->type == PART_FLUID_BUBBLE) || - (part->type == PART_FLUID_FOAM) || (part->type == PART_FLUID_TRACER)) { + if (particles_has_spray(part->type) || particles_has_bubble(part->type) || + particles_has_foam(part->type) || particles_has_tracer(part->type)) { totpart = manta_liquid_get_num_snd_particles(mds->fluid); /* tottypepart is the amount of particles of a snd particle type. */ for (p = 0; p < totpart; p++) { flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p); - if ((part->type & PART_FLUID_SPRAY) && (flagActivePart & PARTICLE_TYPE_SPRAY)) { + if (particles_has_spray(part->type) && (flagActivePart & PARTICLE_TYPE_SPRAY)) { tottypepart++; } - if ((part->type & PART_FLUID_BUBBLE) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) { + if (particles_has_bubble(part->type) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) { tottypepart++; } - if ((part->type & PART_FLUID_FOAM) && (flagActivePart & PARTICLE_TYPE_FOAM)) { + if (particles_has_foam(part->type) && (flagActivePart & PARTICLE_TYPE_FOAM)) { tottypepart++; } - if ((part->type & PART_FLUID_TRACER) && (flagActivePart & PARTICLE_TYPE_TRACER)) { + if (particles_has_tracer(part->type) && (flagActivePart & PARTICLE_TYPE_TRACER)) { tottypepart++; } } @@ -4261,8 +4289,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, velY = manta_liquid_get_flip_particle_velocity_y_at(mds->fluid, p); velZ = manta_liquid_get_flip_particle_velocity_z_at(mds->fluid, p); } - else if ((part->type == PART_FLUID_SPRAY) || (part->type == PART_FLUID_BUBBLE) || - (part->type == PART_FLUID_FOAM) || (part->type == PART_FLUID_TRACER)) { + else if (particles_has_spray(part->type) || particles_has_bubble(part->type) || + particles_has_foam(part->type) || particles_has_tracer(part->type)) { flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p); resX = (float)manta_liquid_get_particle_res_x(mds->fluid); @@ -4292,16 +4320,16 @@ static void particles_fluid_step(ParticleSimulationData *sim, /* Type of particle must match current particle system type * (only important for snd particles). */ - if ((flagActivePart & PARTICLE_TYPE_SPRAY) && (part->type & PART_FLUID_SPRAY) == 0) { + if ((flagActivePart & PARTICLE_TYPE_SPRAY) && !particles_has_spray(part->type)) { continue; } - if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && (part->type & PART_FLUID_BUBBLE) == 0) { + if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && !particles_has_bubble(part->type)) { continue; } - if ((flagActivePart & PARTICLE_TYPE_FOAM) && (part->type & PART_FLUID_FOAM) == 0) { + if ((flagActivePart & PARTICLE_TYPE_FOAM) && !particles_has_foam(part->type)) { continue; } - if ((flagActivePart & PARTICLE_TYPE_TRACER) && (part->type & PART_FLUID_TRACER) == 0) { + if ((flagActivePart & PARTICLE_TYPE_TRACER) && !particles_has_tracer(part->type)) { continue; } # if 0 @@ -4844,9 +4872,9 @@ void particle_system_update(struct Depsgraph *depsgraph, hair_step(&sim, cfra, use_render_params); } } - else if ((part->type == PART_FLUID_FLIP) || (part->type == PART_FLUID_SPRAY) || - (part->type == PART_FLUID_BUBBLE) || (part->type == PART_FLUID_FOAM) || - (part->type == PART_FLUID_TRACER)) { + else if (particles_has_flip(part->type) || particles_has_spray(part->type) || + particles_has_bubble(part->type) || particles_has_foam(part->type) || + particles_has_tracer(part->type)) { particles_fluid_step(&sim, (int)cfra, use_render_params); } else { diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 01612ded396..ec520e188f1 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1120,7 +1120,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata, if (node->flag & PBVH_Leaf) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) { if (vd.mask && *vd.mask < 1.0f) { has_unmasked = true; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index bfaea9d438b..75b9f558e90 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -374,6 +374,13 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons sce_dst->preview = NULL; } + BKE_scene_copy_data_eevee(sce_dst, sce_src); +} + +void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src) +{ + /* Copy eevee data between scenes. */ + sce_dst->eevee = sce_src->eevee; sce_dst->eevee.light_cache = NULL; sce_dst->eevee.light_cache_info[0] = '\0'; /* TODO Copy the cache. */ @@ -401,9 +408,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) sce_copy->unit = sce->unit; sce_copy->physics_settings = sce->physics_settings; sce_copy->audio = sce->audio; - sce_copy->eevee = sce->eevee; - sce_copy->eevee.light_cache = NULL; - sce_copy->eevee.light_cache_info[0] = '\0'; + BKE_scene_copy_data_eevee(sce_copy, sce); if (sce->id.properties) { sce_copy->id.properties = IDP_CopyProperty(sce->id.properties); @@ -1412,6 +1417,19 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on if (run_callbacks) { BKE_callback_exec_id_depsgraph( bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST); + + /* It is possible that the custom callback modified scene and removed some IDs from the main + * database. In this case DEG_ids_clear_recalc() will crash because it iterates over all IDs + * which depsgraph was built for. + * + * The solution is to update relations prior to this call, avoiding access to freed IDs. + * Should be safe because relations update is supposed to preserve flags of all IDs which are + * still a part of the dependency graph. If an ID is kicked out of the dependency graph it + * should also be fine because when/if it's added to another dependency graph it will need to + * be tagged for an update anyway. + * + * If there are no relations changed by the callback this call will do nothing. */ + DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); } /* Inform editors about possible changes. */ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false); @@ -1477,6 +1495,10 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain) /* Notify editors and python about recalc. */ if (pass == 0) { BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST); + + /* NOTE: Similar to this case in scene_graph_update_tagged(). Need to ensure that + * DEG_ids_clear_recalc() doesn't access freed memory of possibly removed ID. */ + DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); } /* Inform editors about possible changes. */ @@ -2253,7 +2275,16 @@ void BKE_scene_cursor_mat3_to_rot(View3DCursor *cursor, const float mat[3][3], b switch (cursor->rotation_mode) { case ROT_MODE_QUAT: { - mat3_normalized_to_quat(cursor->rotation_quaternion, mat); + float quat[4]; + mat3_normalized_to_quat(quat, mat); + if (use_compat) { + float quat_orig[4]; + copy_v4_v4(quat_orig, cursor->rotation_quaternion); + quat_to_compatible_quat(cursor->rotation_quaternion, quat, quat_orig); + } + else { + copy_v4_v4(cursor->rotation_quaternion, quat); + } break; } case ROT_MODE_AXISANGLE: { @@ -2279,7 +2310,14 @@ void BKE_scene_cursor_quat_to_rot(View3DCursor *cursor, const float quat[4], boo switch (cursor->rotation_mode) { case ROT_MODE_QUAT: { - copy_qt_qt(cursor->rotation_quaternion, quat); + if (use_compat) { + float quat_orig[4]; + copy_v4_v4(quat_orig, cursor->rotation_quaternion); + quat_to_compatible_quat(cursor->rotation_quaternion, quat, quat_orig); + } + else { + copy_qt_qt(cursor->rotation_quaternion, quat); + } break; } case ROT_MODE_AXISANGLE: { diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 236fb43e89c..8dfe01ae1fd 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -3888,7 +3888,7 @@ static ImBuf *do_text_effect(const SeqRenderData *context, int font = blf_mono_font_render; int line_height; int y_ofs, x, y; - float proxy_size_comp; + double proxy_size_comp; if (data->text_blf_id == SEQ_FONT_NOT_LOADED) { data->text_blf_id = -1; @@ -3906,15 +3906,11 @@ static ImBuf *do_text_effect(const SeqRenderData *context, display = IMB_colormanagement_display_get_named(display_device); /* Compensate text size for preview render size. */ - if (ELEM( - context->preview_render_size, SEQ_PROXY_RENDER_SIZE_SCENE, SEQ_PROXY_RENDER_SIZE_FULL)) { - proxy_size_comp = context->scene->r.size / 100.0f; - } - else if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_100) { - proxy_size_comp = 1.0f; + if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_SCENE) { + proxy_size_comp = context->scene->r.size / 100.0; } else { - proxy_size_comp = context->preview_render_size / 100.0f; + proxy_size_comp = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size); } /* set before return */ diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index 6dd1c47407f..8c9097e1d4e 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -416,9 +416,7 @@ static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) pfjob->stop = false; pfjob->running = true; - if (&pfjob->threads) { - BLI_threadpool_remove(&pfjob->threads, pfjob); - } + BLI_threadpool_remove(&pfjob->threads, pfjob); BLI_threadpool_insert(&pfjob->threads, pfjob); return pfjob; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index b05724ca6af..747ce18cada 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -38,6 +38,7 @@ #include "DNA_anim_types.h" #include "DNA_object_types.h" #include "DNA_sound_types.h" +#include "DNA_space_types.h" #include "BLI_math.h" #include "BLI_fileops.h" @@ -1587,35 +1588,32 @@ typedef struct SeqIndexBuildContext { #define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE) -static IMB_Proxy_Size seq_rendersize_to_proxysize(int size) +static IMB_Proxy_Size seq_rendersize_to_proxysize(int render_size) { - if (size >= 100) { - return IMB_PROXY_NONE; + switch (render_size) { + case SEQ_PROXY_RENDER_SIZE_25: + return IMB_PROXY_25; + case SEQ_PROXY_RENDER_SIZE_50: + return IMB_PROXY_50; + case SEQ_PROXY_RENDER_SIZE_75: + return IMB_PROXY_75; + case SEQ_PROXY_RENDER_SIZE_100: + return IMB_PROXY_100; } - if (size >= 99) { - return IMB_PROXY_100; - } - if (size >= 75) { - return IMB_PROXY_75; - } - if (size >= 50) { - return IMB_PROXY_50; - } - return IMB_PROXY_25; + return IMB_PROXY_NONE; } -static double seq_rendersize_to_scale_factor(int size) +double BKE_sequencer_rendersize_to_scale_factor(int render_size) { - if (size >= 99) { - return 1.0; - } - if (size >= 75) { - return 0.75; + switch (render_size) { + case SEQ_PROXY_RENDER_SIZE_25: + return 0.25; + case SEQ_PROXY_RENDER_SIZE_50: + return 0.50; + case SEQ_PROXY_RENDER_SIZE_75: + return 0.75; } - if (size >= 50) { - return 0.50; - } - return 0.25; + return 1.0; } /* the number of files will vary according to the stereo format */ @@ -1773,8 +1771,12 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) } } -static bool seq_proxy_get_fname( - Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const int view_id) +static bool seq_proxy_get_fname(Editing *ed, + Sequence *seq, + int cfra, + eSpaceSeq_Proxy_RenderSize render_size, + char *name, + const int view_id) { int frameno; char dir[PROXY_MAXFILE]; @@ -1868,19 +1870,21 @@ static bool seq_proxy_get_fname( /* generate a separate proxy directory for each preview size */ + int proxy_size_number = BKE_sequencer_rendersize_to_scale_factor(render_size) * 100; + if (seq->type == SEQ_TYPE_IMAGE) { BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy%s", dir, - render_size, + proxy_size_number, BKE_sequencer_give_stripelem(seq, cfra)->name, suffix); frameno = 1; } else { frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; - BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix); + BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix); } BLI_path_abs(name, BKE_main_blendfile_path_from_global()); @@ -1896,7 +1900,6 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c char name[PROXY_MAXFILE]; IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); int size_flags; - int render_size = context->preview_render_size; StripProxy *proxy = seq->strip->proxy; Editing *ed = context->scene->ed; StripAnim *sanim; @@ -1905,22 +1908,17 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c return NULL; } - /* dirty hack to distinguish 100% render size from PROXY_100 */ - if (render_size == 99) { - render_size = 100; - } - size_flags = proxy->build_size_flags; /* only use proxies, if they are enabled (even if present!) */ - if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) { + if (psize == IMB_PROXY_NONE || (size_flags & psize) == 0) { return NULL; } if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; if (proxy->anim == NULL) { - if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) { + if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) { return NULL; } @@ -1939,7 +1937,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); } - if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) { + if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) { return NULL; } @@ -2700,10 +2698,10 @@ static ImBuf *input_preprocess(const SeqRenderData *context, int sx, sy, dx, dy; if (is_proxy_image) { - double f = seq_rendersize_to_scale_factor(context->preview_render_size); + double f = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size); if (f != 1.0) { - IMB_scalefastImBuf(ibuf, ibuf->x / f, ibuf->y / f); + IMB_scalefastImBuf(ibuf, ibuf->x * f, ibuf->y * f); } } @@ -3151,12 +3149,11 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (context->scene->r.scemode & R_MULTIVIEW) != 0; - IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size); + IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); if ((seq->flag & SEQ_USE_PROXY) == 0) { - proxy_size = IMB_PROXY_NONE; + psize = IMB_PROXY_NONE; } - /* load all the videos */ seq_open_anim_file(context->scene, seq, false); @@ -3181,10 +3178,10 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, nr + seq->anim_startofs, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, - proxy_size); + psize); /* fetching for requested proxy size failed, try fetching the original instead */ - if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) { + if (!ibuf_arr[i] && psize != IMB_PROXY_NONE) { ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, seq->strip->proxy ? seq->strip->proxy->tc : @@ -3250,10 +3247,10 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, - proxy_size); + psize); /* fetching for requested proxy size failed, try fetching the original instead */ - if (!ibuf && proxy_size != IMB_PROXY_NONE) { + if (!ibuf && psize != IMB_PROXY_NONE) { ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, @@ -3280,6 +3277,7 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence ImBuf *ibuf = NULL; MovieClipUser user; float tloc[2], tscale, tangle; + IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); if (!seq->clip) { return NULL; @@ -3292,7 +3290,7 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER; user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL; - switch (seq_rendersize_to_proxysize(context->preview_render_size)) { + switch (psize) { case IMB_PROXY_NONE: user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL; break; @@ -3876,7 +3874,8 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, if (ibuf) { if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) { - is_proxy_image = (context->preview_render_size != 100); + is_proxy_image = seq_rendersize_to_proxysize(context->preview_render_size) != + IMB_PROXY_NONE; } } } @@ -4920,7 +4919,10 @@ static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir) return tot_ofs; } -bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, Scene *evil_scene) +bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, + Scene *evil_scene, + ListBase *markers, + const bool use_sync_markers) { /* note: seq->tmp is used to tag strips to move */ @@ -4937,6 +4939,16 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, Scene *evil_scene) seq->flag &= ~SEQ_OVERLAP; } } + + if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) { + TimeMarker *marker; + /* affect selected markers - it's unlikely that we will want to affect all in this way? */ + for (marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + marker->frame += offset; + } + } + } } return offset ? false : true; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index c6cac2057d6..49a295c6a9e 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -794,54 +794,59 @@ static bool target_project_tri_correct(void *UNUSED(userdata), float x_next[3]) { /* Insignificant correction threshold */ - const float epsilon = 1e-6f; - const float dir_epsilon = 0.05f; + const float epsilon = 1e-5f; + /* Dot product threshold for checking if step is 'clearly' pointing outside. */ + const float dir_epsilon = 0.5f; bool fixed = false, locked = false; - /* Weight 0 and 1 boundary check. */ - for (int i = 0; i < 2; i++) { - if (step[i] > x[i]) { - if (step[i] > dir_epsilon * fabsf(step[1 - i])) { - /* Abort if the solution is clearly outside the domain. */ - if (x[i] < epsilon) { - return false; - } + /* The barycentric coordinate domain is a triangle bounded by + * the X and Y axes, plus the x+y=1 diagonal. First, clamp the + * movement against the diagonal. Note that step is subtracted. */ + float sum = x[0] + x[1]; + float sstep = -(step[0] + step[1]); - /* Scale a significant step down to arrive at the boundary. */ - mul_v3_fl(step, x[i] / step[i]); - fixed = true; - } - else { - /* Reset precision errors to stay at the boundary. */ - step[i] = x[i]; - fixed = locked = true; - } - } - } + if (sum + sstep > 1.0f) { + float ldist = 1.0f - sum; - /* Weight 2 boundary check. */ - float sum = x[0] + x[1]; - float sstep = step[0] + step[1]; + /* If already at the boundary, slide along it. */ + if (ldist < epsilon * (float)M_SQRT2) { + float step_len = len_v2(step); - if (sum - sstep > 1.0f) { - if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) { /* Abort if the solution is clearly outside the domain. */ - if (sum > 1.0f - epsilon) { + if (step_len > epsilon && sstep > step_len * dir_epsilon * (float)M_SQRT2) { return false; } + /* Project the new position onto the diagonal. */ + add_v2_fl(step, (sum + sstep - 1.0f) * 0.5f); + fixed = locked = true; + } + else { /* Scale a significant step down to arrive at the boundary. */ - mul_v3_fl(step, (1.0f - sum) / -sstep); + mul_v3_fl(step, ldist / sstep); fixed = true; } - else { - /* Reset precision errors to stay at the boundary. */ - if (locked) { - step[0] = step[1] = 0.0f; + } + + /* Weight 0 and 1 boundary checks - along axis. */ + for (int i = 0; i < 2; i++) { + if (step[i] > x[i]) { + /* If already at the boundary, slide along it. */ + if (x[i] < epsilon) { + float step_len = len_v2(step); + + /* Abort if the solution is clearly outside the domain. */ + if (step_len > epsilon && (locked || step[i] > step_len * dir_epsilon)) { + return false; + } + + /* Reset precision errors to stay at the boundary. */ + step[i] = x[i]; + fixed = true; } else { - step[0] -= 0.5f * sstep; - step[1] = -step[0]; + /* Scale a significant step down to arrive at the boundary. */ + mul_v3_fl(step, x[i] / step[i]); fixed = true; } } @@ -1506,7 +1511,7 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C, { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); struct Scene *sce = CTX_data_scene(C); - ShrinkwrapModifierData ssmd = {0}; + ShrinkwrapModifierData ssmd = {{0}}; ModifierEvalContext ctx = {depsgraph, ob_source, 0}; int totvert; @@ -1527,7 +1532,7 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C, void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target) { - ShrinkwrapModifierData ssmd = {0}; + ShrinkwrapModifierData ssmd = {{0}}; int totvert; ssmd.target = ob_target; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index b56403dfb6d..3bbd909800b 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -3132,8 +3132,10 @@ SoftBody *sbNew(Scene *scene) sb->inpush = 0.5f; sb->interval = 10; - sb->sfra = scene->r.sfra; - sb->efra = scene->r.efra; + if (scene != NULL) { + sb->sfra = scene->r.sfra; + sb->efra = scene->r.efra; + } sb->colball = 0.49f; sb->balldamp = 0.50f; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index d42436ecb40..84d135c7f32 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -411,7 +411,7 @@ void BKE_sound_delete_cache(bSound *sound) } } -static void sound_load_audio(Main *bmain, bSound *sound) +static void sound_load_audio(Main *bmain, bSound *sound, bool free_waveform) { if (sound->cache) { @@ -425,7 +425,9 @@ static void sound_load_audio(Main *bmain, bSound *sound) sound->playback_handle = NULL; } - BKE_sound_free_waveform(sound); + if (free_waveform) { + BKE_sound_free_waveform(sound); + } /* XXX unused currently */ # if 0 @@ -488,7 +490,7 @@ static void sound_load_audio(Main *bmain, bSound *sound) void BKE_sound_load(Main *bmain, bSound *sound) { sound_verify_evaluated_id(&sound->id); - sound_load_audio(bmain, sound); + sound_load_audio(bmain, sound, true); } AUD_Device *BKE_sound_mixdown(Scene *scene, AUD_DeviceSpecs specs, int start, float volume) @@ -902,7 +904,7 @@ void BKE_sound_read_waveform(Main *bmain, bSound *sound, short *stop) bool need_close_audio_handles = false; if (sound->playback_handle == NULL) { /* TODO(sergey): Make it fully independent audio handle. */ - sound_load_audio(bmain, sound); + sound_load_audio(bmain, sound, true); need_close_audio_handles = true; } @@ -1096,7 +1098,9 @@ bool BKE_sound_info_get(struct Main *main, struct bSound *sound, SoundInfo *soun return sound_info_from_playback_handle(sound->playback_handle, sound_info); } /* TODO(sergey): Make it fully independent audio handle. */ - sound_load_audio(main, sound); + /* Don't free waveforms during non-destructive queries. + * This causes unnecessary recalculation - see T69921 */ + sound_load_audio(main, sound, false); const bool result = sound_info_from_playback_handle(sound->playback_handle, sound_info); sound_free_audio(sound); return result; diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index a02ff98a38a..9008348ed3b 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -1668,7 +1668,8 @@ StudioLight *BKE_studiolight_create(const char *path, const float light_ambient[3]) { StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_USER_DEFINED | - STUDIOLIGHT_TYPE_STUDIO); + STUDIOLIGHT_TYPE_STUDIO | + STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS); char filename[FILE_MAXFILE]; BLI_split_file_part(path, filename, FILE_MAXFILE); @@ -1688,7 +1689,7 @@ StudioLight *BKE_studiolight_create(const char *path, StudioLight *BKE_studiolight_studio_edit_get(void) { static StudioLight sl = {0}; - sl.flag = STUDIOLIGHT_TYPE_STUDIO; + sl.flag = STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS; memcpy(sl.light, U.light_param, sizeof(*sl.light) * 4); memcpy(sl.light_ambient, U.light_ambient, sizeof(*sl.light_ambient) * 3); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 11d2314ace3..33a9875151a 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2519,7 +2519,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags) struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, struct SubsurfModifierData *smd, - struct Scene *scene, + const struct Scene *scene, float (*vertCos)[3], SubsurfFlags flags) { diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 3e449fa6b25..f58c20a7d72 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -247,8 +247,12 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain, void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout) { - id_us_min(&layout->screen->id); - BKE_id_free(bmain, layout->screen); + /* Screen should usually be set, but we call this from file reading to get rid of invalid + * layouts. */ + if (layout->screen) { + id_us_min(&layout->screen->id); + BKE_id_free(bmain, layout->screen); + } BLI_freelinkN(&workspace->layouts, layout); } |