diff options
Diffstat (limited to 'source/blender/blenkernel')
175 files changed, 16250 insertions, 5462 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index a026cc2e76e..65e7d47c46c 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -97,7 +97,6 @@ struct ColorBand; struct GPUVertexAttribs; struct GPUDrawObject; struct BMEditMesh; -struct ListBase; struct PBVH; /* number of sub-elements each mesh element has (for interpolation) */ @@ -115,11 +114,6 @@ typedef struct DMCoNo { float no[3]; } DMCoNo; -typedef struct DMGridAdjacency { - int index[4]; - int rotation[4]; -} DMGridAdjacency; - /* keep in sync with MFace/MPoly types */ typedef struct DMFlagMat { short mat_nr; @@ -291,7 +285,6 @@ struct DerivedMesh { int (*getNumGrids)(DerivedMesh *dm); int (*getGridSize)(DerivedMesh *dm); struct CCGElem **(*getGridData)(DerivedMesh * dm); - DMGridAdjacency *(*getGridAdjacency)(DerivedMesh * dm); int *(*getGridOffset)(DerivedMesh * dm); void (*getGridKey)(DerivedMesh *dm, struct CCGKey *key); DMFlagMat *(*getGridFlagMats)(DerivedMesh * dm); diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 57ba6fd55ca..fdb465f7105 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -46,8 +46,6 @@ struct bItasc; struct bPoseChannel; struct Main; struct Object; -struct Scene; -struct ID; /* Kernel prototypes */ #ifdef __cplusplus @@ -161,6 +159,9 @@ void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); /* sets constraint flags */ void BKE_pose_update_constraint_flags(struct bPose *pose); +/* tag constraint flags for update */ +void BKE_pose_tag_update_constraint_flags(struct bPose *pose); + /* return the name of structure pointed by pose->ikparam */ const char *BKE_pose_ikparam_get_name(struct bPose *pose); @@ -197,6 +198,9 @@ bool BKE_pose_copy_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void BKE_pose_rest(struct bPose *pose); +/* Tag pose for recalc. Also tag all related data to be recalc. */ +void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose); + #ifdef __cplusplus }; #endif diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h index 9c09fffe0a0..74c1edd1c1b 100644 --- a/source/blender/blenkernel/BKE_addon.h +++ b/source/blender/blenkernel/BKE_addon.h @@ -38,7 +38,7 @@ typedef struct bAddonPrefType { bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet); void BKE_addon_pref_type_add(bAddonPrefType *apt); -void BKE_addon_pref_type_remove(bAddonPrefType *apt); +void BKE_addon_pref_type_remove(const bAddonPrefType *apt); void BKE_addon_pref_type_init(void); void BKE_addon_pref_type_free(void); diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index d1a5bcbf8aa..90af9a15a97 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -36,13 +36,21 @@ struct bContext; struct EvaluationContext; struct Path; struct Object; -struct PartEff; struct Scene; struct ListBase; struct bAnimVizSettings; struct bMotionPath; struct bPoseChannel; struct ReportList; +struct GHash; +struct DupliCache; +struct DupliObject; +struct DupliObjectData; +struct DerivedMesh; +struct Strands; +struct StrandsChildren; +struct DupliCacheIterator; +struct CacheLibrary; /* ---------------------------------------------------- */ /* Animation Visualization */ @@ -68,11 +76,43 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl /* ---------------------------------------------------- */ /* Dupli-Geometry */ -struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update); -struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob); +struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, bool update); +struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); +struct ListBase *group_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, bool update); +struct ListBase *group_duplilist(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group); void free_object_duplilist(struct ListBase *lb); int count_duplilist(struct Object *ob); +void BKE_object_dupli_cache_update(struct Scene *scene, struct Object *ob, struct EvaluationContext *eval_ctx, float frame); +void BKE_object_dupli_cache_clear(struct Object *ob); +void BKE_object_dupli_cache_free(struct Object *ob); +bool BKE_object_dupli_cache_contains(struct Object *ob, struct Object *other); +struct DupliObjectData *BKE_dupli_cache_find_data(struct DupliCache *dupcache, struct Object *ob); + +void BKE_dupli_object_data_init(struct DupliObjectData *data, struct Object *ob); +/* does not free data itself */ +void BKE_dupli_object_data_clear(struct DupliObjectData *data); +void BKE_dupli_object_data_set_mesh(struct DupliObjectData *data, struct DerivedMesh *dm); +void BKE_dupli_object_data_add_strands(struct DupliObjectData *data, const char *name, struct Strands *strands); +void BKE_dupli_object_data_add_strands_children(struct DupliObjectData *data, const char *name, struct StrandsChildren *children); +void BKE_dupli_object_data_find_strands(struct DupliObjectData *data, const char *name, struct Strands **r_strands, struct StrandsChildren **r_children); +bool BKE_dupli_object_data_acquire_strands(struct DupliObjectData *data, struct Strands *strands); +bool BKE_dupli_object_data_acquire_strands_children(struct DupliObjectData *data, struct StrandsChildren *children); + +struct DupliCache *BKE_dupli_cache_new(void); +void BKE_dupli_cache_free(struct DupliCache *dupcache); +void BKE_dupli_cache_clear(struct DupliCache *dupcache); +void BKE_dupli_cache_clear_instances(struct DupliCache *dupcache); +struct DupliObjectData *BKE_dupli_cache_add_object(struct DupliCache *dupcache, struct Object *ob); +struct DupliObject *BKE_dupli_cache_add_instance(struct DupliCache *dupcache, float obmat[4][4], struct DupliObjectData *data); +void BKE_dupli_cache_from_group(struct Scene *scene, struct Group *group, struct CacheLibrary *cachelib, struct DupliCache *dupcache, struct EvaluationContext *eval_ctx, bool calc_strands_base); + +struct DupliCacheIterator *BKE_dupli_cache_iter_new(struct DupliCache *dupcache); +void BKE_dupli_cache_iter_free(struct DupliCacheIterator *iter); +bool BKE_dupli_cache_iter_valid(struct DupliCacheIterator *iter); +void BKE_dupli_cache_iter_next(struct DupliCacheIterator *iter); +struct DupliObjectData *BKE_dupli_cache_iter_get(struct DupliCacheIterator *iter); + typedef struct DupliExtraData { float obmat[4][4]; unsigned int lay; @@ -83,7 +123,7 @@ typedef struct DupliApplyData { DupliExtraData *extra; } DupliApplyData; -DupliApplyData *duplilist_apply(struct Object *ob, struct ListBase *duplilist); +DupliApplyData *duplilist_apply(struct Object *ob, struct Scene *scene, struct ListBase *duplilist); void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data); void duplilist_free_apply_data(DupliApplyData *apply_data); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 0acfd40a110..dc751747f32 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -56,22 +56,22 @@ bool id_type_can_have_animdata(struct ID *id); struct AnimData *BKE_animdata_from_id(struct ID *id); /* Add AnimData to the given ID-block */ -struct AnimData *BKE_id_add_animdata(struct ID *id); +struct AnimData *BKE_animdata_add_id(struct ID *id); /* Set active action used by AnimData from the given ID-block */ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act); /* Free AnimData */ -void BKE_free_animdata(struct ID *id); +void BKE_animdata_free(struct ID *id); /* Copy AnimData */ -struct AnimData *BKE_copy_animdata(struct AnimData *adt, const bool do_action); +struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); /* Copy AnimData */ -bool BKE_copy_animdata_id(struct ID *id_to, struct ID *id_from, const bool do_action); +bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action); /* Copy AnimData Actions */ -void BKE_copy_animdata_id_action(struct ID *id); +void BKE_animdata_copy_id_action(struct ID *id); /* Merge copies of data from source AnimData block */ typedef enum eAnimData_MergeCopy_Modes { @@ -91,7 +91,7 @@ void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_Mer void BKE_animdata_make_local(struct AnimData *adt); /* Re-Assign ID's */ -void BKE_relink_animdata(struct AnimData *adt); +void BKE_animdata_relink(struct AnimData *adt); /* ************************************* */ /* KeyingSets API */ @@ -134,7 +134,7 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st bool verify_paths); /* Fix all the paths for the entire database... */ -void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName); +void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName); /* Fix the path after removing elements that are not ID (e.g., node) */ void BKE_animdata_fix_paths_remove(struct ID *id, const char *path); @@ -175,6 +175,9 @@ void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct An /* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */ void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime); +/* TODO(sergey): This is mainly a temp public function. */ +struct FCurve; +bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu); /* ------------ Specialized API --------------- */ /* There are a few special tools which require these following functions. They are NOT to be used @@ -192,4 +195,13 @@ void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, /* ************************************* */ +/* ------------ Evaluation API --------------- */ + +struct EvaluationContext; + +void BKE_animsys_eval_animdata(struct EvaluationContext *eval_ctx, struct ID *id); +void BKE_animsys_eval_driver(struct EvaluationContext *eval_ctx, struct ID *id, struct FCurve *fcurve); + +/* ************************************* */ + #endif /* __BKE_ANIMSYS_H__*/ diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index 5e42f17be03..077fe2a629c 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -38,6 +38,11 @@ void BKE_appdir_program_path_init(const char *argv0); const char *BKE_appdir_program_path(void); const char *BKE_appdir_program_dir(void); +/* find python executable */ +bool BKE_appdir_program_python_search( + char *fullpath, const size_t fullpath_len, + const int version_major, const int version_minor); + /* Initialize path to temporary directory. */ void BKE_tempdir_init(char *userdir); void BKE_tempdir_system_init(char *dir); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 66e204e51e0..a834a83ca00 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -36,13 +36,10 @@ struct Bone; struct Main; struct bArmature; -struct bPose; struct bPoseChannel; struct bConstraint; struct Scene; struct Object; -struct MDeformVert; -struct Mesh; struct PoseTree; struct ListBase; @@ -145,6 +142,57 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array #define PBONE_SELECTABLE(arm, bone) \ (PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE)) +/* Evaluation helpers */ +struct bKinematicConstraint; +struct bPose; +struct bSplineIKConstraint; +struct EvaluationContext; + +struct bPoseChannel *BKE_armature_ik_solver_find_root( + struct bPoseChannel *pchan, + struct bKinematicConstraint *data); +struct bPoseChannel *BKE_armature_splineik_solver_find_root( + struct bPoseChannel *pchan, + struct bSplineIKConstraint *data); + +void BKE_pose_splineik_init_tree(struct Scene *scene, struct Object *ob, float ctime); +void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime); + +void BKE_pose_eval_init(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPose *pose); + +void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPoseChannel *pchan); + +void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx, + struct Object *ob, + struct bPoseChannel *pchan); + +void BKE_pose_bone_done(struct EvaluationContext *eval_ctx, + struct bPoseChannel *pchan); + +void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPoseChannel *rootchan); + +void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPoseChannel *rootchan); + +void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct bPose *pose); + +void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx, + struct Object *ob); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 63cc9213b2e..80332c08fc2 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,9 +41,9 @@ extern "C" { /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 273 -#define BLENDER_SUBVERSION 9 -/* 262 was the last editmesh release but it has compatibility code for bmesh data */ +#define BLENDER_VERSION 274 +#define BLENDER_SUBVERSION 5 +/* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 5 @@ -55,7 +55,6 @@ extern "C" { extern char versionstr[]; /* from blender.c */ -struct ListBase; struct MemFile; struct bContext; struct ReportList; @@ -88,21 +87,21 @@ void BKE_userdef_free(void); void BKE_userdef_state(void); /* set this callback when a UI is running */ -void set_blender_test_break_cb(void (*func)(void)); +void BKE_blender_callback_test_break_set(void (*func)(void)); int blender_test_break(void); #define BKE_UNDO_STR_MAX 64 /* global undo */ -extern void BKE_write_undo(struct bContext *C, const char *name); -extern void BKE_undo_step(struct bContext *C, int step); -extern void BKE_undo_name(struct bContext *C, const char *name); -extern int BKE_undo_valid(const char *name); -extern void BKE_reset_undo(void); -extern void BKE_undo_number(struct bContext *C, int nr); -extern const char *BKE_undo_get_name(int nr, int *active); -extern bool BKE_undo_save_file(const char *filename); -extern struct Main *BKE_undo_get_main(struct Scene **scene); +extern void BKE_undo_write(struct bContext *C, const char *name); +extern void BKE_undo_step(struct bContext *C, int step); +extern void BKE_undo_name(struct bContext *C, const char *name); +extern bool BKE_undo_is_valid(const char *name); +extern void BKE_undo_reset(void); +extern void BKE_undo_number(struct bContext *C, int nr); +extern const char *BKE_undo_get_name(int nr, bool *r_active); +extern bool BKE_undo_save_file(const char *filename); +extern struct Main *BKE_undo_get_main(struct Scene **r_scene); /* copybuffer */ void BKE_copybuffer_begin(struct Main *bmain); diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h index 990b414a4cf..10ee504f244 100644 --- a/source/blender/blenkernel/BKE_bpath.h +++ b/source/blender/blenkernel/BKE_bpath.h @@ -48,13 +48,21 @@ void *BKE_bpath_list_backup(struct Main *bmain, const int flag); void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle); void BKE_bpath_list_free(void *ls_handle); -#define BKE_BPATH_TRAVERSE_ABS (1 << 0) /* convert paths to absolute */ -#define BKE_BPATH_TRAVERSE_SKIP_LIBRARY (1 << 2) /* skip library paths */ -#define BKE_BPATH_TRAVERSE_SKIP_PACKED (1 << 3) /* skip packed data */ -#define BKE_BPATH_TRAVERSE_SKIP_MULTIFILE (1 << 4) /* skip paths where a single dir is used with an array of files, eg. - * sequence strip images and pointcache. in this case only use the first - * file, this is needed for directory manipulation functions which might - * otherwise modify the same directory multiple times */ +enum { + /* convert paths to absolute */ + BKE_BPATH_TRAVERSE_ABS = (1 << 0), + /* skip library paths */ + BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1), + /* skip packed data */ + BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2), + /* skip paths where a single dir is used with an array of files, eg. + * sequence strip images and pointcache. in this case only use the first + * file, this is needed for directory manipulation functions which might + * otherwise modify the same directory multiple times */ + BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3), + /* reload data (when the path is edited) */ + BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4), +}; /* high level funcs */ diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 49975fa0276..023303fe602 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -27,14 +27,11 @@ * General operations for brushes. */ -struct ID; struct Brush; struct ImBuf; struct ImagePool; struct Main; -struct rctf; struct Scene; -struct wmOperator; // enum CurveMappingPreset; @@ -82,34 +79,36 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondar /* unified strength size and color */ -float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush); -float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush); +const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush); +const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush); void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]); -int BKE_brush_size_get(const struct Scene *scene, struct Brush *brush); +int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush); void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value); -float BKE_brush_unprojected_radius_get(const struct Scene *scene, struct Brush *brush); +float BKE_brush_unprojected_radius_get(const struct Scene *scene, const struct Brush *brush); void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float value); -float BKE_brush_alpha_get(const struct Scene *scene, struct Brush *brush); +float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush); void BKE_brush_alpha_set(Scene *scene, struct Brush *brush, float alpha); -float BKE_brush_weight_get(const Scene *scene, struct Brush *brush); +float BKE_brush_weight_get(const Scene *scene, const struct Brush *brush); void BKE_brush_weight_set(const Scene *scene, struct Brush *brush, float value); -int BKE_brush_use_locked_size(const struct Scene *scene, struct Brush *brush); -int BKE_brush_use_alpha_pressure(const struct Scene *scene, struct Brush *brush); -int BKE_brush_use_size_pressure(const struct Scene *scene, struct Brush *brush); +int BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush); +int BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush); +int BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush); /* scale unprojected radius to reflect a change in the brush's 2D size */ -void BKE_brush_scale_unprojected_radius(float *unprojected_radius, - int new_brush_size, - int old_brush_size); +void BKE_brush_scale_unprojected_radius( + float *unprojected_radius, + int new_brush_size, + int old_brush_size); /* scale brush size to reflect a change in the brush's unprojected radius */ -void BKE_brush_scale_size(int *BKE_brush_size_get, - float new_unprojected_radius, - float old_unprojected_radius); +void BKE_brush_scale_size( + int *r_brush_size, + float new_unprojected_radius, + float old_unprojected_radius); /* debugging only */ void BKE_brush_debug_print_state(struct Brush *br); diff --git a/source/blender/blenkernel/BKE_cache_library.h b/source/blender/blenkernel/BKE_cache_library.h new file mode 100644 index 00000000000..62ec261f123 --- /dev/null +++ b/source/blender/blenkernel/BKE_cache_library.h @@ -0,0 +1,254 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_CACHE_LIBRARY_H__ +#define __BKE_CACHE_LIBRARY_H__ + +/** \file BKE_cache_library.h + * \ingroup bke + */ + +#include "DNA_cache_library_types.h" + +struct ListBase; +struct Main; +struct bContext; +struct DerivedMesh; +struct Group; +struct Object; +struct Scene; +struct EvaluationContext; +struct ParticleSystem; +struct DupliCache; +struct DupliObjectData; +struct CacheModifier; +struct ID; +struct CacheProcessData; +struct BVHTreeFromMesh; +struct Strands; +struct StrandsChildren; +struct StrandsKeyCacheModifier; +struct Key; +struct KeyBlock; + +struct ClothModifierData; + +struct CacheLibrary *BKE_cache_library_add(struct Main *bmain, const char *name); +struct CacheLibrary *BKE_cache_library_copy(struct CacheLibrary *cachelib); +void BKE_cache_library_free(struct CacheLibrary *cachelib); +void BKE_cache_library_unlink(struct CacheLibrary *cachelib); + +const char *BKE_cache_item_name_prefix(int type); +void BKE_cache_item_name(struct Object *ob, int type, int index, char *name); +int BKE_cache_item_name_length(struct Object *ob, int type, int index); +eCacheReadSampleResult BKE_cache_read_result(int ptc_result); + +bool BKE_cache_library_validate_item(struct CacheLibrary *cachelib, struct Object *ob, int type, int index); + +struct IDProperty *BKE_cache_library_get_input_metadata(struct CacheLibrary *cachelib, bool create); +struct IDProperty *BKE_cache_library_get_output_metadata(struct CacheLibrary *cachelib, bool create); + +/* ========================================================================= */ + +void BKE_cache_library_get_read_flags(struct CacheLibrary *cachelib, bool use_render, bool for_display, bool *read_strands_motion, bool *read_strands_children); + +bool BKE_cache_archive_path_test(struct CacheLibrary *cachelib, const char *path); +void BKE_cache_archive_path_ex(const char *path, struct Library *lib, const char *default_filename, char *result, int max); +void BKE_cache_archive_input_path(struct CacheLibrary *cachelib, char *result, int max); +void BKE_cache_archive_output_path(struct CacheLibrary *cachelib, char *result, int max); + +void BKE_cache_library_dag_recalc_tag(struct EvaluationContext *eval_ctx, struct Main *bmain); + +/*void BKE_cache_library_filter_duplilist(struct CacheLibrary *cachelib, struct ListBase *duplilist);*/ +void BKE_cache_library_tag_used_objects(CacheLibrary *cachelib); + +bool BKE_cache_read_dupli_cache(struct CacheLibrary *cachelib, struct DupliCache *dupcache, + struct Scene *scene, struct Group *dupgroup, float frame, bool use_render, bool for_display); +bool BKE_cache_read_dupli_object(struct CacheLibrary *cachelib, struct DupliObjectData *data, + struct Scene *scene, struct Object *ob, float frame, bool use_render, bool for_display); + +void BKE_cache_process_dupli_cache(struct CacheLibrary *cachelib, struct CacheProcessData *data, + struct Scene *scene, struct Group *dupgroup, float frame_prev, float frame, + bool do_modifiers, bool do_strands_child_deform, bool do_strands_motion); + +/* ========================================================================= */ + +typedef void (*CacheModifier_IDWalkFunc)(void *userdata, struct CacheLibrary *cachelib, struct CacheModifier *md, struct ID **id_ptr); + +typedef struct CacheProcessContext { + struct Main *bmain; + struct Scene *scene; + struct CacheLibrary *cachelib; + struct Group *group; +} CacheProcessContext; + +typedef struct CacheProcessData { + unsigned int lay; + float mat[4][4]; + struct DupliCache *dupcache; +} CacheProcessData; + +typedef enum eCacheProcessFlag { + eCacheProcessFlag_DoStrands = (1 << 0), + eCacheProcessFlag_DoStrandsChildren = (1 << 1), +} eCacheProcessFlag; + +typedef void (*CacheModifier_InitFunc)(struct CacheModifier *md); +typedef void (*CacheModifier_FreeFunc)(struct CacheModifier *md); +typedef void (*CacheModifier_CopyFunc)(struct CacheModifier *md, struct CacheModifier *target); +typedef void (*CacheModifier_ForeachIDLinkFunc)(struct CacheModifier *md, struct CacheLibrary *cachelib, + CacheModifier_IDWalkFunc walk, void *userData); +typedef void (*CacheModifier_ProcessFunc)(struct CacheModifier *md, struct CacheProcessContext *ctx, struct CacheProcessData *data, + int frame, int frame_prev, int process_flag); + +typedef struct CacheModifierTypeInfo { + /* The user visible name for this modifier */ + char name[32]; + + /* The DNA struct name for the modifier data type, + * used to write the DNA data out. + */ + char struct_name[32]; + + /* The size of the modifier data type, used by allocation. */ + int struct_size; + + /********************* Non-optional functions *********************/ + + /* Copy instance data for this modifier type. Should copy all user + * level settings to the target modifier. + */ + CacheModifier_CopyFunc copy; + + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the modifier data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. + */ + CacheModifier_ForeachIDLinkFunc foreachIDLink; + + /* Process data and write results to the modifier's output archive */ + CacheModifier_ProcessFunc process; + + /********************* Optional functions *********************/ + + /* Initialize new instance data for this modifier type, this function + * should set modifier variables to their default values. + * + * This function is optional. + */ + CacheModifier_InitFunc init; + + /* Free internal modifier data variables, this function should + * not free the md variable itself. + * + * This function is optional. + */ + CacheModifier_FreeFunc free; +} CacheModifierTypeInfo; + +void BKE_cache_modifier_init(void); + +const char *BKE_cache_modifier_type_name(eCacheModifier_Type type); +const char *BKE_cache_modifier_type_struct_name(eCacheModifier_Type type); +int BKE_cache_modifier_type_struct_size(eCacheModifier_Type type); + +bool BKE_cache_modifier_unique_name(struct ListBase *modifiers, struct CacheModifier *md); +struct CacheModifier *BKE_cache_modifier_add(struct CacheLibrary *cachelib, const char *name, eCacheModifier_Type type); +void BKE_cache_modifier_remove(struct CacheLibrary *cachelib, struct CacheModifier *md); +void BKE_cache_modifier_clear(struct CacheLibrary *cachelib); +struct CacheModifier *BKE_cache_modifier_copy(struct CacheLibrary *cachelib, struct CacheModifier *md); + +void BKE_cache_modifier_foreachIDLink(struct CacheLibrary *cachelib, struct CacheModifier *md, CacheModifier_IDWalkFunc walk, void *userdata); + +bool BKE_cache_modifier_find_object(struct DupliCache *dupcache, struct Object *ob, struct DupliObjectData **r_data); +bool BKE_cache_modifier_find_strands(struct DupliCache *dupcache, struct Object *ob, int hair_system, struct DupliObjectData **r_data, struct Strands **r_strands, struct StrandsChildren **r_children, const char **r_name); + +struct KeyBlock *BKE_cache_modifier_strands_key_insert_key(struct StrandsKeyCacheModifier *md, struct Strands *strands, const char *name, const bool from_mix); +bool BKE_cache_modifier_strands_key_get(struct Object *ob, struct StrandsKeyCacheModifier **r_skmd, struct DerivedMesh **r_dm, struct Strands **r_strands, + struct DupliObjectData **r_dobdata, const char **r_name, float r_mat[4][4]); +bool BKE_cache_library_uses_key(struct CacheLibrary *cachelib, struct Key *key); + +/* ========================================================================= */ + +typedef struct CacheEffectorInstance { + struct CacheEffectorInstance *next, *prev; + + float mat[4][4]; + float imat[4][4]; + // TODO add linear/angular velocity if necessary +} CacheEffectorInstance; + +typedef struct CacheEffector { + int type; + + ListBase instances; + + struct DerivedMesh *dm; + struct BVHTreeFromMesh *treedata; + struct ForceFieldVertexCache *vertex_cache; + + float strength, falloff; + float mindist, maxdist; + bool double_sided; +} CacheEffector; + +typedef enum eCacheEffector_Type { + eCacheEffector_Type_Deflect = 0, + eCacheEffector_Type_Drag = 1, +} eCacheEffector_Type; + +typedef struct CacheEffectorPoint { + int index; + float x[3], v[3]; +} CacheEffectorPoint; + +typedef struct CacheEffectorResult { + float f[3]; +} CacheEffectorResult; + +int BKE_cache_effectors_get(struct CacheEffector *effectors, int max, struct CacheLibrary *cachelib, struct DupliCache *dupcache, float obmat[4][4]); +void BKE_cache_effectors_free(struct CacheEffector *effectors, int tot); +void BKE_cache_effector_velocity_update(struct CacheLibrary *cachelib, struct DupliCache *dupcache, float obmat[4][4], float frame); +int BKE_cache_effectors_eval(struct CacheEffector *effectors, int tot, struct CacheEffectorPoint *point, struct CacheEffectorResult *result); +int BKE_cache_effectors_eval_ex(struct CacheEffector *effectors, int tot, struct CacheEffectorPoint *point, struct CacheEffectorResult *result, + bool (*filter)(void *, struct CacheEffector *), void *filter_data); + +/* ========================================================================= */ + +struct CacheArchiveInfo *BKE_cache_archive_info_new(void); +void BKE_cache_archive_info_free(struct CacheArchiveInfo *info); +void BKE_cache_archive_info_clear(struct CacheArchiveInfo *info); + +struct CacheArchiveInfoNode *BKE_cache_archive_info_find_node(struct CacheArchiveInfo *info, struct CacheArchiveInfoNode *parent, + eCacheArchiveInfoNode_Type type, const char *name); +struct CacheArchiveInfoNode *BKE_cache_archive_info_add_node(struct CacheArchiveInfo *info, struct CacheArchiveInfoNode *parent, + eCacheArchiveInfoNode_Type type, const char *name); + +#endif diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index 77296920ee2..aacb7a4066b 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -104,26 +104,45 @@ typedef struct CameraParams { float winmat[4][4]; } CameraParams; +/* values for CameraParams.zoom, need to be taken into account for some operations */ +#define CAMERA_PARAM_ZOOM_INIT_CAMOB 1.0f +#define CAMERA_PARAM_ZOOM_INIT_PERSP 2.0f + void BKE_camera_params_init(CameraParams *params); -void BKE_camera_params_from_object(CameraParams *params, struct Object *camera); -void BKE_camera_params_from_view3d(CameraParams *params, struct View3D *v3d, struct RegionView3D *rv3d); +void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera); +void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d); void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy); void BKE_camera_params_compute_matrix(CameraParams *params); /* Camera View Frame */ -void BKE_camera_view_frame_ex(struct Scene *scene, struct Camera *camera, float drawsize, const bool do_clip, const float scale[3], - float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]); +void BKE_camera_view_frame_ex( + const struct Scene *scene, const struct Camera *camera, + const float drawsize, const bool do_clip, const float scale[3], + float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]); +void BKE_camera_view_frame( + const struct Scene *scene, const struct Camera *camera, + float r_vec[4][3]); + +bool BKE_camera_view_frame_fit_to_scene( + struct Scene *scene, struct View3D *v3d, struct Object *camera_ob, + float r_co[3], float *r_scale); +bool BKE_camera_view_frame_fit_to_coords( + const struct Scene *scene, + const float (*cos)[3], int num_cos, + const struct Object *camera_ob, + float r_co[3], float *r_scale); -void BKE_camera_view_frame(struct Scene *scene, struct Camera *camera, float r_vec[4][3]); +void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings); -bool BKE_camera_view_frame_fit_to_scene(struct Scene *scene, struct View3D *v3d, struct Object *camera_ob, - float r_co[3], float *r_scale); -bool BKE_camera_view_frame_fit_to_coords(struct Scene *scene, float (*cos)[3], int num_cos, - struct Object *camera_ob, float r_co[3], float *r_scale); +/* Camera multi-view API */ -void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings); +struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname); +void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]); +void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]); +float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname); +void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index a7fad85ed42..81621f9d3e7 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -36,15 +36,11 @@ #include "BLI_math_inline.h" struct Object; -struct ListBase; struct Scene; struct MFace; struct DerivedMesh; struct ClothModifierData; struct CollisionModifierData; -struct CollisionTree; -struct VoxelData; -struct PartDeflect; #define DO_INLINE MALWAYS_INLINE diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index b81b8f04817..bdc20324bee 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -43,16 +43,12 @@ #include "BLI_kdopbvh.h" -struct Cloth; -struct ClothModifierData; struct CollisionModifierData; -struct DerivedMesh; struct Group; struct MFace; struct MVert; struct Object; struct Scene; -struct LinkNode; //////////////////////////////////////// // used for collisions in collision.c diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index 9234625a37c..74a327c3808 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -103,5 +103,6 @@ void BKE_color_managed_view_settings_free(struct ColorManagedViewSettings *setti void BKE_color_managed_colorspace_settings_init(struct ColorManagedColorspaceSettings *colorspace_settings); void BKE_color_managed_colorspace_settings_copy(struct ColorManagedColorspaceSettings *colorspace_settings, const struct ColorManagedColorspaceSettings *settings); - +bool BKE_color_managed_colorspace_settings_equals(const struct ColorManagedColorspaceSettings *settings1, + const struct ColorManagedColorspaceSettings *settings2); #endif diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 1346feec82c..f3cfb901154 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -108,8 +108,8 @@ typedef struct bConstraintTypeInfo { } bConstraintTypeInfo; /* Function Prototypes for bConstraintTypeInfo's */ -bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con); -bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type); +const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con); +const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type); /* ---------------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 04990ad7144..74dafcac671 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -53,7 +53,6 @@ struct StructRNA; struct ToolSettings; struct Image; struct Text; -struct ImBuf; struct EditBone; struct bPoseChannel; struct bGPdata; @@ -108,6 +107,7 @@ enum { CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PARTICLE, + CTX_MODE_HAIR, CTX_MODE_OBJECT }; diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 60cbf8b302e..9bae2ad948d 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -33,7 +33,6 @@ * \author nzc */ -struct BevList; struct BezTriple; struct Curve; struct EditNurb; @@ -91,6 +90,7 @@ void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys); void BKE_curve_material_index_remove(struct Curve *cu, int index); void BKE_curve_material_index_clear(struct Curve *cu); int BKE_curve_material_index_validate(struct Curve *cu); +void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len); ListBase *BKE_curve_nurbs_get(struct Curve *cu); @@ -120,6 +120,7 @@ void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBa const bool for_render, const bool use_render_resolution); void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); +void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect); @@ -183,4 +184,14 @@ void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag); void BKE_nurb_bezt_handle_test(struct BezTriple *bezt, const bool use_handle); void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles); +/* **** Depsgraph evaluation **** */ + +struct EvaluationContext; + +void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx, + struct Curve *curve); + +void BKE_curve_eval_path(struct EvaluationContext *eval_ctx, + struct Curve *curve); + #endif /* __BKE_CURVE_H__ */ diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 6a0cfefb1c2..8cd6311e84c 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -46,7 +46,6 @@ extern "C" { struct BMesh; struct ID; struct CustomData; -struct CustomDataLayer; typedef uint64_t CustomDataMask; /*a data type large enough to hold 1 element from any customdata layer type*/ @@ -58,6 +57,8 @@ extern const CustomDataMask CD_MASK_EDITMESH; extern const CustomDataMask CD_MASK_DERIVEDMESH; extern const CustomDataMask CD_MASK_BMESH; extern const CustomDataMask CD_MASK_FACECORNERS; +extern const CustomDataMask CD_MASK_STRANDS; +extern const CustomDataMask CD_MASK_STRANDS_BMESH; extern const CustomDataMask CD_MASK_EVERYTHING; /* for ORIGINDEX layer type, indicates no original index for this element */ @@ -260,6 +261,7 @@ void *CustomData_get(const struct CustomData *data, int index, int type); void *CustomData_get_n(const struct CustomData *data, int type, int index, int n); void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type); void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n); +void *CustomData_bmesh_get_named(const struct CustomData *data, void *block, int type, const char *name); /* gets the layer at physical index n, with no type checking. */ diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index 08312035e40..a45893b00fa 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -39,7 +39,6 @@ struct Object; struct ListBase; struct bDeformGroup; struct MDeformVert; -struct MVert; struct MEdge; struct MLoop; struct MPoly; diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index 27cf19d7d06..d1214d39469 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -44,11 +44,11 @@ extern "C" { #endif +struct Group; struct ID; struct Main; struct Object; struct Scene; -struct ListBase; /* Dependency graph evaluation context * @@ -57,6 +57,7 @@ struct ListBase; */ typedef struct EvaluationContext { int mode; /* evaluation mode */ + float ctime; /* evaluation time */ } EvaluationContext; typedef enum eEvaluationMode { @@ -92,6 +93,7 @@ void DAG_exit(void); */ void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce); +void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce); void DAG_relations_tag_update(struct Main *bmain); void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene); void DAG_scene_free(struct Scene *sce); @@ -112,6 +114,7 @@ void DAG_scene_free(struct Scene *sce); * example a datablock was removed. */ void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const bool do_time, const bool do_invisible_flush); +void DAG_scene_update_group_flags(struct Main *bmain, struct Scene *scene, struct Group *group, unsigned int lay, const bool do_time, const bool do_invisible_flush); void DAG_on_visible_update(struct Main *bmain, const bool do_time); void DAG_id_tag_update(struct ID *id, short flag); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 0afc457f2b5..3b096773d96 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -53,14 +53,9 @@ /* prototypes */ -struct Base; struct Scene; struct Object; -struct Curve; struct ListBase; -struct Material; -struct Bone; -struct Mesh; struct DerivedMesh; struct EvaluationContext; diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h index a8e152fd301..e7384fb1a9c 100644 --- a/source/blender/blenkernel/BKE_dynamicpaint.h +++ b/source/blender/blenkernel/BKE_dynamicpaint.h @@ -27,8 +27,6 @@ * \ingroup bke */ -struct bContext; -struct wmOperator; struct Scene; /* Actual surface point */ @@ -70,8 +68,8 @@ void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct Dyn bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene); struct DynamicPaintSurface *dynamicPaint_createNewSurface(struct DynamicPaintCanvasSettings *canvas, struct Scene *scene); -void dynamicPaint_clearSurface(struct Scene *scene, struct DynamicPaintSurface *surface); -bool dynamicPaint_resetSurface(struct Scene *scene, struct DynamicPaintSurface *surface); +void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface); +bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface); void dynamicPaint_freeSurface(struct DynamicPaintSurface *surface); void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd); void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd); diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 38c8cf12969..d350eea7ac7 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -32,7 +32,6 @@ struct BMesh; struct BMLoop; -struct BMFace; struct Mesh; struct Scene; struct DerivedMesh; @@ -93,11 +92,12 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em); void BKE_editmesh_color_free(BMEditMesh *em); void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype); +float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]; /* editderivedmesh.c */ /* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */ void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm, - struct MeshStatVis *statvis); + const struct MeshStatVis *statvis); float (*BKE_editmesh_vertexCos_get(struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3]; diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index 3ee7dcd94b8..3736efff146 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -39,7 +39,6 @@ struct BMVert; struct BMLoop; struct BMBVHTree; struct BVHTree; -struct Scene; typedef struct BMBVHTree BMBVHTree; diff --git a/source/blender/blenkernel/BKE_editstrands.h b/source/blender/blenkernel/BKE_editstrands.h new file mode 100644 index 00000000000..ddca51e4736 --- /dev/null +++ b/source/blender/blenkernel/BKE_editstrands.h @@ -0,0 +1,104 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_EDITSTRANDS_H__ +#define __BKE_EDITSTRANDS_H__ + +/** \file blender/blenkernel/BKE_editstrands.h + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +#include "DNA_customdata_types.h" + +#include "BKE_customdata.h" +#include "bmesh.h" + +struct BMesh; +struct DerivedMesh; +struct Key; +struct Object; +struct Strands; + +typedef struct BMEditStrands { + struct BMesh *bm; + + /*this is for undoing failed operations*/ + struct BMEditStrands *emcopy; + int emcopyusers; + + /* Object this editmesh came from (if it came from one) */ + struct Object *ob; + struct DerivedMesh *root_dm; + + int flag; + + unsigned int vertex_glbuf; + unsigned int elem_glbuf; + unsigned int dot_glbuf; + + /*temp variables for x-mirror editing*/ + int mirror_cdlayer; /* -1 is invalid */ +} BMEditStrands; + +/* BMEditStrands->flag */ +typedef enum BMEditStrandsFlag { + BM_STRANDS_DIRTY_SEGLEN = 1, +} BMEditStrandsFlag; + +struct BMEditStrands *BKE_editstrands_create(struct BMesh *bm, struct DerivedMesh *root_dm, float mat[4][4]); +struct BMEditStrands *BKE_editstrands_copy(struct BMEditStrands *es); +struct BMEditStrands *BKE_editstrands_from_object(struct Object *ob); +void BKE_editstrands_update_linked_customdata(struct BMEditStrands *es); +void BKE_editstrands_free(struct BMEditStrands *es); + +/* === constraints === */ + +/* Stores vertex locations for temporary reference: + * Vertex locations get modified by tools, but then need to be corrected + * by calculating a smooth solution based on the difference to original pre-tool locations. + */ +typedef float (*BMEditStrandsLocations)[3]; +BMEditStrandsLocations BKE_editstrands_get_locations(struct BMEditStrands *edit); +void BKE_editstrands_free_locations(BMEditStrandsLocations locs); + +void BKE_editstrands_solve_constraints(struct Object *ob, struct BMEditStrands *es, BMEditStrandsLocations orig); +void BKE_editstrands_ensure(struct BMEditStrands *es); + + +/* === cache shape key conversion === */ + +struct BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, float mat[4][4], int act_key_nr, struct DerivedMesh *dm); +struct Strands *BKE_cache_strands_from_bmesh(struct BMEditStrands *edit, struct Key *key, float mat[4][4], struct DerivedMesh *dm); + +/* === particle conversion === */ + +struct BMesh *BKE_particles_to_bmesh(struct Object *ob, struct ParticleSystem *psys); +void BKE_particles_from_bmesh(struct Object *ob, struct ParticleSystem *psys); + +#endif diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index c4c27e1060d..69c3d632c49 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -39,11 +39,8 @@ struct Object; struct Scene; -struct Effect; struct ListBase; -struct Particle; struct Group; -struct RNG; struct ParticleSimulationData; struct ParticleData; struct ParticleKey; @@ -113,7 +110,8 @@ typedef struct EffectorCache { } EffectorCache; void free_partdeflect(struct PartDeflect *pd); -struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool precalc); +struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights); +struct ListBase *pdInitEffectors_ex(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, int layers, struct EffectorWeights *weights, bool precalc); void pdEndEffectors(struct ListBase **effectors); void pdPrecalculateEffectors(struct ListBase *effectors); void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse); @@ -196,7 +194,10 @@ void BKE_sim_debug_data_free(void); void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash); +void BKE_sim_debug_data_add_element_ex(struct SimDebugData *debug_data, int type, const float v1[3], const float v2[3], + float r, float g, float b, unsigned int category_hash, unsigned int hash); void BKE_sim_debug_data_remove_element(unsigned int hash); +void BKE_sim_debug_data_remove_element_ex(struct SimDebugData *debug_data, unsigned int hash); #define BKE_sim_debug_data_add_dot(p, r, g, b, category, ...) { \ const float v2[3] = { 0.0f, 0.0f, 0.0f }; \ diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 83783946d4f..443a03a475a 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -172,8 +172,8 @@ typedef enum eFMI_Requirement_Flags { } eFMI_Requirement_Flags; /* Function Prototypes for FModifierTypeInfo's */ -FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm); -FModifierTypeInfo *get_fmodifier_typeinfo(int type); +const FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm); +const FModifierTypeInfo *get_fmodifier_typeinfo(int type); /* ---------------------- */ @@ -223,12 +223,12 @@ struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, c */ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName); -/* find an f-curve based on an rna property. */ +/* Find an f-curve based on an rna property. */ struct FCurve *rna_get_fcurve(struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex, - struct AnimData **adt, struct bAction **action, bool *r_driven); + struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special); /* Same as above, but takes a context data, temp hack needed for complex paths like texture ones. */ struct FCurve *rna_get_fcurve_context_ui(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, - int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven); + int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special); /* Binary search algorithm for finding where to 'insert' BezTriple with given frame number. * Returns the index to insert at (data already at that index will be offset if replace is 0) diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h index 433c10b82f1..6501c968abc 100644 --- a/source/blender/blenkernel/BKE_fluidsim.h +++ b/source/blender/blenkernel/BKE_fluidsim.h @@ -34,9 +34,7 @@ struct Object; struct Scene; -struct FluidsimModifierData; struct FluidsimSettings; -struct DerivedMesh; struct MVert; /* old interface */ diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index e12ce3df476..137670215cc 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -40,8 +40,6 @@ extern "C" { struct VFont; struct Object; struct Curve; -struct objfnt; -struct TmpFont; struct CharInfo; struct Main; diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index bb909e4aa9d..e10594634f0 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -41,6 +41,7 @@ extern "C" { struct FreestyleConfig; struct FreestyleLineSet; struct FreestyleModuleConfig; +struct Main; /* RNA aliases */ typedef struct FreestyleSettings FreestyleSettings; @@ -58,7 +59,7 @@ bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf); /* FreestyleConfig.linesets */ -FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name); +FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name); bool BKE_freestyle_lineset_delete(FreestyleConfig *config, FreestyleLineSet *lineset); FreestyleLineSet *BKE_freestyle_lineset_get_active(FreestyleConfig *config); short BKE_freestyle_lineset_get_active_index(FreestyleConfig *config); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 57003ffc3aa..7585dc23342 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -45,7 +45,6 @@ extern "C" { /* forwards */ struct Main; -struct Object; typedef struct Global { @@ -127,10 +126,12 @@ enum { G_DEBUG_FREESTYLE = (1 << 7), /* freestyle messages */ G_DEBUG_DEPSGRAPH = (1 << 8), /* depsgraph messages */ G_DEBUG_SIMDATA = (1 << 9), /* sim debug data display */ + G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */ + G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* sinle threaded depsgraph */ }; #define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \ - G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH) + G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM) /* G.fileflags */ diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 820e1ea1494..d856e90a340 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -36,10 +36,8 @@ struct Base; struct EvaluationContext; struct Group; -struct GroupObject; struct Main; struct Object; -struct bAction; struct Scene; void BKE_group_free(struct Group *group); diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 9af0d96884a..763a3874d4e 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -48,10 +48,14 @@ typedef struct Icon Icon; struct PreviewImage; struct ID; +enum eIconSizes; + void BKE_icons_init(int first_dyn_id); /* return icon id for library object or create new icon if not found */ -int BKE_icon_getid(struct ID *id); +int BKE_icon_id_ensure(struct ID *id); + +int BKE_icon_preview_ensure(struct PreviewImage *preview); /* retrieve icon for id */ struct Icon *BKE_icon_get(int icon_id); @@ -60,8 +64,10 @@ struct Icon *BKE_icon_get(int icon_id); /* used for inserting the internal icons */ void BKE_icon_set(int icon_id, struct Icon *icon); -/* remove icon and free date if library object becomes invalid */ -void BKE_icon_delete(struct ID *id); +/* remove icon and free data if library object becomes invalid */ +void BKE_icon_id_delete(struct ID *id); + +void BKE_icon_delete(int icon_id); /* report changes - icon needs to be recalculated */ void BKE_icon_changed(int icon_id); @@ -75,8 +81,17 @@ void BKE_previewimg_freefunc(void *link); /* free the preview image */ void BKE_previewimg_free(struct PreviewImage **prv); +/* clear the preview image or icon, but does not free it */ +void BKE_previewimg_clear(struct PreviewImage *prv); + +/* clear the preview image or icon at a specific size */ +void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size); + +/* get the preview from any pointer */ +struct PreviewImage **BKE_previewimg_id_get_p(struct ID *id); + /* free the preview image belonging to the id */ -void BKE_previewimg_free_id(struct ID *id); +void BKE_previewimg_id_free(struct ID *id); /* create a new preview image */ struct PreviewImage *BKE_previewimg_create(void); @@ -85,6 +100,19 @@ struct PreviewImage *BKE_previewimg_create(void); struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv); /* retrieve existing or create new preview image */ -struct PreviewImage *BKE_previewimg_get(struct ID *id); +struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id); + +void BKE_previewimg_ensure(struct PreviewImage *prv, const int size); + +struct PreviewImage *BKE_previewimg_cached_get(const char *name); + +struct PreviewImage *BKE_previewimg_cached_ensure(const char *name); + +struct PreviewImage *BKE_previewimg_cached_thumbnail_read( + const char *name, const char *path, const int source, bool force_update); + +void BKE_previewimg_cached_release(const char *name); + +#define ICON_RENDER_DEFAULT_HEIGHT 32 #endif /* __BKE_ICONS_H__ */ diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 2c9ecef4c2d..facf3cf2103 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -39,41 +39,46 @@ extern "C" { struct Image; struct ImBuf; -struct Tex; struct anim; struct Scene; struct Object; struct ImageFormatData; struct ImagePool; struct Main; +struct ReportList; +struct RenderResult; +struct StampData; #define IMA_MAX_SPACE 64 void BKE_images_init(void); void BKE_images_exit(void); +void BKE_image_free_packedfiles(struct Image *image); +void BKE_image_free_views(struct Image *image); void BKE_image_free_buffers(struct Image *image); /* call from library */ void BKE_image_free(struct Image *image); -void BKE_imbuf_stamp_info(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf); -void BKE_image_stamp_buf( - struct Scene *scene, struct Object *camera, - unsigned char *rect, float *rectf, int width, int height, int channels); +typedef void (StampCallback)(void *data, const char *propname, const char *propvalue); + +void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr); +void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf); +void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback); +void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels); bool BKE_imbuf_alpha_test(struct ImBuf *ibuf); -int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); +int BKE_imbuf_write_stamp(struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); +void BKE_imbuf_write_prepare(struct ImBuf *ibuf, struct ImageFormatData *imf); int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy); - void BKE_image_path_from_imformat( char *string, const char *base, const char *relbase, int frame, - const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames); + const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix); void BKE_image_path_from_imtype( char *string, const char *base, const char *relbase, int frame, - const char imtype, const bool use_ext, const bool use_frames); - -bool BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format); -bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype); + const char imtype, const bool use_ext, const bool use_frames, const char *suffix); +int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format); +int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype); char BKE_image_ftype_to_imtype(const int ftype); int BKE_image_imtype_to_ftype(const char imtype); @@ -104,6 +109,7 @@ void BKE_image_tag_time(struct Image *ima); /* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */ /* should be used in conjunction with an ID * to Image. */ struct ImageUser; +struct RenderData; struct RenderPass; struct RenderResult; @@ -153,7 +159,7 @@ bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser); /* same as above, but can be used to retrieve images being rendered in * a thread safe way, always call both acquire and release */ -struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **lock_r); +struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock); void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock); struct ImagePool *BKE_image_pool_new(void); @@ -173,11 +179,12 @@ struct Image *BKE_image_load_exists(const char *filepath); /* adds image, adds ibuf, generates color or pattern */ struct Image *BKE_image_add_generated( - struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4]); + struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d); /* adds image from imbuf, owns imbuf */ -struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf); +struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf, const char *name); /* for reload, refresh, pack */ +void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser); void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal); void BKE_image_walk_all_users(const struct Main *mainp, void *customdata, @@ -185,6 +192,8 @@ void BKE_image_walk_all_users(const struct Main *mainp, void *customdata, /* ensures an Image exists for viewing nodes or render */ struct Image *BKE_image_verify_viewer(int type, const char *name); +/* ensures the view node cache is compatible with the scene views */ +void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser); /* called on frame change or before render */ void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr); @@ -196,13 +205,23 @@ void BKE_image_update_frame(const struct Main *bmain, int cfra); /* sets index offset for multilayer files */ struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser); +/* sets index offset for multiview files */ +void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser); + /* for multilayer images as well as for render-viewer */ +bool BKE_image_is_multilayer(struct Image *ima); struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima); void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima); +/* for multilayer images as well as for singlelayer */ +bool BKE_image_is_openexr(struct Image *ima); + /* for multiple slot render, call this before render */ void BKE_image_backup_render(struct Scene *scene, struct Image *ima); - + +/* for singlelayer openexr saving */ +bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags); + /* goes over all textures that use images */ void BKE_image_free_all_textures(void); @@ -213,6 +232,8 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame); void BKE_image_all_free_anim_ibufs(int except_frame); void BKE_image_memorypack(struct Image *ima); +void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath); +void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima, char *data, const size_t data_len); /* prints memory statistics for images */ void BKE_image_print_memlist(void); @@ -244,7 +265,8 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame); /* Guess offset for the first frame in the sequence */ int BKE_image_sequence_guess_offset(struct Image *image); - +bool BKE_image_has_anim(struct Image *image); +bool BKE_image_has_packedfile(struct Image *image); bool BKE_image_is_animated(struct Image *image); bool BKE_image_is_dirty(struct Image *image); void BKE_image_file_format_set(struct Image *image, int ftype); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 61aac255762..1e9e392406b 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -38,10 +38,10 @@ struct ID; struct ListBase; struct Curve; struct Object; -struct Scene; struct Lattice; struct Mesh; struct ParticleSystem; +struct Strands; struct WeightsArrayCache; /* Kernel prototypes */ @@ -52,6 +52,7 @@ extern "C" { void BKE_key_free(struct Key *sc); void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct ID *id); +struct Key *BKE_key_add_ex(struct ID *from, int fromtype, int fromindex); struct Key *BKE_key_add_particles(struct Object *ob, struct ParticleSystem *psys); struct Key *BKE_key_copy(struct Key *key); struct Key *BKE_key_copy_nolib(struct Key *key); @@ -70,12 +71,19 @@ float *BKE_key_evaluate_object_ex( float *arr, size_t arr_size); float *BKE_key_evaluate_object( struct Object *ob, int *r_totelem); +float *BKE_key_evaluate_strands_ex( + struct Strands *strands, struct Key *key, struct KeyBlock *actkb, bool lock_shape, + int *r_totelem, float *arr, size_t arr_size); +float *BKE_key_evaluate_strands( + struct Strands *strand, struct Key *key, struct KeyBlock *actkbs, bool lock_shape, + int *r_totelem, bool use_motion); float *BKE_key_evaluate_particles_ex( struct Object *ob, struct ParticleSystem *psys, float cfra, int *r_totelem, float *arr, size_t arr_size); float *BKE_key_evaluate_particles( struct Object *ob, struct ParticleSystem *psys, float cfra, int *r_totelem); +struct Key **BKE_key_from_object_p(struct Object *ob); struct Key *BKE_key_from_object(struct Object *ob); struct KeyBlock *BKE_keyblock_from_object(struct Object *ob); struct KeyBlock *BKE_keyblock_from_object_reference(struct Object *ob); @@ -96,10 +104,13 @@ typedef struct WeightsArrayCache { } WeightsArrayCache; float **BKE_keyblock_get_per_block_object_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache); +float **BKE_keyblock_strands_get_per_block_weights(struct Strands *strands, struct Key *key, struct WeightsArrayCache *cache); float **BKE_keyblock_get_per_block_particle_weights(struct Object *ob, struct ParticleSystem *psys, float cfra, struct Key *key, struct WeightsArrayCache *cache); void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache); void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, float **per_keyblock_weights, const int mode); +void BKE_key_evaluate_strands_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, + float **per_keyblock_weights, const int mode); /* conversion functions */ /* Note: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */ @@ -115,6 +126,10 @@ void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb); void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb); void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me); +void BKE_keyblock_update_from_strands(struct Strands *strands, struct KeyBlock *kb, bool use_motion); +void BKE_keyblock_convert_from_strands(struct Strands *strands, struct Key *key, struct KeyBlock *kb, bool use_motion); +void BKE_keyblock_convert_to_strands(struct KeyBlock *kb, struct Strands *strands, bool use_motion); + void BKE_keyblock_update_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]); void BKE_keyblock_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]); float (*BKE_keyblock_convert_to_vertcos(struct Object *ob, struct KeyBlock *kb))[3]; @@ -126,6 +141,7 @@ void BKE_keyblock_convert_from_hair_keys(struct Object *ob, struct ParticleSy /* other management */ bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index); +bool BKE_keyblock_move_ex(struct Key *key, int *shapenr, int org_index, int new_index); bool BKE_keyblock_is_basis(struct Key *key, const int index); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 5fb1053b53f..4ffdb632513 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -93,4 +93,11 @@ int BKE_lattice_index_flip(struct Lattice *lt, const int index, void BKE_lattice_bitmap_from_flag(struct Lattice *lt, unsigned int *bitmap, const short flag, const bool clear, const bool respecthide); +/* **** Depsgraph evaluation **** */ + +struct EvaluationContext; + +void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx, + struct Lattice *latt); + #endif /* __BKE_LATTICE_H__ */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index e88a4e88209..63192cad11d 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id); struct ListBase *which_libbase(struct Main *mainlib, short type); -#define MAX_LIBARRAY 35 +#define MAX_LIBARRAY 36 int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]); void BKE_libblock_free(struct Main *bmain, void *idv); @@ -107,8 +107,9 @@ void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagg struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *)); -void set_free_notifier_reference_cb(void (*func)(const void *)); +void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *)); +void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *)); +void BKE_library_callback_free_editor_id_reference_set(void (*func)(const struct ID *)); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index ae10ba4caab..e77b4f5e8fe 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -49,9 +49,9 @@ struct Object; struct ColorBand; struct bContext; -FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main); +FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name); void BKE_linestyle_free(FreestyleLineStyle *linestyle); -FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle); +FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index ec654ea4b71..a0c67e055ae 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -94,6 +94,7 @@ typedef struct Main { ListBase movieclip; ListBase mask; ListBase linestyle; + ListBase cache_library; char id_tag_update[256]; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 2f20505bea3..0cfa1aeecb5 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -40,8 +40,6 @@ struct Main; struct Material; struct ID; struct Object; -struct Mesh; -struct MTFace; struct Scene; /* materials */ @@ -52,6 +50,7 @@ void BKE_material_free_ex(struct Material *ma, bool do_id_user); void test_object_materials(struct Main *bmain, struct ID *id); void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user); void init_material(struct Material *ma); +void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); struct Material *BKE_material_add(struct Main *bmain, const char *name); struct Material *BKE_material_copy(struct Material *ma); struct Material *localize_material(struct Material *ma); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index c021960e730..62cd50099fd 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -32,7 +32,6 @@ * \since March 2001 * \author nzc */ -struct EvaluationContext; struct Main; struct MetaBall; struct Object; @@ -46,9 +45,6 @@ struct MetaBall *BKE_mball_copy(struct MetaBall *mb); void BKE_mball_make_local(struct MetaBall *mb); -void BKE_mball_cubeTable_free(void); - -void BKE_mball_polygonize(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob); @@ -72,4 +68,11 @@ void BKE_mball_select_all(struct MetaBall *mb); void BKE_mball_deselect_all(struct MetaBall *mb); void BKE_mball_select_swap(struct MetaBall *mb); +/* **** Depsgraph evaluation **** */ + +struct EvaluationContext; + +void BKE_mball_eval_geometry(struct EvaluationContext *eval_ctx, + struct MetaBall *mball); + #endif diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h new file mode 100644 index 00000000000..361f31b704c --- /dev/null +++ b/source/blender/blenkernel/BKE_mball_tessellate.h @@ -0,0 +1,36 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MBALL_TESSELLATE_H__ +#define __BKE_MBALL_TESSELLATE_H__ + +/** \file BKE_mball_tessellate.h + * \ingroup bke + */ +struct EvaluationContext; +struct Object; +struct Scene; + +void BKE_mball_polygonize( + struct EvaluationContext *eval_ctx, struct Scene *scene, + struct Object *ob, struct ListBase *dispbase); + +void BKE_mball_cubeTable_free(void); + +#endif /* __BKE_MBALL_TESSELLATE_H__ */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 224be0f3685..7cb121bcf5e 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -33,14 +33,13 @@ struct ID; struct BoundBox; -struct DispList; struct EdgeHash; struct ListBase; struct LinkNode; struct BLI_Stack; struct MemArena; -struct BMEditMesh; struct BMesh; +struct DupliObjectData; struct Main; struct Mesh; struct MPoly; @@ -49,18 +48,11 @@ struct MFace; struct MEdge; struct MVert; struct MDeformVert; -struct MCol; struct Object; -struct MTFace; -struct VecNor; struct CustomData; struct DerivedMesh; struct Scene; struct MLoopUV; -struct UvVertMap; -struct UvMapVert; -struct UvElementMap; -struct UvElement; struct ReportList; #ifdef __cplusplus @@ -78,12 +70,13 @@ extern "C" { struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob); -int poly_find_loop_from_vert(const struct MPoly *poly, - const struct MLoop *loopstart, - unsigned vert); - -int poly_get_adj_loops_from_vert(unsigned r_adj[3], const struct MPoly *poly, - const struct MLoop *mloop, unsigned vert); +int poly_find_loop_from_vert( + const struct MPoly *poly, + const struct MLoop *loopstart, + unsigned vert); +int poly_get_adj_loops_from_vert( + unsigned r_adj[2], const struct MPoly *poly, + const struct MLoop *mloop, unsigned vert); int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); @@ -116,6 +109,7 @@ void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblis void BKE_mesh_to_curve(struct Scene *scene, struct Object *ob); void BKE_mesh_material_index_remove(struct Mesh *me, short index); void BKE_mesh_material_index_clear(struct Mesh *me); +void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len); void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth); const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh); @@ -128,10 +122,14 @@ bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, con const char *new_name, const bool do_tessface); bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface); -float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3]; +float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; + +void BKE_mesh_calc_normals_split(struct Mesh *mesh); +void BKE_mesh_split_faces(struct Mesh *mesh); struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob, int apply_modifiers, int settings, int calc_tessface, int calc_undeformed); +struct Mesh *BKE_mesh_new_from_dupli_data(struct Main *bmain, struct DupliObjectData *data, bool calc_tessface, bool calc_undeformed); /* vertex level transformations & checks (no derived mesh) */ @@ -280,7 +278,7 @@ int BKE_mesh_recalc_tessellation( struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MVert *mvert, int totface, int totloop, int totpoly, - const bool do_face_normals); + const bool do_face_nor_copy); int BKE_mesh_mpoly_to_mface( struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, int totface, int totloop, int totpoly); @@ -364,6 +362,13 @@ void BKE_mesh_strip_loose_edges(struct Mesh *me); void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old); void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select); +/* **** Depsgraph evaluation **** */ + +struct EvaluationContext; + +void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx, + struct Mesh *mesh); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index da44c989146..a2f47858f90 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -102,7 +102,8 @@ typedef struct MeshElemMap { /* mapping */ UvVertMap *BKE_mesh_uv_vert_map_create( struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, - unsigned int totpoly, unsigned int totvert, int selected, float *limit); + unsigned int totpoly, unsigned int totvert, + const float limit[2], const bool selected, const bool use_winding); UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v); void BKE_mesh_uv_vert_map_free(UvVertMap *vmap); diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h index 752270a8120..c6d8da16565 100644 --- a/source/blender/blenkernel/BKE_mesh_remap.h +++ b/source/blender/blenkernel/BKE_mesh_remap.h @@ -28,7 +28,6 @@ struct CustomData; struct DerivedMesh; struct MVert; -struct MeshElemMap; struct MemArena; /* Generic ways to map some geometry elements from a source mesh to a dest one. */ diff --git a/source/blender/blenkernel/BKE_mesh_sample.h b/source/blender/blenkernel/BKE_mesh_sample.h new file mode 100644 index 00000000000..6b489550847 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_sample.h @@ -0,0 +1,68 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_MESH_SAMPLE_H__ +#define __BKE_MESH_SAMPLE_H__ + +/** \file BKE_mesh_sample.h + * \ingroup bke + */ + +struct DerivedMesh; +struct Key; +struct KeyBlock; + +struct MSurfaceSample; + +/* ==== Evaluate ==== */ + +bool BKE_mesh_sample_eval(struct DerivedMesh *dm, const struct MSurfaceSample *sample, float loc[3], float nor[3], float tang[3]); +bool BKE_mesh_sample_shapekey(struct Key *key, struct KeyBlock *kb, const struct MSurfaceSample *sample, float loc[3]); + + +/* ==== Sampling ==== */ + +/* Storage descriptor to allow generic data storage by arbitrary algorithms */ +typedef struct MSurfaceSampleStorage { + bool (*store_sample)(void *data, int capacity, int index, const struct MSurfaceSample *sample); + void *data; + int capacity; + int free_data; +} MSurfaceSampleStorage; + +void BKE_mesh_sample_storage_single(struct MSurfaceSampleStorage *storage, struct MSurfaceSample *sample); +void BKE_mesh_sample_storage_array(struct MSurfaceSampleStorage *storage, struct MSurfaceSample *samples, int capacity); +void BKE_mesh_sample_storage_release(struct MSurfaceSampleStorage *storage); + +int BKE_mesh_sample_generate_random(struct MSurfaceSampleStorage *dst, struct DerivedMesh *dm, unsigned int seed, int totsample); + +typedef bool (*MeshSampleRayCallback)(void *userdata, float ray_start[3], float ray_end[3]); +int BKE_mesh_sample_generate_raycast(struct MSurfaceSampleStorage *dst, struct DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata, int totsample); + +/* ==== Utilities ==== */ + +struct ParticleSystem; +struct ParticleData; +struct BVHTreeFromMesh; + +bool BKE_mesh_sample_from_particle(struct MSurfaceSample *sample, struct ParticleSystem *psys, struct DerivedMesh *dm, struct ParticleData *pa); +bool BKE_mesh_sample_to_particle(struct MSurfaceSample *sample, struct ParticleSystem *psys, struct DerivedMesh *dm, struct BVHTreeFromMesh *bvhtree, struct ParticleData *pa); + +#endif /* __BKE_MESH_SAMPLE_H__ */ diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 12eb78e422b..cc53f9409fd 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -39,10 +39,11 @@ struct DagNode; struct Object; struct Scene; struct ListBase; -struct LinkNode; struct bArmature; +struct Main; struct ModifierData; struct BMEditMesh; +struct DepsNodeHandle; typedef enum { /* Should not be used, only for None modifier type */ @@ -256,9 +257,21 @@ typedef struct ModifierTypeInfo { * * This function is optional. */ - void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, struct Scene *scene, + void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, + struct Main *bmain, struct Scene *scene, struct Object *ob, struct DagNode *obNode); + /* Add the appropriate relations to the dependency graph. + * + * This function is optional. + */ + /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */ + void (*updateDepsgraph)(struct ModifierData *md, + struct Main *bmain, + struct Scene *scene, + struct Object *ob, + struct DepsNodeHandle *node); + /* Should return true if the modifier needs to be recalculated on time * changes. * @@ -311,7 +324,7 @@ typedef struct ModifierTypeInfo { /* Initialize modifier's global data (type info and some common global storages). */ void BKE_modifier_init(void); -ModifierTypeInfo *modifierType_getInfo(ModifierType type); +const ModifierTypeInfo *modifierType_getInfo(ModifierType type); /* Modifier utility calls, do call through type pointer and return * default values if pointer is optional. diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index a4aa58e22f1..7d7675270de 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -37,7 +37,6 @@ struct Main; struct MovieClip; struct MovieClipScopes; struct MovieClipUser; -struct MovieTrackingTrack; struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); @@ -61,7 +60,7 @@ void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr); void BKE_movieclip_update_scopes(struct MovieClip *clip, struct MovieClipUser *user, struct MovieClipScopes *scopes); -void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUser *user, int *totseg_r, int **points_r); +void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUser *user, int *r_totseg, int **r_points); void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, struct MovieDistortion *distortion, int cfra, int *build_sizes, int build_count, bool undistorted); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 11d81a149b1..a8242a529f3 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -34,9 +34,7 @@ enum MultiresModifiedFlags; struct DerivedMesh; -struct GridHidden; struct MDisps; -struct MFace; struct Mesh; struct ModifierData; struct Multires; @@ -81,8 +79,9 @@ struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifier struct Object *ob); void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction); void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob); -void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, - int updateblock, int simple); +void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple); +void multiresModifier_sync_levels_ex( + struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst); int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd, struct Object *dst, struct Object *src); int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd, diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index c3fc29e811f..3bf8bba47f5 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -76,6 +76,8 @@ void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip); struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks); void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt); +struct NlaTrack *BKE_nlatrack_find_tweaked(struct AnimData *adt); + void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt); bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 44ac3b7bb38..0a6c21c2c60 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -62,24 +62,20 @@ struct bNodeTreeExec; struct bNodeExecContext; struct bNodeExecData; struct GPUMaterial; -struct GPUNode; struct GPUNodeStack; struct ID; struct ImBuf; struct ImageFormatData; struct ListBase; struct Main; -struct uiBlock; struct uiLayout; struct MTex; struct PointerRNA; -struct rctf; struct RenderData; struct Scene; struct Tex; struct SpaceNode; struct ARegion; -struct Object; struct ColorManagedViewSettings; struct ColorManagedDisplaySettings; struct bNodeInstanceHash; @@ -323,7 +319,7 @@ typedef struct bNodeTreeType { struct bNodeTreeType *ntreeTypeFind(const char *idname); void ntreeTypeAdd(struct bNodeTreeType *nt); -void ntreeTypeFreeLink(struct bNodeTreeType *nt); +void ntreeTypeFreeLink(const struct bNodeTreeType *nt); bool ntreeIsRegistered(struct bNodeTree *ntree); struct GHashIterator *ntreeTypeGetIterator(void); @@ -511,8 +507,7 @@ const struct ListBase *BKE_node_clipboard_get_links(void); int BKE_node_clipboard_get_type(void); /* Node Instance Hash */ -typedef struct bNodeInstanceHash -{ +typedef struct bNodeInstanceHash { GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */ } bNodeInstanceHash; @@ -787,6 +782,7 @@ struct ShadeResult; #define SH_NODE_COMBXYZ 189 #define SH_NODE_OUTPUT_LINESTYLE 190 #define SH_NODE_UVALONGSTROKE 191 +#define SH_NODE_TEX_POINTDENSITY 192 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 @@ -945,6 +941,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria #define CMP_NODE_MAP_RANGE 319 #define CMP_NODE_PLANETRACKDEFORM 320 #define CMP_NODE_CORNERPIN 321 +#define CMP_NODE_SWITCH_VIEW 322 /* channel toggles */ #define CMP_CHAN_RGB 1 @@ -978,9 +975,9 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria #define CMP_TRACKPOS_ABSOLUTE_FRAME 3 /* API */ -struct CompBuf; void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews, - const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings); + const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, + const char *view_name); void ntreeCompositTagRender(struct Scene *sce); int ntreeCompositTagAnimated(struct bNodeTree *ntree); void ntreeCompositTagGenerators(struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 614ed9962f1..d134701fc80 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -33,33 +33,31 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + struct Base; struct EvaluationContext; struct Scene; struct Object; -struct Camera; struct BoundBox; struct View3D; struct SoftBody; struct BulletSoftBody; -struct Group; -struct bAction; -struct RenderData; -struct rctf; struct MovieClip; struct Main; struct RigidBodyWorld; struct HookModifierData; +struct ModifierData; void BKE_object_workob_clear(struct Object *workob); void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob); void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src); -struct SoftBody *copy_softbody(struct SoftBody *sb, bool copy_caches); +struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches); struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb); struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys); -void BKE_object_copy_particlesystems(struct Object *obn, struct Object *ob); -void BKE_object_copy_softbody(struct Object *obn, struct Object *ob); +void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src); +void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_particlesystems(struct Object *ob); void BKE_object_free_softbody(struct Object *ob); void BKE_object_free_bulletsoftbody(struct Object *ob); @@ -69,13 +67,13 @@ void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob); void BKE_object_free(struct Object *ob); void BKE_object_free_ex(struct Object *ob, bool do_id_user); void BKE_object_free_derived_caches(struct Object *ob); -void BKE_object_free_caches(struct Object *object); +void BKE_object_free_caches(struct Object *object, bool free_smoke_sim); void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); bool BKE_object_support_modifier_type_check(struct Object *ob, int modifier_type); -void BKE_object_link_modifiers(struct Object *ob, struct Object *from); +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob); void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); @@ -87,9 +85,18 @@ bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); bool BKE_object_is_in_wpaint_select_vert(struct Object *ob); -struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name); -struct Object *BKE_object_add(struct Main *bmain, struct Scene *scene, int type); -void *BKE_object_obdata_add_from_type(struct Main *bmain, int type); +struct Object *BKE_object_add_only_object( + struct Main *bmain, + int type, const char *name) + ATTR_NONNULL(1) ATTR_RETURNS_NONNULL; +struct Object *BKE_object_add( + struct Main *bmain, struct Scene *scene, + int type, const char *name) + ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL; +void *BKE_object_obdata_add_from_type( + struct Main *bmain, + int type, const char *name) + ATTR_NONNULL(1); void BKE_object_lod_add(struct Object *ob); void BKE_object_lod_sort(struct Object *ob); @@ -118,6 +125,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]); bool BKE_object_pose_context_check(struct Object *ob); struct Object *BKE_object_pose_armature_get(struct Object *ob); +void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]); void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob); void BKE_object_where_is_calc_ex(struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]); void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime); @@ -172,6 +180,32 @@ void BKE_object_tfm_protected_restore(struct Object *ob, const ObjectTfmProtectedChannels *obtfm, const short protectflag); +/* Dependency graph evaluation callbacks. */ +void BKE_object_eval_local_transform(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); +void BKE_object_eval_parent(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); +void BKE_object_eval_constraints(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); +void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob); + +void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct ModifierData *md); +void BKE_object_eval_uber_transform(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); +void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); + +void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); void BKE_object_handle_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); void BKE_object_handle_update_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, @@ -183,7 +217,9 @@ int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float * int BKE_object_insert_ptcache(struct Object *ob); void BKE_object_delete_ptcache(struct Object *ob, int index); -struct KeyBlock *BKE_object_insert_shape_key(struct Object *ob, const char *name, const bool from_mix); +struct KeyBlock *BKE_object_shapekey_insert(struct Object *ob, const char *name, const bool from_mix); +bool BKE_object_shapekey_remove(struct Main *bmain, struct Object *ob, struct KeyBlock *kb); +bool BKE_object_shapekey_free(struct Main *bmain, struct Object *ob); bool BKE_object_flag_test_recursive(const struct Object *ob, short flag); @@ -222,6 +258,8 @@ void BKE_object_groups_clear(struct Scene *scene, struct Base *base, struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot); +bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h index b750d8b283a..9b1b937febf 100644 --- a/source/blender/blenkernel/BKE_ocean.h +++ b/source/blender/blenkernel/BKE_ocean.h @@ -74,13 +74,14 @@ typedef struct OceanCache { #define OCEAN_CACHING 1 #define OCEAN_CACHED 2 -struct Ocean *BKE_add_ocean(void); -void BKE_free_ocean_data(struct Ocean *oc); -void BKE_free_ocean(struct Ocean *oc); +struct Ocean *BKE_ocean_add(void); +void BKE_ocean_free_data(struct Ocean *oc); +void BKE_ocean_free(struct Ocean *oc); -void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, - float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed); -void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount); +void BKE_ocean_init( + struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, + float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed); +void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount); /* sampling the ocean surface */ float BKE_ocean_jminus_to_foam(float jminus, float coverage); @@ -92,16 +93,17 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j) /* ocean cache handling */ -struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, - int start, int end, float wave_scale, - float chop_amount, float foam_coverage, float foam_fade, int resolution); -void BKE_simulate_ocean_cache(struct OceanCache *och, int frame); +struct OceanCache *BKE_ocean_init_cache( + const char *bakepath, const char *relbase, + int start, int end, float wave_scale, + float chop_amount, float foam_coverage, float foam_fade, int resolution); +void BKE_ocean_simulate_cache(struct OceanCache *och, int frame); -void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data); +void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data); void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v); void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j); -void BKE_free_ocean_cache(struct OceanCache *och); +void BKE_ocean_free_cache(struct OceanCache *och); #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h index 54deef1ce2f..454edb40c4e 100644 --- a/source/blender/blenkernel/BKE_treehash.h +++ b/source/blender/blenkernel/BKE_outliner_treehash.h @@ -19,34 +19,33 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BKE_TREEHASH_H__ -#define __BKE_TREEHASH_H__ +#ifndef __BKE_OUTLINER_TREEHASH_H__ +#define __BKE_OUTLINER_TREEHASH_H__ -/** \file BKE_treehash.h +/** \file BKE_outliner_treehash.h * \ingroup bke */ struct ID; -struct GHash; struct BLI_mempool; struct TreeStoreElem; /* create and fill hashtable with treestore elements */ -void *BKE_treehash_create_from_treestore(struct BLI_mempool *treestore); +void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore); /* full rebuild for already allocated hashtable */ -void *BKE_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore); +void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore); /* full rebuild for already allocated hashtable */ -void BKE_treehash_add_element(void *treehash, struct TreeStoreElem *elem); +void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem); /* find first unused element with specific type, nr and id */ -struct TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id); +struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id); /* find user or unused element with specific type, nr and id */ -struct TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id); +struct TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id); /* free treehash structure */ -void BKE_treehash_free(void *treehash); +void BKE_outliner_treehash_free(void *treehash); #endif diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h index 8fab44121de..a2397922061 100644 --- a/source/blender/blenkernel/BKE_packedFile.h +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -48,7 +48,7 @@ struct PackedFile *dupPackedFile(const struct PackedFile *pf_src); struct PackedFile *newPackedFile(struct ReportList *reports, const char *filename, const char *relabase); struct PackedFile *newPackedFileMemory(void *mem, int memlen); -void packAll(struct Main *bmain, struct ReportList *reports); +void packAll(struct Main *bmain, struct ReportList *reports, bool verbose); void packLibraries(struct Main *bmain, struct ReportList *reports); /* unpack */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 3e4e6ab4146..09ccc3dced7 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -37,12 +37,10 @@ struct BMesh; struct BMFace; struct Brush; struct CurveMapping; -struct MDisps; struct MeshElemMap; struct GridPaintMask; struct Main; struct MFace; -struct MultireModifierData; struct MVert; struct Object; struct Paint; @@ -57,7 +55,6 @@ struct StrokeCache; struct Tex; struct ImagePool; struct UnifiedPaintSettings; -struct wmOperator; enum OverlayFlags; @@ -103,7 +100,7 @@ struct Palette *BKE_palette_add(struct Main *bmain, const char *name); struct PaletteColor *BKE_palette_color_add(struct Palette *palette); bool BKE_palette_is_empty(const struct Palette *palette); void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color); -void BKE_palette_cleanup(struct Palette *palette); +void BKE_palette_clear(struct Palette *palette); /* paint curves */ struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); @@ -123,6 +120,7 @@ void BKE_paint_brush_set(struct Paint *paint, struct Brush *br); struct Palette *BKE_paint_palette(struct Paint *paint); void BKE_paint_palette_set(struct Paint *p, struct Palette *palette); void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc); +void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, const int add_index); void BKE_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil); bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil); @@ -146,6 +144,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, /* stroke related */ void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]); +void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation); void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); @@ -158,7 +157,6 @@ typedef struct SculptSession { struct MPoly *mpoly; struct MLoop *mloop; int totvert, totpoly; - float (*face_normals)[3]; struct KeyBlock *kb; float *vmask; @@ -197,8 +195,8 @@ typedef struct SculptSession { struct StrokeCache *cache; } SculptSession; -void BKE_free_sculptsession(struct Object *ob); -void BKE_free_sculptsession_deformMats(struct SculptSession *ss); +void BKE_sculptsession_free(struct Object *ob); +void BKE_sculptsession_free_deformMats(struct SculptSession *ss); void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder); void BKE_sculptsession_bm_to_me_for_render(struct Object *object); void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index ab3231d7c12..f8ddb33b0ba 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -45,10 +45,8 @@ struct ParticleSystemModifierData; struct ParticleSystem; struct ParticleKey; struct ParticleSettings; -struct HairKey; struct Main; -struct Group; struct Object; struct Scene; struct DerivedMesh; @@ -57,12 +55,10 @@ struct MTFace; struct MCol; struct MFace; struct MVert; -struct IpoCurve; struct LatticeDeformData; struct LinkNode; struct KDTree; struct RNG; -struct SurfaceModifierData; struct BVHTreeRay; struct BVHTreeRayHit; struct EdgeHash; @@ -122,6 +118,7 @@ typedef struct ParticleTexture { float damp, gravity, field; /* used in physics */ float length, clump, kink_freq, kink_amp, effector; /* used in path caching */ float rough1, rough2, roughe; /* used in path caching */ + float color[3]; } ParticleTexture; typedef struct ParticleSeam { @@ -395,7 +392,7 @@ void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct Pa void psys_thread_context_init(struct ParticleThreadContext *ctx, struct ParticleSimulationData *sim); void psys_thread_context_free(struct ParticleThreadContext *ctx); -void psys_tasks_create(struct ParticleThreadContext *ctx, int totpart, struct ParticleTask **r_tasks, int *r_numtasks); +void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int endpart, struct ParticleTask **r_tasks, int *r_numtasks); void psys_tasks_free(struct ParticleTask *tasks, int numtasks); void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]); @@ -431,6 +428,7 @@ void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]); void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]); void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]); +void psys_child_mat_to_object(struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct ChildParticle *cpa, float hairmat[4][4]); float psys_get_dietime_from_cache(struct PointCache *cache, int index); @@ -445,6 +443,7 @@ void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFa float orco[3], float ornor[3]); float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values); void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time); +int psys_get_index_on_dm(struct ParticleSystem *psys, struct DerivedMesh *dm, ParticleData *pa, int *mapindex, float mapfw[4]); /* BLI_bvhtree_ray_cast callback */ void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit); @@ -499,4 +498,12 @@ typedef struct ParticleRenderData { #define DMCACHE_NOTFOUND -1 #define DMCACHE_ISCHILD -2 +/* **** Depsgraph evaluation **** */ + +struct EvaluationContext; + +void BKE_particle_system_eval(struct EvaluationContext *eval_ctx, + struct Object *ob, + struct ParticleSystem *psys); + #endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index c8c693fc342..227994b73ee 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -34,8 +34,6 @@ struct CCGElem; struct CCGKey; struct CustomData; struct DMFlagMat; -struct DMGridAdjacency; -struct GHash; struct MFace; struct MVert; struct PBVH; @@ -64,7 +62,7 @@ PBVH *BKE_pbvh_new(void); void BKE_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, int totface, int totvert, struct CustomData *vdata); void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, - struct DMGridAdjacency *gridadj, int totgrid, + int totgrid, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset); @@ -105,8 +103,9 @@ bool BKE_pbvh_bmesh_node_raycast_detail( /* for orthographic cameras, project the far away ray segment points to the root node so * we can have better precision. */ -void BKE_pbvh_raycast_project_ray_root(PBVH *bvh, bool original, float ray_start[3], - float ray_end[3], float ray_normal[3]); +void BKE_pbvh_raycast_project_ray_root( + PBVH *bvh, bool original, + float ray_start[3], float ray_end[3], float ray_normal[3]); /* Drawing */ @@ -122,6 +121,7 @@ typedef enum { } PBVHType; PBVHType BKE_pbvh_type(const PBVH *bvh); +bool BKE_pbvh_has_faces(const PBVH *bvh); /* Get the PBVH root's bounding box */ void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]); @@ -144,8 +144,10 @@ typedef enum { PBVH_Subdivide = 1, PBVH_Collapse = 2, } PBVHTopologyUpdateMode; -bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, - const float center[3], float radius); +bool BKE_pbvh_bmesh_update_topology( + PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], const float view_normal[3], + float radius); /* Node Access */ @@ -173,7 +175,7 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, - struct CCGElem ***grid_elems, struct DMGridAdjacency **gridadj); + struct CCGElem ***grid_elems); void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert); void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, @@ -201,7 +203,7 @@ void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface); void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, - struct DMGridAdjacency *gridadj, void **gridfaces, + void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); /* Layer displacement */ @@ -334,6 +336,9 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro void BKE_pbvh_node_free_proxies(PBVHNode *node); PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node); void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode); +void BKE_pbvh_node_get_bm_orco_data( + PBVHNode *node, + int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3]); //void BKE_pbvh_node_BB_reset(PBVHNode *node); //void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index e18e9d46a25..3d67b91d767 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -267,10 +267,8 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct Rig void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis); -/***************** Global funcs ****************************/ -void BKE_ptcache_remove(void); - /************ ID specific functions ************************/ +void BKE_ptcache_id_clear_ex(PTCacheID *pid, int mode, unsigned int cfra, bool allow_file_delete); void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra); int BKE_ptcache_id_exist(PTCacheID *id, int cfra); int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode); @@ -303,7 +301,7 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); void BKE_ptcache_free_mem(struct ListBase *mem_cache); void BKE_ptcache_free(struct PointCache *cache); void BKE_ptcache_free_list(struct ListBase *ptcaches); -struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, struct ListBase *ptcaches_old, bool copy_data); +struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data); /********************** Baking *********************/ @@ -314,10 +312,10 @@ void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene); void BKE_ptcache_bake(struct PTCacheBaker *baker); /* Convert disk cache to memory cache. */ -void BKE_ptcache_disk_to_mem(struct PTCacheID *pid); +void BKE_ptcache_disk_to_mem(struct PTCacheID *pid, bool clear); /* Convert memory cache to disk cache. */ -void BKE_ptcache_mem_to_disk(struct PTCacheID *pid); +void BKE_ptcache_mem_to_disk(struct PTCacheID *pid, bool clear); /* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */ void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid); diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index c946f3ac9e8..b327f0c2574 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -39,7 +39,6 @@ struct RigidBodyOb; struct Scene; struct Object; -struct Group; /* -------------- */ /* Memory Management */ @@ -99,4 +98,19 @@ void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw); void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime); void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime); +/* -------------------- */ +/* Depsgraph evaluation */ + +struct EvaluationContext; + +void BKE_rigidbody_rebuild_sim(struct EvaluationContext *eval_ctx, + struct Scene *scene); + +void BKE_rigidbody_eval_simulation(struct EvaluationContext *eval_ctx, + struct Scene *scene); + +void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob); + #endif /* __BKE_RIGIDBODY_H__ */ diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index d598a26fdf9..ebdd159b40c 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -31,7 +31,6 @@ * \ingroup bke */ -struct Text; struct bSensor; struct Object; struct bController; diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 149472db8fa..e6b19296068 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -39,16 +39,14 @@ extern "C" { struct AviCodecData; struct Base; -struct DisplaySafeAreas; struct EvaluationContext; -struct bglMats; +struct Group; struct Main; struct Object; struct QuicktimeCodecData; struct RenderData; struct SceneRenderLayer; struct Scene; -struct Text; struct UnitSettings; struct Main; @@ -73,6 +71,7 @@ void BKE_scene_free(struct Scene *sce); struct Scene *BKE_scene_add(struct Main *bmain, const char *name); /* base functions */ +struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name); struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob); struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob); void BKE_scene_base_unlink(struct Scene *sce, struct Base *base); @@ -113,28 +112,37 @@ char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame); /* checks for cycle, returns 1 if it's all OK */ bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce); -float BKE_scene_frame_get(struct Scene *scene); -float BKE_scene_frame_get_from_ctime(struct Scene *scene, const float frame); +float BKE_scene_frame_get(const struct Scene *scene); +float BKE_scene_frame_get_from_ctime(const struct Scene *scene, const float frame); void BKE_scene_frame_set(struct Scene *scene, double cfra); /* ** Scene evaluation ** */ void BKE_scene_update_tagged(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce); void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay); void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay, bool do_invisible_flush); +void BKE_scene_update_group_for_newframe(struct EvaluationContext *eval_ctx, + struct Main *bmain, + struct Scene *scene, + struct Group *group, + unsigned int lay); struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name); bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl); +struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name); +bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv); + /* render profile */ -int get_render_subsurf_level(struct RenderData *r, int level); -int get_render_child_particle_number(struct RenderData *r, int num); -int get_render_shadow_samples(struct RenderData *r, int samples); -float get_render_aosss_error(struct RenderData *r, float error); +int get_render_subsurf_level(const struct RenderData *r, int level, bool for_render); +int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render); +int get_render_shadow_samples(const struct RenderData *r, int samples); +float get_render_aosss_error(const struct RenderData *r, float error); -bool BKE_scene_use_new_shading_nodes(struct Scene *scene); +bool BKE_scene_use_new_shading_nodes(const struct Scene *scene); +bool BKE_scene_use_shading_nodes_custom(struct Scene *scene); -bool BKE_scene_uses_blender_internal(struct Scene *scene); -bool BKE_scene_uses_blender_game(struct Scene *scene); +bool BKE_scene_uses_blender_internal(const struct Scene *scene); +bool BKE_scene_uses_blender_game(const struct Scene *scene); void BKE_scene_disable_color_management(struct Scene *scene); bool BKE_scene_check_color_management_enabled(const struct Scene *scene); @@ -145,6 +153,23 @@ int BKE_render_num_threads(const struct RenderData *r); double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value); +/* multiview */ +bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd); +bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv); +bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname); +bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname); +size_t BKE_scene_multiview_num_views_get(const struct RenderData *rd); +struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd, const int view_id); +const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, const int view_id); +size_t BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname); +void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, const char *filepath, char *r_filepath); +void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath); +const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname); +const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const size_t view_id); +void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char *name, char *rprefix, char **rext); +void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height); +size_t BKE_scene_multiview_num_videos_get(const struct RenderData *rd); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index efe2c52e99c..60fd402ef4b 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -47,7 +47,6 @@ struct bContextDataResult; struct bScreen; struct uiLayout; struct uiList; -struct uiMenuItem; struct wmKeyConfig; struct wmNotifier; struct wmWindow; @@ -277,6 +276,9 @@ void BKE_spacedata_freelist(ListBase *lb); void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2); void BKE_spacedata_draw_locks(int set); +void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)); +void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); + /* area/regions */ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar); @@ -284,6 +286,7 @@ void BKE_screen_area_free(struct ScrArea *sa); struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); +struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y); struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min); struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y); @@ -293,6 +296,8 @@ unsigned int BKE_screen_view3d_layer_active_ex( unsigned int BKE_screen_view3d_layer_active( const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2); +unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); + void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene); void BKE_screen_view3d_scene_sync(struct bScreen *sc); void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 8958fc2ca85..5f159b14fb8 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -38,11 +38,10 @@ struct GSet; struct ImBuf; struct Main; struct Mask; -struct MovieClip; struct Scene; struct Sequence; struct SequenceModifierData; -struct Strip; +struct Stereo3dFormat; struct StripElem; struct bSound; @@ -101,6 +100,7 @@ typedef struct SeqRenderData { float motion_blur_shutter; bool skip_cache; bool is_proxy_render; + size_t view_id; } SeqRenderData; void BKE_sequencer_new_render_data( @@ -225,6 +225,7 @@ void BKE_sequencer_base_clipboard_pointers_store(struct ListBase *seqbase); void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain); void BKE_sequence_free(struct Scene *scene, struct Sequence *seq); +void BKE_sequence_free_anim(struct Sequence *seq); const char *BKE_sequence_give_name(struct Sequence *seq); ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset); void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq); @@ -238,7 +239,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra); void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change); bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra); -struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list); +void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue); void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress); void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop); @@ -296,7 +297,7 @@ int BKE_sequence_effect_get_supports_mask(int seq_type); * Sequencer editing functions * ********************************************************************** */ - + /* for transform but also could use elsewhere */ int BKE_sequence_tx_get_final_left(struct Sequence *seq, bool metaclip); int BKE_sequence_tx_get_final_right(struct Sequence *seq, bool metaclip); @@ -358,6 +359,10 @@ typedef struct SeqLoadInfo { int len; /* only for image strips */ char path[1024]; /* 1024 = FILE_MAX */ + /* multiview */ + char views_format; + struct Stereo3dFormat *stereo3d_format; + /* return values */ char name[64]; struct Sequence *seq_sound; /* for movie's */ @@ -402,7 +407,7 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load); /* view3d draw callback, run when not in background view */ -typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, char[256]); +typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]); extern SequencerDrawView sequencer_view3d_cb; /* copy/paste */ @@ -436,7 +441,7 @@ typedef struct SequenceModifierTypeInfo { void (*apply) (struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask); } SequenceModifierTypeInfo; -struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type); +const struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type); struct SequenceModifierData *BKE_sequence_modifier_new(struct Sequence *seq, const char *name, int type); bool BKE_sequence_modifier_remove(struct Sequence *seq, struct SequenceModifierData *smd); @@ -450,7 +455,9 @@ void BKE_sequence_modifier_list_copy(struct Sequence *seqn, struct Sequence *seq int BKE_sequence_supports_modifiers(struct Sequence *seq); /* internal filters */ -struct ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id, int cfra, bool make_float); +struct ImBuf *BKE_sequencer_render_mask_input( + const SeqRenderData *context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id, + int cfra, int fra_offset, bool make_float); void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb, struct ImBuf *ibuf, float mul, bool make_float, struct ImBuf *mask_input); #endif /* __BKE_SEQUENCER_H__ */ diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 070cd4a9cf0..070f5c762db 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -47,7 +47,6 @@ */ struct Object; -struct Scene; struct DerivedMesh; struct MVert; struct MDeformVert; diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index a4182b8405f..819b49da8e9 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -35,9 +35,7 @@ #define SOUND_WAVE_SAMPLES_PER_SECOND 250 -struct PackedFile; struct bSound; -struct ListBase; struct Main; struct Sequence; @@ -46,98 +44,98 @@ typedef struct SoundWaveform { float *data; } SoundWaveform; -void sound_init_once(void); -void sound_exit_once(void); +void BKE_sound_init_once(void); +void BKE_sound_exit_once(void); -void sound_init(struct Main *main); +void BKE_sound_init(struct Main *main); -void sound_init_main(struct Main *bmain); +void BKE_sound_init_main(struct Main *bmain); -void sound_exit(void); +void BKE_sound_exit(void); -void sound_force_device(int device); -int sound_define_from_str(const char *str); +void BKE_sound_force_device(int device); +int BKE_sound_define_from_str(const char *str); -struct bSound *sound_new_file(struct Main *main, const char *filename); +struct bSound *BKE_sound_new_file(struct Main *main, const char *filename); // XXX unused currently #if 0 -struct bSound *sound_new_buffer(struct Main *bmain, struct bSound *source); +struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source); -struct bSound *sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end); +struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end); #endif -void sound_delete(struct Main *bmain, struct bSound *sound); +void BKE_sound_delete(struct Main *bmain, struct bSound *sound); -void sound_cache(struct bSound *sound); +void BKE_sound_cache(struct bSound *sound); -void sound_delete_cache(struct bSound *sound); +void BKE_sound_delete_cache(struct bSound *sound); -void sound_load(struct Main *main, struct bSound *sound); +void BKE_sound_load(struct Main *main, struct bSound *sound); void BKE_sound_free(struct bSound *sound); #ifdef __AUD_C_API_H__ -AUD_Device *sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume); +AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume); #endif -void sound_create_scene(struct Scene *scene); +void BKE_sound_create_scene(struct Scene *scene); -void sound_destroy_scene(struct Scene *scene); +void BKE_sound_destroy_scene(struct Scene *scene); -void sound_mute_scene(struct Scene *scene, int muted); +void BKE_sound_mute_scene(struct Scene *scene, int muted); -void sound_update_fps(struct Scene *scene); +void BKE_sound_update_fps(struct Scene *scene); -void sound_update_scene_listener(struct Scene *scene); +void BKE_sound_update_scene_listener(struct Scene *scene); -void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip); -void *sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); +void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip); +void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); -void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip); -void *sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); +void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip); +void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); -void sound_remove_scene_sound(struct Scene *scene, void *handle); +void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle); -void sound_mute_scene_sound(void *handle, char mute); +void BKE_sound_mute_scene_sound(void *handle, char mute); -void sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip); -void sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); +void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip); +void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); -void sound_update_scene_sound(void *handle, struct bSound *sound); +void BKE_sound_update_scene_sound(void *handle, struct bSound *sound); -void sound_set_cfra(int cfra); +void BKE_sound_set_cfra(int cfra); -void sound_set_scene_volume(struct Scene *scene, float volume); +void BKE_sound_set_scene_volume(struct Scene *scene, float volume); -void sound_set_scene_sound_volume(void *handle, float volume, char animated); +void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated); -void sound_set_scene_sound_pitch(void *handle, float pitch, char animated); +void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated); -void sound_set_scene_sound_pan(void *handle, float pan, char animated); +void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated); -void sound_update_sequencer(struct Main *main, struct bSound *sound); +void BKE_sound_update_sequencer(struct Main *main, struct bSound *sound); -void sound_play_scene(struct Scene *scene); +void BKE_sound_play_scene(struct Scene *scene); -void sound_stop_scene(struct Scene *scene); +void BKE_sound_stop_scene(struct Scene *scene); -void sound_seek_scene(struct Main *bmain, struct Scene *scene); +void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene); -float sound_sync_scene(struct Scene *scene); +float BKE_sound_sync_scene(struct Scene *scene); -int sound_scene_playing(struct Scene *scene); +int BKE_sound_scene_playing(struct Scene *scene); -void sound_free_waveform(struct bSound *sound); +void BKE_sound_free_waveform(struct bSound *sound); -void sound_read_waveform(struct bSound *sound, short *stop); +void BKE_sound_read_waveform(struct bSound *sound, short *stop); -void sound_update_scene(struct Main *bmain, struct Scene *scene); +void BKE_sound_update_scene(struct Main *bmain, struct Scene *scene); -void *sound_get_factory(void *sound); +void *BKE_sound_get_factory(void *sound); -float sound_get_length(struct bSound *sound); +float BKE_sound_get_length(struct bSound *sound); -bool sound_is_jack_supported(void); +bool BKE_sound_is_jack_supported(void); #endif /* __BKE_SOUND_H__ */ diff --git a/source/blender/blenkernel/BKE_strands.h b/source/blender/blenkernel/BKE_strands.h new file mode 100644 index 00000000000..2ec1363727b --- /dev/null +++ b/source/blender/blenkernel/BKE_strands.h @@ -0,0 +1,358 @@ +/* + * Copyright 2015, Blender Foundation. + * + * 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_STRANDS_H__ +#define __BKE_STRANDS_H__ + +#include "BLI_utildefines.h" + +#include "DNA_strands_types.h" + +struct StrandChildIterator; + +struct Strands *BKE_strands_new(int strands, int verts); +struct Strands *BKE_strands_copy(struct Strands *strands); +void BKE_strands_free(struct Strands *strands); + +void BKE_strands_add_motion_state(struct Strands *strands); +void BKE_strands_remove_motion_state(struct Strands *strands); +void BKE_strands_state_copy_rest_positions(struct Strands *strands); +void BKE_strands_state_clear_velocities(struct Strands *strands); + +void BKE_strands_ensure_normals(struct Strands *strands); + +void BKE_strands_get_minmax(struct Strands *strands, float min[3], float max[3], bool use_motion_state); + + +struct StrandsChildren *BKE_strands_children_new(int strands, int verts); +struct StrandsChildren *BKE_strands_children_copy(struct StrandsChildren *strands); +void BKE_strands_children_free(struct StrandsChildren *strands); + +void BKE_strands_children_add_uvs(struct StrandsChildren *strands, int num_layers); +void BKE_strands_children_add_vcols(struct StrandsChildren *strands, int num_layers); + +void BKE_strands_children_deform(struct StrandsChildren *strands, struct Strands *parents, bool use_motion); + +void BKE_strands_children_ensure_normals(struct StrandsChildren *strands); + +void BKE_strands_children_get_minmax(struct StrandsChildren *strands, float min[3], float max[3]); + +/* ------------------------------------------------------------------------- */ +/* Strand Curves Iterator */ + +typedef struct StrandIterator { + int index, tot; + struct StrandsCurve *curve; + struct StrandsVertex *verts; + struct StrandsMotionState *state; +} StrandIterator; + +BLI_INLINE void BKE_strand_iter_init(StrandIterator *iter, Strands *strands) +{ + iter->tot = strands->totcurves; + iter->index = 0; + iter->curve = strands->curves; + iter->verts = strands->verts; + iter->state = strands->state; +} + +BLI_INLINE bool BKE_strand_iter_valid(StrandIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_iter_next(StrandIterator *iter) +{ + const int numverts = iter->curve->numverts; + + ++iter->index; + ++iter->curve; + iter->verts += numverts; + if (iter->state) + iter->state += numverts; +} + +BLI_INLINE size_t BKE_strand_iter_curve_offset(Strands *strands, StrandIterator *iter) +{ + return iter->curve - strands->curves; +} + +BLI_INLINE size_t BKE_strand_iter_vertex_offset(Strands *strands, StrandIterator *iter) +{ + return iter->verts - strands->verts; +} + +/* ------------------------------------------------------------------------- */ +/* Strand Vertices Iterator */ + +typedef struct StrandVertexIterator { + int index, tot; + StrandsVertex *vertex; + StrandsMotionState *state; +} StrandVertexIterator; + +BLI_INLINE void BKE_strand_vertex_iter_init(StrandVertexIterator *iter, StrandIterator *strand_iter) +{ + iter->tot = strand_iter->curve->numverts; + iter->index = 0; + iter->vertex = strand_iter->verts; + iter->state = strand_iter->state; +} + +BLI_INLINE bool BKE_strand_vertex_iter_valid(StrandVertexIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_vertex_iter_next(StrandVertexIterator *iter) +{ + ++iter->vertex; + if (iter->state) + ++iter->state; + ++iter->index; +} + +BLI_INLINE size_t BKE_strand_vertex_iter_vertex_offset(Strands *strands, StrandVertexIterator *iter) +{ + return iter->vertex - strands->verts; +} + +/* ------------------------------------------------------------------------- */ +/* Strand Edges Iterator */ + +typedef struct StrandEdgeIterator { + int index, tot; + StrandsVertex *vertex0, *vertex1; + StrandsMotionState *state0, *state1; +} StrandEdgeIterator; + +BLI_INLINE void BKE_strand_edge_iter_init(StrandEdgeIterator *iter, StrandIterator *strand_iter) +{ + iter->tot = strand_iter->curve->numverts - 1; + iter->index = 0; + iter->vertex0 = strand_iter->verts; + iter->state0 = strand_iter->state; + iter->vertex1 = strand_iter->verts + 1; + iter->state1 = strand_iter->state + 1; +} + +BLI_INLINE bool BKE_strand_edge_iter_valid(StrandEdgeIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_edge_iter_next(StrandEdgeIterator *iter) +{ + ++iter->vertex0; + ++iter->vertex1; + if (iter->state0) { + ++iter->state0; + ++iter->state1; + } + ++iter->index; +} + +BLI_INLINE size_t BKE_strand_edge_iter_vertex0_offset(Strands *strands, StrandEdgeIterator *iter) +{ + return iter->vertex0 - strands->verts; +} + +BLI_INLINE size_t BKE_strand_edge_iter_vertex1_offset(Strands *strands, StrandEdgeIterator *iter) +{ + return iter->vertex1 - strands->verts; +} + +/* ------------------------------------------------------------------------- */ +/* Strand Bends Iterator */ + +typedef struct StrandBendIterator { + int index, tot; + StrandsVertex *vertex0, *vertex1, *vertex2; + StrandsMotionState *state0, *state1, *state2; +} StrandBendIterator; + +BLI_INLINE void BKE_strand_bend_iter_init(StrandBendIterator *iter, StrandIterator *strand_iter) +{ + iter->tot = strand_iter->curve->numverts - 2; + iter->index = 0; + iter->vertex0 = strand_iter->verts; + iter->state0 = strand_iter->state; + iter->vertex1 = strand_iter->verts + 1; + iter->state1 = strand_iter->state + 1; + iter->vertex2 = strand_iter->verts + 2; + iter->state2 = strand_iter->state + 2; +} + +BLI_INLINE bool BKE_strand_bend_iter_valid(StrandBendIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_bend_iter_next(StrandBendIterator *iter) +{ + ++iter->vertex0; + ++iter->vertex1; + ++iter->vertex2; + if (iter->state0) { + ++iter->state0; + ++iter->state1; + ++iter->state2; + } + ++iter->index; +} + +BLI_INLINE size_t BKE_strand_bend_iter_vertex0_offset(Strands *strands, StrandBendIterator *iter) +{ + return iter->vertex0 - strands->verts; +} + +BLI_INLINE size_t BKE_strand_bend_iter_vertex1_offset(Strands *strands, StrandBendIterator *iter) +{ + return iter->vertex1 - strands->verts; +} + +BLI_INLINE size_t BKE_strand_bend_iter_vertex2_offset(Strands *strands, StrandBendIterator *iter) +{ + return iter->vertex2 - strands->verts; +} + +void BKE_strand_bend_iter_transform_rest(StrandBendIterator *iter, float mat[3][3]); +void BKE_strand_bend_iter_transform_state(StrandBendIterator *iter, float mat[3][3]); + +/* ------------------------------------------------------------------------- */ +/* Strand Child Curves Iterator */ + +typedef struct StrandChildIterator { + int index, tot, numuv, numvcol; + StrandsChildCurve *curve; + StrandsChildCurveUV *curve_uv; + StrandsChildCurveVCol *curve_vcol; + StrandsChildVertex *verts; +} StrandChildIterator; + +BLI_INLINE void BKE_strand_child_iter_init(StrandChildIterator *iter, StrandsChildren *strands) +{ + iter->tot = strands->totcurves; + iter->numuv = strands->numuv; + iter->numvcol = strands->numvcol; + iter->index = 0; + + iter->curve = strands->curves; + iter->curve_uv = strands->curve_uvs; + iter->curve_vcol = strands->curve_vcols; + iter->verts = strands->verts; +} + +BLI_INLINE bool BKE_strand_child_iter_valid(StrandChildIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_child_iter_next(StrandChildIterator *iter) +{ + const int numverts = iter->curve->numverts; + + ++iter->index; + ++iter->curve; + if (iter->curve_uv) + iter->curve_uv += iter->numuv; + if (iter->curve_vcol) + iter->curve_vcol += iter->numvcol; + iter->verts += numverts; +} + +BLI_INLINE size_t BKE_strand_child_iter_curve_offset(StrandsChildren *strands, StrandChildIterator *iter) +{ + return iter->curve - strands->curves; +} + +BLI_INLINE size_t BKE_strand_child_iter_vertex_offset(StrandsChildren *strands, StrandChildIterator *iter) +{ + return iter->verts - strands->verts; +} + +/* ------------------------------------------------------------------------- */ +/* Strand Child Vertices Iterator */ + +typedef struct StrandChildVertexIterator { + int index, tot; + StrandsChildVertex *vertex; +} StrandChildVertexIterator; + +BLI_INLINE void BKE_strand_child_vertex_iter_init(StrandChildVertexIterator *iter, StrandChildIterator *strand_iter) +{ + iter->tot = strand_iter->curve->numverts; + iter->index = 0; + iter->vertex = strand_iter->verts; +} + +BLI_INLINE bool BKE_strand_child_vertex_iter_valid(StrandChildVertexIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_child_vertex_iter_next(StrandChildVertexIterator *iter) +{ + ++iter->vertex; + ++iter->index; +} + +BLI_INLINE size_t BKE_strand_child_vertex_iter_vertex_offset(StrandsChildren *strands, StrandChildVertexIterator *iter) +{ + return iter->vertex - strands->verts; +} + +/* ------------------------------------------------------------------------- */ +/* Strand Child Edges Iterator */ + +typedef struct StrandChildEdgeIterator { + int index, tot; + StrandsChildVertex *vertex0, *vertex1; +} StrandChildEdgeIterator; + +BLI_INLINE void BKE_strand_child_edge_iter_init(StrandChildEdgeIterator *iter, StrandChildIterator *strand_iter) +{ + iter->tot = strand_iter->curve->numverts - 1; + iter->index = 0; + iter->vertex0 = strand_iter->verts; + iter->vertex1 = strand_iter->verts + 1; +} + +BLI_INLINE bool BKE_strand_child_edge_iter_valid(StrandChildEdgeIterator *iter) +{ + return iter->index < iter->tot; +} + +BLI_INLINE void BKE_strand_child_edge_iter_next(StrandChildEdgeIterator *iter) +{ + ++iter->vertex0; + ++iter->vertex1; + ++iter->index; +} + +BLI_INLINE size_t BKE_strand_child_edge_iter_vertex0_offset(StrandsChildren *strands, StrandChildEdgeIterator *iter) +{ + return iter->vertex0 - strands->verts; +} + +BLI_INLINE size_t BKE_strand_child_edge_iter_vertex1_offset(StrandsChildren *strands, StrandChildEdgeIterator *iter) +{ + return iter->vertex1 - strands->verts; +} + +#endif /* __BKE_STRANDS_H__ */ diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 3dae4087866..c1c96c8228c 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -41,17 +41,14 @@ struct DerivedMesh; struct MeshElemMap; struct Mesh; struct MPoly; -struct MultiresSubsurf; struct Object; struct PBVH; struct SubsurfModifierData; struct CCGEdge; struct CCGFace; -struct CCGSubsurf; struct CCGVert; struct EdgeHash; struct PBVH; -struct DMGridAdjacency; /**************************** External *****************************/ @@ -120,7 +117,6 @@ typedef struct CCGDerivedMesh { int *pmap_mem; struct CCGElem **gridData; - struct DMGridAdjacency *gridAdjacency; int *gridOffset; struct CCGFace **gridFaces; struct DMFlagMat *gridFlagMats; diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 96e88f80464..a5a59d14c92 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -40,14 +40,13 @@ extern "C" { struct Main; struct Text; struct TextLine; -struct SpaceText; void BKE_text_free (struct Text *text); void txt_set_undostate (int u); int txt_get_undostate (void); struct Text *BKE_text_add (struct Main *bmain, const char *name); int txt_extended_ascii_as_utf8(char **str); -int BKE_text_reload (struct Text *text); +bool BKE_text_reload(struct Text *text); struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath, const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index ebf85ff51d1..95918b9ca0b 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -42,9 +42,7 @@ struct Brush; struct ColorBand; struct EnvMap; struct FreestyleLineStyle; -struct HaloRen; struct Lamp; -struct LampRen; struct Main; struct Material; struct MTex; @@ -61,8 +59,6 @@ struct World; #define MAXCOLORBAND 32 -void BKE_texture_free(struct Tex *t); - void init_colorband(struct ColorBand *coba, bool rangetype); struct ColorBand *add_colorband(bool rangetype); bool do_colorband(const struct ColorBand *coba, float in, float out[4]); @@ -71,15 +67,17 @@ struct CBData *colorband_element_add(struct ColorBand *coba, float position); int colorband_element_remove(struct ColorBand *coba, int index); void colorband_update_sort(struct ColorBand *coba); -void default_tex(struct Tex *tex); -struct Tex *add_texture(struct Main *bmain, const char *name); -void tex_set_type(struct Tex *tex, int type); -void default_mtex(struct MTex *mtex); -struct MTex *add_mtex(void); -struct MTex *add_mtex_id(struct ID *id, int slot); -struct Tex *BKE_texture_copy(struct Tex *tex); -struct Tex *localize_texture(struct Tex *tex); -void BKE_texture_make_local(struct Tex *tex); +void BKE_texture_free(struct Tex *tex); +void BKE_texture_default(struct Tex *tex); +struct Tex *BKE_texture_copy(struct Tex *tex); +struct Tex *BKE_texture_add(struct Main *bmain, const char *name); +struct Tex *BKE_texture_localize(struct Tex *tex); +void BKE_texture_make_local(struct Tex *tex); +void BKE_texture_type_set(struct Tex *tex, int type); + +void BKE_texture_mtex_default(struct MTex *mtex); +struct MTex *BKE_texture_mtex_add(void); +struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot); /* UNUSED */ // void autotexname(struct Tex *tex); @@ -105,36 +103,39 @@ void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex bool has_current_material_texture(struct Material *ma); -struct TexMapping *add_tex_mapping(int type); -void default_tex_mapping(struct TexMapping *texmap, int type); -void init_tex_mapping(struct TexMapping *texmap); +struct TexMapping *BKE_texture_mapping_add(int type); +void BKE_texture_mapping_default(struct TexMapping *texmap, int type); +void BKE_texture_mapping_init(struct TexMapping *texmap); + +struct ColorMapping *BKE_texture_colormapping_add(void); +void BKE_texture_colormapping_default(struct ColorMapping *colormap); -struct ColorMapping *add_color_mapping(void); -void default_color_mapping(struct ColorMapping *colormap); +void BKE_texture_envmap_free_data(struct EnvMap *env); +void BKE_texture_envmap_free(struct EnvMap *env); +struct EnvMap *BKE_texture_envmap_add(void); +struct EnvMap *BKE_texture_envmap_copy(struct EnvMap *env); -void BKE_free_envmapdata(struct EnvMap *env); -void BKE_free_envmap(struct EnvMap *env); -struct EnvMap *BKE_add_envmap(void); -struct EnvMap *BKE_copy_envmap(struct EnvMap *env); +void BKE_texture_pointdensity_init_data(struct PointDensity *pd); +void BKE_texture_pointdensity_free_data(struct PointDensity *pd); +void BKE_texture_pointdensity_free(struct PointDensity *pd); +struct PointDensity *BKE_texture_pointdensity_add(void); +struct PointDensity *BKE_texture_pointdensity_copy(struct PointDensity *pd); -void BKE_free_pointdensitydata(struct PointDensity *pd); -void BKE_free_pointdensity(struct PointDensity *pd); -struct PointDensity *BKE_add_pointdensity(void); -struct PointDensity *BKE_copy_pointdensity(struct PointDensity *pd); +void BKE_texture_voxeldata_free_data(struct VoxelData *vd); +void BKE_texture_voxeldata_free(struct VoxelData *vd); +struct VoxelData *BKE_texture_voxeldata_add(void); +struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd); -void BKE_free_voxeldatadata(struct VoxelData *vd); -void BKE_free_voxeldata(struct VoxelData *vd); -struct VoxelData *BKE_add_voxeldata(void); -struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd); +void BKE_texture_ocean_free(struct OceanTex *ot); +struct OceanTex *BKE_texture_ocean_add(void); +struct OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot); -void BKE_free_oceantex(struct OceanTex *ot); -struct OceanTex *BKE_add_oceantex(void); -struct OceanTex *BKE_copy_oceantex(struct OceanTex *ot); - bool BKE_texture_dependsOnTime(const struct Tex *texture); bool BKE_texture_is_image_user(const struct Tex *tex); -void BKE_texture_get_value(struct Scene *scene, struct Tex *texture, float *tex_co, struct TexResult *texres, bool use_color_management); +void BKE_texture_get_value( + const struct Scene *scene, struct Tex *texture, + float *tex_co, struct TexResult *texres, bool use_color_management); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index e5fb60cf1b5..b03a234e1e7 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -41,7 +41,6 @@ struct MovieTrackingMarker; struct MovieTrackingPlaneTrack; struct MovieTrackingPlaneMarker; struct MovieTracking; -struct MovieTrackingContext; struct MovieTrackingObject; struct MovieClipUser; struct MovieDistortion; @@ -91,7 +90,7 @@ struct MovieTrackingTrack *BKE_tracking_track_get_named(struct MovieTracking *tr struct MovieTrackingObject *object, const char *name); struct MovieTrackingTrack *BKE_tracking_track_get_indexed(struct MovieTracking *tracking, int tracknr, - struct ListBase **tracksbase_r); + struct ListBase **r_tracksbase); struct MovieTrackingTrack *BKE_tracking_track_get_active(struct MovieTracking *tracking); @@ -137,6 +136,21 @@ struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct Movie void BKE_tracking_plane_tracks_deselect_all(struct ListBase *plane_tracks_base); +bool BKE_tracking_plane_track_has_point_track(struct MovieTrackingPlaneTrack *plane_track, + struct MovieTrackingTrack *track); +bool BKE_tracking_plane_track_remove_point_track(struct MovieTrackingPlaneTrack *plane_track, + struct MovieTrackingTrack *track); + +void BKE_tracking_plane_tracks_remove_point_track(struct MovieTracking *tracking, + struct MovieTrackingTrack *track); + +void BKE_tracking_plane_track_replace_point_track(struct MovieTrackingPlaneTrack *plane_track, + struct MovieTrackingTrack *old_track, + struct MovieTrackingTrack *new_track); +void BKE_tracking_plane_tracks_replace_point_track(struct MovieTracking *tracking, + struct MovieTrackingTrack *old_track, + struct MovieTrackingTrack *new_track); + /* **** Plane Marker **** */ struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(struct MovieTrackingPlaneTrack *plane_track, struct MovieTrackingPlaneMarker *plane_marker); diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h index 78875951ca4..ca295c51f5d 100644 --- a/source/blender/blenkernel/BKE_writeavi.h +++ b/source/blender/blenkernel/BKE_writeavi.h @@ -43,16 +43,20 @@ struct ReportList; struct Scene; typedef struct bMovieHandle { - int (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports); - int (*append_movie)(struct RenderData *rd, int start_frame, int frame, int *pixels, - int rectx, int recty, struct ReportList *reports); - void (*end_movie)(void); - int (*get_next_frame)(struct RenderData *rd, struct ReportList *reports); /* optional */ - void (*get_movie_path)(char *string, struct RenderData *rd); /* optional */ + int (*start_movie)(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, + struct ReportList *reports, bool preview, const char *suffix); + int (*append_movie)(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, + int rectx, int recty, const char *suffix, struct ReportList *reports); + void (*end_movie)(void *context_v); + int (*get_next_frame)(void *context_v, struct RenderData *rd, struct ReportList *reports); /* optional */ + void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix); /* optional */ + void *(*context_create)(void); + void (*context_free)(void *context_v); } bMovieHandle; bMovieHandle *BKE_movie_handle_get(const char imtype); -void BKE_movie_filepath_get(char *string, struct RenderData *rd); +void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix); +void BKE_context_create(bMovieHandle *mh); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 703e84b3798..a40c31022e3 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -64,16 +64,15 @@ enum { FFMPEG_PRESET_XVID = 7, }; -struct IDProperty; struct RenderData; struct ReportList; struct Scene; -int BKE_ffmpeg_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports); -void BKE_ffmpeg_end(void); -int BKE_ffmpeg_append(struct RenderData *rd, int start_frame, int frame, int *pixels, - int rectx, int recty, struct ReportList *reports); -void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd); +int BKE_ffmpeg_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix); +void BKE_ffmpeg_end(void *context_v); +int BKE_ffmpeg_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, + int rectx, int recty, const char *suffix, struct ReportList *reports); +void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix); void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset); void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf); @@ -83,6 +82,9 @@ bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd); int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str); void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_); +void *BKE_ffmpeg_context_create(void); +void BKE_ffmpeg_context_free(void *context_v); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h index bdce9abe8ad..0837e9bce79 100644 --- a/source/blender/blenkernel/BKE_writeframeserver.h +++ b/source/blender/blenkernel/BKE_writeframeserver.h @@ -40,11 +40,16 @@ struct RenderData; struct ReportList; struct Scene; -int BKE_frameserver_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports); -void BKE_frameserver_end(void); -int BKE_frameserver_append(struct RenderData *rd, int start_frame, int frame, int *pixels, - int rectx, int recty, struct ReportList *reports); -int BKE_frameserver_loop(struct RenderData *rd, struct ReportList *reports); +int BKE_frameserver_start( + void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, + struct ReportList *reports, bool preview, const char *suffix); +void BKE_frameserver_end(void *context_v); +int BKE_frameserver_append( + void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, + int rectx, int recty, const char *suffix, struct ReportList *reports); +int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports); +void *BKE_frameserver_context_create(void); +void BKE_frameserver_context_free(void *context_v); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d61d6ee135c..70d26e8b27e 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC ../blenfont ../blenlib ../blenloader + ../depsgraph ../gpu ../ikplugin ../imbuf @@ -37,6 +38,7 @@ set(INC ../modifiers ../nodes ../physics + ../pointcache ../render/extern/include ../../../intern/ghost ../../../intern/guardedalloc @@ -67,6 +69,7 @@ set(SRC intern/anim_sys.c intern/appdir.c intern/armature.c + intern/armature_update.c intern/autoexec.c intern/blender.c intern/bmfont.c @@ -75,6 +78,7 @@ set(SRC intern/brush.c intern/bullet.c intern/bvhutils.c + intern/cache_library.c intern/camera.c intern/cdderivedmesh.c intern/cloth.c @@ -94,6 +98,7 @@ set(SRC intern/editderivedmesh.c intern/editmesh.c intern/editmesh_bvh.c + intern/editstrands.c intern/effect.c intern/facemap.c intern/fcurve.c @@ -120,10 +125,12 @@ set(SRC intern/mask_rasterize.c intern/material.c intern/mball.c + intern/mball_tessellate.c intern/mesh.c intern/mesh_evaluate.c intern/mesh_mapping.c intern/mesh_remap.c + intern/mesh_sample.c intern/mesh_validate.c intern/modifier.c intern/modifiers_bmesh.c @@ -134,7 +141,9 @@ set(SRC intern/object.c intern/object_deform.c intern/object_dupli.c + intern/object_update.c intern/ocean.c + intern/outliner_treehash.c intern/packedFile.c intern/paint.c intern/particle.c @@ -161,6 +170,7 @@ set(SRC intern/softbody.c intern/sound.c intern/speaker.c + intern/strands.c intern/subsurf_ccg.c intern/suggestions.c intern/text.c @@ -173,7 +183,6 @@ set(SRC intern/tracking_solver.c intern/tracking_stabilize.c intern/tracking_util.c - intern/treehash.c intern/unit.c intern/world.c intern/writeavi.c @@ -195,6 +204,7 @@ set(SRC BKE_brush.h BKE_bullet.h BKE_bvhutils.h + BKE_cache_library.h BKE_camera.h BKE_ccg.h BKE_cdderivedmesh.h @@ -212,6 +222,9 @@ set(SRC BKE_depsgraph.h BKE_displist.h BKE_dynamicpaint.h + BKE_editstrands.h + BKE_editmesh.h + BKE_editmesh_bvh.h BKE_effect.h BKE_facemap.h BKE_fcurve.h @@ -236,9 +249,11 @@ set(SRC BKE_mask.h BKE_material.h BKE_mball.h + BKE_mball_tessellate.h BKE_mesh.h BKE_mesh_mapping.h BKE_mesh_remap.h + BKE_mesh_sample.h BKE_modifier.h BKE_movieclip.h BKE_multires.h @@ -247,6 +262,7 @@ set(SRC BKE_object.h BKE_object_deform.h BKE_ocean.h + BKE_outliner_treehash.h BKE_packedFile.h BKE_paint.h BKE_particle.h @@ -265,14 +281,12 @@ set(SRC BKE_softbody.h BKE_sound.h BKE_speaker.h + BKE_strands.h BKE_subsurf.h BKE_suggestions.h - BKE_editmesh.h - BKE_editmesh_bvh.h BKE_text.h BKE_texture.h BKE_tracking.h - BKE_treehash.h BKE_unit.h BKE_utildefines.h BKE_world.h @@ -425,9 +439,16 @@ if(WITH_JACK) endif() if(WITH_LZO) - list(APPEND INC_SYS - ../../../extern/lzo/minilzo - ) + if(WITH_SYSTEM_LZO) + list(APPEND INC_SYS + ${LZO_INCLUDE_DIR} + ) + add_definitions(-DWITH_SYSTEM_LZO) + else() + list(APPEND INC_SYS + ../../../extern/lzo/minilzo + ) + endif() add_definitions(-DWITH_LZO) endif() @@ -474,4 +495,8 @@ endif() # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") #endif() +if(WITH_LEGACY_DEPSGRAPH) + add_definitions(-DWITH_LEGACY_DEPSGRAPH) +endif() + blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 47bba5f5537..ec2cf90a32a 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -58,6 +58,7 @@ incs = [ '../blenlib', '../blenloader', '../bmesh', + '../depsgraph', '../gpu', '../ikplugin', '../imbuf', @@ -66,6 +67,7 @@ incs = [ '../modifiers', '../nodes', '../physics', + '../pointcache', '../render/extern/include', '../windowmanager', env['BF_ZLIB_INC'], @@ -175,6 +177,9 @@ if env['WITH_BF_BINRELOC']: incs += ' #extern/binreloc/include' defs.append('WITH_BINRELOC') +if env['WITH_BF_LEGACY_DEPSGRAPH']: + defs.append('WITH_LEGACY_DEPSGRAPH') + if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') ) else: diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index dd129228dd8..d850dd3ee26 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -295,11 +295,11 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges, dm->dirty = 0; /* don't use CustomData_reset(...); because we dont want to touch customdata */ - fill_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1); - fill_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1); + copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1); } void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type, @@ -931,7 +931,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, ModifierData *md, int build_shapekey_layers) { Mesh *me = ob->data; - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); DerivedMesh *dm; KeyBlock *kb; @@ -1011,8 +1011,9 @@ static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *fr ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth); KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob), clmd->sim_parms->shapekey_rest); - if (kb->data) + if (kb && kb->data) { return kb->data; + } } return NULL; @@ -1131,7 +1132,7 @@ typedef struct DMWeightColorInfo { } DMWeightColorInfo; -static int dm_drawflag_calc(ToolSettings *ts) +static int dm_drawflag_calc(const ToolSettings *ts) { return ((ts->multipaint ? CALC_WP_MULTIPAINT : /* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL*/ @@ -1275,7 +1276,7 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d else { weightpaint_color(col, dm_wcinfo, 0.0f); } - fill_vn_i((int *)r_wtcol_v, numVerts, *((int *)col)); + copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col)); } } @@ -1368,7 +1369,7 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag, } } -static void DM_update_statvis_color(Scene *scene, Object *ob, DerivedMesh *dm) +static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm) { BMEditMesh *em = BKE_editmesh_from_object(ob); @@ -1585,7 +1586,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos /* Apply all leading deforming modifiers */ for (; md; md = md->next, curr = curr->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -1639,7 +1640,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos clothorcodm = NULL; for (; md; md = md->next, curr = curr->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -1938,7 +1939,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle); } - { + if (sculpt_dyntopo == false) { DM_ensure_tessface(finaldm); /* without this, drawing ngon tri's faces will show ugly tessellated face @@ -2000,7 +2001,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3] bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; if (!modifier_isEnabled(scene, md, required_mode)) return 0; @@ -2059,7 +2060,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D curr = datamasks; for (i = 0; md; i++, md = md->next, curr = curr->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -2291,13 +2292,8 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask, - int build_shapekey_layers) + int build_shapekey_layers, int needMapping) { - Object *obact = scene->basact ? scene->basact->object : NULL; - bool editing = BKE_paint_select_face_test(ob); - /* weight paint and face select need original indices because of selection buffer drawing */ - int needMapping = (ob == obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT))); - BLI_assert(ob->type == OB_MESH); BKE_object_free_derived_caches(ob); @@ -2312,6 +2308,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask, ob->derivedFinal->needsFree = 0; ob->derivedDeform->needsFree = 0; ob->lastDataMask = dataMask; + ob->lastNeedMapping = needMapping; if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) { /* create PBVH immediately (would be created on the fly too, @@ -2340,14 +2337,23 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS)); } -static CustomDataMask object_get_datamask(Scene *scene, Object *ob) +static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, int *r_needmapping) { Object *actob = scene->basact ? scene->basact->object : NULL; CustomDataMask mask = ob->customdata_mask; + bool editing = BKE_paint_select_face_test(ob); + + if (r_needmapping) + *r_needmapping = 0; if (ob == actob) { + + /* weight paint and face select need original indices because of selection buffer drawing */ + if (r_needmapping) + *r_needmapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT))); + /* check if we need tfaces & mcols due to face select or texture paint */ - if (BKE_paint_select_face_test(ob) || (ob->mode & OB_MODE_TEXTURE_PAINT)) { + if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) { mask |= CD_MASK_MTFACE | CD_MASK_MCOL; } @@ -2370,13 +2376,14 @@ static CustomDataMask object_get_datamask(Scene *scene, Object *ob) void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em, CustomDataMask dataMask, int build_shapekey_layers) { - dataMask |= object_get_datamask(scene, ob); + int needMapping; + dataMask |= object_get_datamask(scene, ob, &needMapping); if (em) { editbmesh_build_data(scene, ob, em, dataMask); } else { - mesh_build_data(scene, ob, dataMask, build_shapekey_layers); + mesh_build_data(scene, ob, dataMask, build_shapekey_layers, needMapping); } } @@ -2387,10 +2394,11 @@ DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dat /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, ob); + int needMapping; + dataMask |= object_get_datamask(scene, ob, &needMapping); - if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask) - mesh_build_data(scene, ob, dataMask, 0); + if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask || (needMapping != ob->lastNeedMapping)) + mesh_build_data(scene, ob, dataMask, 0, needMapping); if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); } return ob->derivedFinal; @@ -2401,10 +2409,12 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, ob); + int needmapping; - if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask) - mesh_build_data(scene, ob, dataMask, 0); + dataMask |= object_get_datamask(scene, ob, &needmapping); + + if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask || (needmapping != ob->lastNeedMapping)) + mesh_build_data(scene, ob, dataMask, 0, needmapping); return ob->derivedDeform; } @@ -2493,7 +2503,7 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, obedit); + dataMask |= object_get_datamask(scene, obedit, NULL); if (!em->derivedCage || (em->lastDataMask & dataMask) != dataMask) @@ -2511,7 +2521,7 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, obedit); + dataMask |= object_get_datamask(scene, obedit, NULL); if (!em->derivedCage || (em->lastDataMask & dataMask) != dataMask) @@ -3235,7 +3245,8 @@ static void navmesh_drawColored(DerivedMesh *dm) #endif glDisable(GL_LIGHTING); - /* if (GPU_buffer_legacy(dm) ) */ { /* TODO - VBO draw code, not high priority - campbell */ + /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */ + { DEBUG_VBO("Using legacy code. drawNavMeshColored\n"); //glShadeModel(GL_SMOOTH); glBegin(glmode = GL_QUADS); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index f9556bf39ab..7e09ad355a7 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -54,6 +54,7 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_deform.h" +#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -929,6 +930,12 @@ void BKE_pose_update_constraint_flags(bPose *pose) pchan->constflag |= PCHAN_HAS_CONST; } } + pose->flag &= ~POSE_CONSTRAINTS_NEED_UPDATE_FLAGS; +} + +void BKE_pose_tag_update_constraint_flags(bPose *pose) +{ + pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS; } /* Clears all BONE_UNKEYED flags for every pose channel in every pose @@ -1311,6 +1318,16 @@ bool BKE_pose_copy_result(bPose *to, bPose *from) return true; } +/* Tag pose for recalc. Also tag all related data to be recalc. */ +void BKE_pose_tag_recalc(Main *bmain, bPose *pose) +{ + pose->flag |= POSE_RECALC; + /* Depsgraph components depends on actual pose state, + * if pose was changed depsgraph is to be updated as well. + */ + DAG_relations_tag_update(bmain); +} + /* For the calculation of the effects of an Action at the given frame on an object * This is currently only used for the Action Constraint */ diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c index 28667d458b8..811461b84c1 100644 --- a/source/blender/blenkernel/intern/addon.c +++ b/source/blender/blenkernel/intern/addon.c @@ -62,12 +62,12 @@ bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet) void BKE_addon_pref_type_add(bAddonPrefType *apt) { - BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt); + BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt); } -void BKE_addon_pref_type_remove(bAddonPrefType *apt) +void BKE_addon_pref_type_remove(const bAddonPrefType *apt) { - BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, MEM_freeN); + BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN); } void BKE_addon_pref_type_init(void) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index effe32a8079..d5a8b8f857c 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -134,7 +134,7 @@ AnimData *BKE_animdata_from_id(ID *id) * the AnimData pointer is stored immediately after the given ID-block in the struct, * as per IdAdtTemplate. Also note that */ -AnimData *BKE_id_add_animdata(ID *id) +AnimData *BKE_animdata_add_id(ID *id) { /* Only some ID-blocks have this info for now, so we cast the * types that do to be of type IdAdtTemplate, and add the AnimData @@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) /* Freeing -------------------------------------------- */ /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ -void BKE_free_animdata(ID *id) +void BKE_animdata_free(ID *id) { /* Only some ID-blocks have this info for now, so we cast the * types that do to be of type IdAdtTemplate @@ -253,7 +253,7 @@ void BKE_free_animdata(ID *id) /* Copying -------------------------------------------- */ /* Make a copy of the given AnimData - to be used when copying datablocks */ -AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action) +AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) { AnimData *dadt; @@ -285,25 +285,25 @@ AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action) return dadt; } -bool BKE_copy_animdata_id(ID *id_to, ID *id_from, const bool do_action) +bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) { AnimData *adt; if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) return false; - BKE_free_animdata(id_to); + BKE_animdata_free(id_to); adt = BKE_animdata_from_id(id_from); if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id_to; - iat->adt = BKE_copy_animdata(adt, do_action); + iat->adt = BKE_animdata_copy(adt, do_action); } return true; } -void BKE_copy_animdata_id_action(ID *id) +void BKE_animdata_copy_id_action(ID *id) { AnimData *adt = BKE_animdata_from_id(id); if (adt) { @@ -426,7 +426,7 @@ void BKE_animdata_make_local(AnimData *adt) /* When duplicating data (i.e. objects), drivers referring to the original data will * get updated to point to the duplicated data (if drivers belong to the new data) */ -void BKE_relink_animdata(AnimData *adt) +void BKE_animdata_relink(AnimData *adt) { /* sanity check */ if (adt == NULL) @@ -571,7 +571,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths /* get animdata from src, and create for destination (if needed) */ srcAdt = BKE_animdata_from_id(srcID); - dstAdt = BKE_id_add_animdata(dstID); + dstAdt = BKE_animdata_add_id(dstID); if (ELEM(NULL, srcAdt, dstAdt)) { if (G.debug & G_DEBUG) @@ -1167,7 +1167,7 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u * i.e. pose.bones["Bone"] */ /* TODO: use BKE_animdata_main_cb for looping over all data */ -void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName) +void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName) { Main *mainptr = G.main; ID *id; @@ -1496,8 +1496,11 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind /* get property to write to */ if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) { - /* set value - only for animatable numerical values */ - if (RNA_property_animateable(&new_ptr, prop)) { + /* set value for animatable numerical values only + * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated + * without an ID provided, which causes the animateable test to fail! + */ + if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) { int array_len = RNA_property_array_length(&new_ptr, prop); bool written = false; @@ -1617,7 +1620,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind } /* Simple replacement based data-setting of the FCurve using RNA */ -static bool animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu) +bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu) { char *path = NULL; bool free_path = false; @@ -1652,7 +1655,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { calculate_fcurve(fcu, ctime); - animsys_execute_fcurve(ptr, remap, fcu); + BKE_animsys_execute_fcurve(ptr, remap, fcu); } } } @@ -1682,7 +1685,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 */ calculate_fcurve(fcu, ctime); - ok = animsys_execute_fcurve(ptr, NULL, fcu); + ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu); /* clear recalc flag */ driver->flag &= ~DRIVER_FLAG_RECALC; @@ -1751,7 +1754,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) { calculate_fcurve(fcu, ctime); - animsys_execute_fcurve(ptr, remap, fcu); + BKE_animsys_execute_fcurve(ptr, remap, fcu); } } } @@ -1797,12 +1800,6 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe) /* evaluate the evaluation time and influence for the strip, storing the results in the strip */ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime) { - /* firstly, analytically generate values for influence and time (if applicable) */ - if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) - strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); - if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) - strip->influence = nlastrip_get_influence(strip, ctime); - /* now strip's evaluate F-Curves for these settings (if applicable) */ if (strip->fcurves.first) { PointerRNA strip_ptr; @@ -1813,6 +1810,15 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime) /* execute these settings as per normal */ animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime); } + + /* analytically generate values for influence and time (if applicable) + * - we do this after the F-Curves have been evaluated to override the effects of those + * in case the override has been turned off. + */ + if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) + strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); + if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) + strip->influence = nlastrip_get_influence(strip, ctime); /* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped * to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip @@ -2840,3 +2846,62 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) } /* ***************************************** */ + +/* ************** */ +/* Evaluation API */ + +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + +void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id) +{ + AnimData *adt = BKE_animdata_from_id(id); + Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, + * which should get handled as part of the graph instead... + */ + DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime); + BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM); +} + +void BKE_animsys_eval_driver(EvaluationContext *eval_ctx, + ID *id, + FCurve *fcu) +{ + /* TODO(sergey): De-duplicate with BKE animsys. */ + ChannelDriver *driver = fcu->driver; + PointerRNA id_ptr; + bool ok = false; + + DEBUG_PRINT("%s on %s (%s[%d])\n", + __func__, + id->name, + fcu->rna_path, + fcu->array_index); + + RNA_id_pointer_create(id, &id_ptr); + + /* check if this driver's curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { + /* check if driver itself is tagged for recalculation */ + /* XXX driver recalc flag is not set yet by depsgraph! */ + if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) { + /* evaluate this using values set already in other places + * 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 */ + //printf("\told val = %f\n", fcu->curval); + calculate_fcurve(fcu, eval_ctx->ctime); + ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu); + //printf("\tnew val = %f\n", fcu->curval); + + /* clear recalc flag */ + driver->flag &= ~DRIVER_FLAG_RECALC; + + /* set error-flag if evaluation failed */ + if (ok == 0) { + printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index); + driver->flag |= DRIVER_FLAG_INVALID; + } + } + } +} + +#undef DEBUG_PRINT diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 60e81003c40..b1b32e75f59 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -501,54 +501,6 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con /* Preset paths */ /** - * Tries appending each of the semicolon-separated extensions in the PATHEXT - * environment variable (Windows-only) onto *name in turn until such a file is found. - * Returns success/failure. - */ -static int add_win32_extension(char *name) -{ - int retval = 0; - int type; - - type = BLI_exists(name); - if ((type == 0) || S_ISDIR(type)) { -#ifdef _WIN32 - char filename[FILE_MAX]; - char ext[FILE_MAX]; - const char *extensions = getenv("PATHEXT"); - if (extensions) { - char *temp; - do { - strcpy(filename, name); - temp = strstr(extensions, ";"); - if (temp) { - strncpy(ext, extensions, temp - extensions); - ext[temp - extensions] = 0; - extensions = temp + 1; - strcat(filename, ext); - } - else { - strcat(filename, extensions); - } - - type = BLI_exists(filename); - if (type && (!S_ISDIR(type))) { - retval = 1; - strcpy(name, filename); - break; - } - } while (temp); - } -#endif - } - else { - retval = 1; - } - - return (retval); -} - -/** * Checks if name is a fully qualified filename to an executable. * If not it searches $PATH for the file. On Windows it also * adds the correct extension (.com .exe etc) from @@ -562,39 +514,34 @@ static int add_win32_extension(char *name) */ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name) { - char filename[FILE_MAX]; - const char *path = NULL, *temp; - -#ifdef _WIN32 - const char *separator = ";"; -#else - const char *separator = ":"; -#endif - - #ifdef WITH_BINRELOC /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */ - path = br_find_exe(NULL); - if (path) { - BLI_strncpy(fullname, path, maxlen); - free((void *)path); - return; + { + const char *path = NULL; + path = br_find_exe(NULL); + if (path) { + BLI_strncpy(fullname, path, maxlen); + free((void *)path); + return; + } } #endif #ifdef _WIN32 - wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); - if (GetModuleFileNameW(0, fullname_16, maxlen)) { - conv_utf_16_to_8(fullname_16, fullname, maxlen); - if (!BLI_exists(fullname)) { - printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); - MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); + { + wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); + if (GetModuleFileNameW(0, fullname_16, maxlen)) { + conv_utf_16_to_8(fullname_16, fullname, maxlen); + if (!BLI_exists(fullname)) { + printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); + MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); + } + MEM_freeN(fullname_16); + return; } + MEM_freeN(fullname_16); - return; } - - MEM_freeN(fullname_16); #endif /* unix and non linux */ @@ -611,34 +558,19 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name else BLI_join_dirfile(fullname, maxlen, wdir, name); - add_win32_extension(fullname); /* XXX, doesnt respect length */ +#ifdef _WIN32 + BLI_path_program_extensions_add_win32(fullname, maxlen); +#endif } else if (BLI_last_slash(name)) { // full path BLI_strncpy(fullname, name, maxlen); - add_win32_extension(fullname); +#ifdef _WIN32 + BLI_path_program_extensions_add_win32(fullname, maxlen); +#endif } else { - // search for binary in $PATH - path = getenv("PATH"); - if (path) { - do { - temp = strstr(path, separator); - if (temp) { - strncpy(filename, path, temp - path); - filename[temp - path] = 0; - path = temp + 1; - } - else { - strncpy(filename, path, sizeof(filename)); - } - BLI_path_append(fullname, maxlen, name); - if (add_win32_extension(filename)) { - BLI_strncpy(fullname, filename, maxlen); - break; - } - } while (temp); - } + BLI_path_program_search(fullname, maxlen, name); } #if defined(DEBUG) if (!STREQ(name, fullname)) { @@ -670,6 +602,58 @@ const char *BKE_appdir_program_dir(void) return bprogdir; } +bool BKE_appdir_program_python_search( + char *fullpath, const size_t fullpath_len, + const int version_major, const int version_minor) +{ + const char *basename = "python"; + char python_ver[16]; + /* check both possible names */ + const char *python_names[] = {basename, python_ver}; + int i; + + bool is_found = false; + + BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor); + + { + const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin"); + if (python_bin_dir) { + + for (i = 0; i < ARRAY_SIZE(python_names); i++) { + BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]); + + if ( +#ifdef _WIN32 + BLI_path_program_extensions_add_win32(fullpath, fullpath_len) +#else + BLI_exists(fullpath) +#endif + ) + { + is_found = true; + break; + } + } + } + } + + if (is_found == false) { + for (i = 0; i < ARRAY_SIZE(python_names); i++) { + if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) { + is_found = true; + break; + } + } + } + + if (is_found == false) { + *fullpath = '\0'; + } + + return is_found; +} + /** * Gets the temp directory when blender first runs. * If the default path is not found, use try $TEMP diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 6b67a4e5763..27d3d1c50fb 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -127,7 +127,7 @@ void BKE_armature_free(bArmature *arm) /* free animation data */ if (arm->adt) { - BKE_free_animdata(&arm->id); + BKE_animdata_free(&arm->id); arm->adt = NULL; } } @@ -1700,7 +1700,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected /* constraints - set target ob pointer to own object */ for (con = pchanw.constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1825,9 +1825,12 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */ +#ifdef WITH_LEGACY_DEPSGRAPH /* the sorting */ + /* Sorting for new dependnecy graph is done on the scene graph level. */ if (counter > 1) DAG_pose_sort(ob); +#endif ob->pose->flag &= ~POSE_RECALC; ob->pose->flag |= POSE_WAS_REBUILT; @@ -1835,494 +1838,6 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) BKE_pose_channels_hash_make(ob->pose); } - -/* ********************** SPLINE IK SOLVER ******************* */ - -/* Temporary evaluation tree data used for Spline IK */ -typedef struct tSplineIK_Tree { - struct tSplineIK_Tree *next, *prev; - - int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */ - - bool free_points; /* free the point positions array */ - short chainlen; /* number of bones in the chain */ - - float *points; /* parametric positions for the joints along the curve */ - bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */ - - bPoseChannel *root; /* bone that is the root node of the chain */ - - bConstraint *con; /* constraint for this chain */ - bSplineIKConstraint *ikData; /* constraint settings for this chain */ -} tSplineIK_Tree; - -/* ----------- */ - -/* Tag the bones in the chain formed by the given bone for IK */ -static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip) -{ - bPoseChannel *pchan, *pchanRoot = NULL; - bPoseChannel *pchanChain[255]; - bConstraint *con = NULL; - bSplineIKConstraint *ikData = NULL; - float boneLengths[255], *jointPoints; - float totLength = 0.0f; - bool free_joints = 0; - int segcount = 0; - - /* find the SplineIK constraint */ - for (con = pchan_tip->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_SPLINEIK) { - ikData = con->data; - - /* target can only be curve */ - if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE)) - continue; - /* skip if disabled */ - if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))) - continue; - - /* otherwise, constraint is ok... */ - break; - } - } - if (con == NULL) - return; - - /* make sure that the constraint targets are ok - * - this is a workaround for a depsgraph bug... - */ - if (ikData->tar) { - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, - * currently for paths to work it needs to go through the bevlist/displist system (ton) - */ - - /* only happens on reload file, but violates depsgraph still... fix! */ - if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { - BKE_displist_make_curveTypes(scene, ikData->tar, 0); - - /* path building may fail in EditMode after removing verts [#33268]*/ - if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { - /* BLI_assert(cu->path != NULL); */ - return; - } - } - } - - /* find the root bone and the chain of bones from the root to the tip - * NOTE: this assumes that the bones are connected, but that may not be true... */ - for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) { - /* store this segment in the chain */ - pchanChain[segcount] = pchan; - - /* if performing rebinding, calculate the length of the bone */ - boneLengths[segcount] = pchan->bone->length; - totLength += boneLengths[segcount]; - } - - if (segcount == 0) - return; - else - pchanRoot = pchanChain[segcount - 1]; - - /* perform binding step if required */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) { - float segmentLen = (1.0f / (float)segcount); - int i; - - /* setup new empty array for the points list */ - if (ikData->points) - MEM_freeN(ikData->points); - ikData->numpoints = ikData->chainlen + 1; - ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding"); - - /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */ - ikData->points[0] = 1.0f; - - /* perform binding of the joints to parametric positions along the curve based - * proportion of the total length that each bone occupies - */ - for (i = 0; i < segcount; i++) { - /* 'head' joints, traveling towards the root of the chain - * - 2 methods; the one chosen depends on whether we've got usable lengths - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) { - /* 1) equi-spaced joints */ - ikData->points[i + 1] = ikData->points[i] - segmentLen; - } - else { - /* 2) to find this point on the curve, we take a step from the previous joint - * a distance given by the proportion that this bone takes - */ - ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength); - } - } - - /* spline has now been bound */ - ikData->flag |= CONSTRAINT_SPLINEIK_BOUND; - } - - /* disallow negative values (happens with float precision) */ - CLAMP_MIN(ikData->points[segcount], 0.0f); - - /* apply corrections for sensitivity to scaling on a copy of the bind points, - * since it's easier to determine the positions of all the joints beforehand this way - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) { - float splineLen, maxScale; - int i; - - /* make a copy of the points array, that we'll store in the tree - * - although we could just multiply the points on the fly, this approach means that - * we can introduce per-segment stretchiness later if it is necessary - */ - jointPoints = MEM_dupallocN(ikData->points); - free_joints = 1; - - /* get the current length of the curve */ - /* NOTE: this is assumed to be correct even after the curve was resized */ - splineLen = ikData->tar->curve_cache->path->totdist; - - /* calculate the scale factor to multiply all the path values by so that the - * bone chain retains its current length, such that - * maxScale * splineLen = totLength - */ - maxScale = totLength / splineLen; - - /* apply scaling correction to all of the temporary points */ - /* TODO: this is really not adequate enough on really short chains */ - for (i = 0; i < segcount; i++) - jointPoints[i] *= maxScale; - } - else { - /* just use the existing points array */ - jointPoints = ikData->points; - free_joints = 0; - } - - /* make a new Spline-IK chain, and store it in the IK chains */ - /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */ - { - /* make new tree */ - tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); - tree->type = CONSTRAINT_TYPE_SPLINEIK; - - tree->chainlen = segcount; - - /* copy over the array of links to bones in the chain (from tip to root) */ - tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain"); - memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount); - - /* store reference to joint position array */ - tree->points = jointPoints; - tree->free_points = free_joints; - - /* store references to different parts of the chain */ - tree->root = pchanRoot; - tree->con = con; - tree->ikData = ikData; - - /* AND! link the tree to the root */ - BLI_addtail(&pchanRoot->siktree, tree); - } - - /* mark root channel having an IK tree */ - pchanRoot->flag |= POSE_IKSPLINE; -} - -/* Tag which bones are members of Spline IK chains */ -static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime)) -{ - bPoseChannel *pchan; - - /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->constflag & PCHAN_HAS_SPLINEIK) - splineik_init_tree_from_pchan(scene, ob, pchan); - } -} - -/* ----------- */ - -/* Evaluate spline IK for a given bone */ -static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, - int index, float ctime) -{ - bSplineIKConstraint *ikData = tree->ikData; - float poseHead[3], poseTail[3], poseMat[4][4]; - float splineVec[3], scaleFac, radius = 1.0f; - - /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); - - copy_v3_v3(poseHead, pchan->pose_head); - copy_v3_v3(poseTail, pchan->pose_tail); - - /* step 1: determine the positions for the endpoints of the bone */ - { - float vec[4], dir[3], rad; - float tailBlendFac = 1.0f; - - /* determine if the bone should still be affected by SplineIK */ - if (tree->points[index + 1] >= 1.0f) { - /* spline doesn't affect the bone anymore, so done... */ - pchan->flag |= POSE_DONE; - return; - } - else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { - /* blending factor depends on the amount of the bone still left on the chain */ - tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); - } - - /* tail endpoint */ - if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { - /* apply curve's object-mode transforms to the position - * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) - mul_m4_v3(ikData->tar->obmat, vec); - - /* convert the position to pose-space, then store it */ - mul_m4_v3(ob->imat, vec); - interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); - - /* set the new radius */ - radius = rad; - } - - /* head endpoint */ - if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { - /* apply curve's object-mode transforms to the position - * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) - mul_m4_v3(ikData->tar->obmat, vec); - - /* store the position, and convert it to pose space */ - mul_m4_v3(ob->imat, vec); - copy_v3_v3(poseHead, vec); - - /* set the new radius (it should be the average value) */ - radius = (radius + rad) / 2; - } - } - - /* step 2: determine the implied transform from these endpoints - * - splineVec: the vector direction that the spline applies on the bone - * - scaleFac: the factor that the bone length is scaled by to get the desired amount - */ - sub_v3_v3v3(splineVec, poseTail, poseHead); - scaleFac = len_v3(splineVec) / pchan->bone->length; - - /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis - * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) - */ - { - float dmat[3][3], rmat[3][3], tmat[3][3]; - float raxis[3], rangle; - - /* compute the raw rotation matrix from the bone's current matrix by extracting only the - * orientation-relevant axes, and normalizing them - */ - copy_v3_v3(rmat[0], pchan->pose_mat[0]); - copy_v3_v3(rmat[1], pchan->pose_mat[1]); - copy_v3_v3(rmat[2], pchan->pose_mat[2]); - normalize_m3(rmat); - - /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ - normalize_v3(splineVec); - - /* calculate smallest axis-angle rotation necessary for getting from the - * current orientation of the bone, to the spline-imposed direction - */ - cross_v3_v3v3(raxis, rmat[1], splineVec); - - rangle = dot_v3v3(rmat[1], splineVec); - CLAMP(rangle, -1.0f, 1.0f); - rangle = acosf(rangle); - - /* multiply the magnitude of the angle by the influence of the constraint to - * control the influence of the SplineIK effect - */ - rangle *= tree->con->enforce; - - /* construct rotation matrix from the axis-angle rotation found above - * - this call takes care to make sure that the axis provided is a unit vector first - */ - axis_angle_to_mat3(dmat, raxis, rangle); - - /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, - * while still maintaining roll control from the existing bone animation - */ - mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ - normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ - copy_m4_m3(poseMat, tmat); - } - - /* step 4: set the scaling factors for the axes */ - { - /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ - mul_v3_fl(poseMat[1], scaleFac); - - /* set the scaling factors of the x and z axes from... */ - switch (ikData->xzScaleMode) { - case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: - { - /* original scales get used */ - float scale; - - /* x-axis scale */ - scale = len_v3(pchan->pose_mat[0]); - mul_v3_fl(poseMat[0], scale); - /* z-axis scale */ - scale = len_v3(pchan->pose_mat[2]); - mul_v3_fl(poseMat[2], scale); - break; - } - case CONSTRAINT_SPLINEIK_XZS_INVERSE: - { - /* old 'volume preservation' method using the inverse scale */ - float scale; - - /* calculate volume preservation factor which is - * basically the inverse of the y-scaling factor - */ - if (fabsf(scaleFac) != 0.0f) { - scale = 1.0f / fabsf(scaleFac); - - /* we need to clamp this within sensible values */ - /* NOTE: these should be fine for now, but should get sanitised in future */ - CLAMP(scale, 0.0001f, 100000.0f); - } - else - scale = 1.0f; - - /* apply the scaling */ - mul_v3_fl(poseMat[0], scale); - mul_v3_fl(poseMat[2], scale); - break; - } - case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: - { - /* improved volume preservation based on the Stretch To constraint */ - float final_scale; - - /* as the basis for volume preservation, we use the inverse scale factor... */ - if (fabsf(scaleFac) != 0.0f) { - /* NOTE: The method here is taken wholesale from the Stretch To constraint */ - float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); - - if (bulge > 1.0f) { - if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { - float bulge_max = max_ff(ikData->bulge_max, 1.0f); - float hard = min_ff(bulge, bulge_max); - - float range = bulge_max - 1.0f; - float scale = (range > 0.0f) ? 1.0f / range : 0.0f; - float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; - - bulge = interpf(soft, hard, ikData->bulge_smooth); - } - } - if (bulge < 1.0f) { - if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { - float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); - float hard = max_ff(bulge, bulge_min); - - float range = 1.0f - bulge_min; - float scale = (range > 0.0f) ? 1.0f / range : 0.0f; - float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; - - bulge = interpf(soft, hard, ikData->bulge_smooth); - } - } - - /* compute scale factor for xz axes from this value */ - final_scale = sqrt(bulge); - } - else { - /* no scaling, so scale factor is simple */ - final_scale = 1.0f; - } - - /* apply the scaling (assuming normalised scale) */ - mul_v3_fl(poseMat[0], final_scale); - mul_v3_fl(poseMat[2], final_scale); - break; - } - } - - /* finally, multiply the x and z scaling by the radius of the curve too, - * to allow automatic scales to get tweaked still - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { - mul_v3_fl(poseMat[0], radius); - mul_v3_fl(poseMat[2], radius); - } - } - - /* step 5: set the location of the bone in the matrix */ - if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { - /* when the 'no-root' option is affected, the chain can retain - * the shape but be moved elsewhere - */ - copy_v3_v3(poseHead, pchan->pose_head); - } - else if (tree->con->enforce < 1.0f) { - /* when the influence is too low - * - blend the positions for the 'root' bone - * - stick to the parent for any other - */ - if (pchan->parent) { - copy_v3_v3(poseHead, pchan->pose_head); - } - else { - /* FIXME: this introduces popping artifacts when we reach 0.0 */ - interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); - } - } - copy_v3_v3(poseMat[3], poseHead); - - /* finally, store the new transform */ - copy_m4_m4(pchan->pose_mat, poseMat); - copy_v3_v3(pchan->pose_head, poseHead); - - /* recalculate tail, as it's now outdated after the head gets adjusted above! */ - BKE_pose_where_is_bone_tail(pchan); - - /* done! */ - pchan->flag |= POSE_DONE; -} - -/* Evaluate the chain starting from the nominated bone */ -static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) -{ - tSplineIK_Tree *tree; - - /* for each pose-tree, execute it if it is spline, otherwise just free it */ - while ((tree = pchan_root->siktree.first) != NULL) { - int i; - - /* walk over each bone in the chain, calculating the effects of spline IK - * - the chain is traversed in the opposite order to storage order (i.e. parent to children) - * so that dependencies are correct - */ - for (i = tree->chainlen - 1; i >= 0; i--) { - bPoseChannel *pchan = tree->chain[i]; - splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime); - } - - /* free the tree info specific to SplineIK trees now */ - if (tree->chain) - MEM_freeN(tree->chain); - if (tree->free_points) - MEM_freeN(tree->points); - - /* free this tree */ - BLI_freelinkN(&pchan_root->siktree, tree); - } -} - /* ********************** THE POSE SOLVER ******************* */ /* loc/rot/size to given mat4 */ @@ -2623,7 +2138,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob) * - this is not integrated as an IK plugin, since it should be able * to function in conjunction with standard IK */ - splineik_init_tree(scene, ob, ctime); + BKE_pose_splineik_init_tree(scene, ob, ctime); /* 3. the main loop, channels are already hierarchical sorted from root to children */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -2633,7 +2148,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob) } /* 4b. if we find a Spline IK root, we handle it separated too */ else if (pchan->flag & POSE_IKSPLINE) { - splineik_execute_tree(scene, ob, pchan, ctime); + BKE_splineik_execute_tree(scene, ob, pchan, ctime); } /* 5. otherwise just call the normal solver */ else if (!(pchan->flag & POSE_DONE)) { @@ -2703,3 +2218,46 @@ BoundBox *BKE_armature_boundbox_get(Object *ob) return ob->bb; } + +/************** Graph evaluation ********************/ + +bPoseChannel *BKE_armature_ik_solver_find_root( + bPoseChannel *pchan, + bKinematicConstraint *data) +{ + bPoseChannel *rootchan = pchan; + if (!(data->flag & CONSTRAINT_IK_TIP)) { + /* Exclude tip from chain. */ + rootchan = rootchan->parent; + } + if (rootchan != NULL) { + int segcount = 0; + while (rootchan->parent) { + /* Continue up chain, until we reach target number of items. */ + segcount++; + if (segcount == data->rootbone) { + break; + } + rootchan = rootchan->parent; + } + } + return rootchan; +} + +bPoseChannel *BKE_armature_splineik_solver_find_root( + bPoseChannel *pchan, + bSplineIKConstraint *data) +{ + bPoseChannel *rootchan = pchan; + int segcount = 0; + BLI_assert(rootchan != NULL); + while (rootchan->parent) { + /* Continue up chain, until we reach target number of items. */ + segcount++; + if (segcount == data->chainlen) { + break; + } + rootchan = rootchan->parent; + } + return rootchan; +} diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c new file mode 100644 index 00000000000..ceda9f056bb --- /dev/null +++ b/source/blender/blenkernel/intern/armature_update.c @@ -0,0 +1,697 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2015 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + * + * Defines and code for core node types + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_action.h" +#include "BKE_anim.h" +#include "BKE_armature.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_displist.h" +#include "BKE_fcurve.h" +#include "BKE_scene.h" + +#include "BIK_api.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "DEG_depsgraph.h" + +#ifdef WITH_LEGACY_DEPSGRAPH +# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf +#else +# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf +#endif + +/* ********************** SPLINE IK SOLVER ******************* */ + +/* Temporary evaluation tree data used for Spline IK */ +typedef struct tSplineIK_Tree { + struct tSplineIK_Tree *next, *prev; + + int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */ + + bool free_points; /* free the point positions array */ + short chainlen; /* number of bones in the chain */ + + float *points; /* parametric positions for the joints along the curve */ + bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */ + + bPoseChannel *root; /* bone that is the root node of the chain */ + + bConstraint *con; /* constraint for this chain */ + bSplineIKConstraint *ikData; /* constraint settings for this chain */ +} tSplineIK_Tree; + +/* ----------- */ + +/* Tag the bones in the chain formed by the given bone for IK */ +static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip) +{ + bPoseChannel *pchan, *pchanRoot = NULL; + bPoseChannel *pchanChain[255]; + bConstraint *con = NULL; + bSplineIKConstraint *ikData = NULL; + float boneLengths[255], *jointPoints; + float totLength = 0.0f; + bool free_joints = 0; + int segcount = 0; + + /* find the SplineIK constraint */ + for (con = pchan_tip->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SPLINEIK) { + ikData = con->data; + + /* target can only be curve */ + if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE)) + continue; + /* skip if disabled */ + if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))) + continue; + + /* otherwise, constraint is ok... */ + break; + } + } + if (con == NULL) + return; + + /* make sure that the constraint targets are ok + * - this is a workaround for a depsgraph bug... + */ + if (ikData->tar) { + /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, + * currently for paths to work it needs to go through the bevlist/displist system (ton) + */ + + /* only happens on reload file, but violates depsgraph still... fix! */ + if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { + BKE_displist_make_curveTypes(scene, ikData->tar, 0); + + /* path building may fail in EditMode after removing verts [#33268]*/ + if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { + /* BLI_assert(cu->path != NULL); */ + return; + } + } + } + + /* find the root bone and the chain of bones from the root to the tip + * NOTE: this assumes that the bones are connected, but that may not be true... */ + for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) { + /* store this segment in the chain */ + pchanChain[segcount] = pchan; + + /* if performing rebinding, calculate the length of the bone */ + boneLengths[segcount] = pchan->bone->length; + totLength += boneLengths[segcount]; + } + + if (segcount == 0) + return; + else + pchanRoot = pchanChain[segcount - 1]; + + /* perform binding step if required */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) { + float segmentLen = (1.0f / (float)segcount); + int i; + + /* setup new empty array for the points list */ + if (ikData->points) + MEM_freeN(ikData->points); + ikData->numpoints = ikData->chainlen + 1; + ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding"); + + /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */ + ikData->points[0] = 1.0f; + + /* perform binding of the joints to parametric positions along the curve based + * proportion of the total length that each bone occupies + */ + for (i = 0; i < segcount; i++) { + /* 'head' joints, traveling towards the root of the chain + * - 2 methods; the one chosen depends on whether we've got usable lengths + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) { + /* 1) equi-spaced joints */ + ikData->points[i + 1] = ikData->points[i] - segmentLen; + } + else { + /* 2) to find this point on the curve, we take a step from the previous joint + * a distance given by the proportion that this bone takes + */ + ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength); + } + } + + /* spline has now been bound */ + ikData->flag |= CONSTRAINT_SPLINEIK_BOUND; + } + + /* disallow negative values (happens with float precision) */ + CLAMP_MIN(ikData->points[segcount], 0.0f); + + /* apply corrections for sensitivity to scaling on a copy of the bind points, + * since it's easier to determine the positions of all the joints beforehand this way + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) { + float splineLen, maxScale; + int i; + + /* make a copy of the points array, that we'll store in the tree + * - although we could just multiply the points on the fly, this approach means that + * we can introduce per-segment stretchiness later if it is necessary + */ + jointPoints = MEM_dupallocN(ikData->points); + free_joints = 1; + + /* get the current length of the curve */ + /* NOTE: this is assumed to be correct even after the curve was resized */ + splineLen = ikData->tar->curve_cache->path->totdist; + + /* calculate the scale factor to multiply all the path values by so that the + * bone chain retains its current length, such that + * maxScale * splineLen = totLength + */ + maxScale = totLength / splineLen; + + /* apply scaling correction to all of the temporary points */ + /* TODO: this is really not adequate enough on really short chains */ + for (i = 0; i < segcount; i++) + jointPoints[i] *= maxScale; + } + else { + /* just use the existing points array */ + jointPoints = ikData->points; + free_joints = 0; + } + + /* make a new Spline-IK chain, and store it in the IK chains */ + /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */ + { + /* make new tree */ + tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); + tree->type = CONSTRAINT_TYPE_SPLINEIK; + + tree->chainlen = segcount; + + /* copy over the array of links to bones in the chain (from tip to root) */ + tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain"); + memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount); + + /* store reference to joint position array */ + tree->points = jointPoints; + tree->free_points = free_joints; + + /* store references to different parts of the chain */ + tree->root = pchanRoot; + tree->con = con; + tree->ikData = ikData; + + /* AND! link the tree to the root */ + BLI_addtail(&pchanRoot->siktree, tree); + } + + /* mark root channel having an IK tree */ + pchanRoot->flag |= POSE_IKSPLINE; +} + +/* Tag which bones are members of Spline IK chains */ +static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime)) +{ + bPoseChannel *pchan; + + /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */ + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->constflag & PCHAN_HAS_SPLINEIK) + splineik_init_tree_from_pchan(scene, ob, pchan); + } +} + +/* ----------- */ + +/* Evaluate spline IK for a given bone */ +static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, + int index, float ctime) +{ + bSplineIKConstraint *ikData = tree->ikData; + float poseHead[3], poseTail[3], poseMat[4][4]; + float splineVec[3], scaleFac, radius = 1.0f; + + /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + + copy_v3_v3(poseHead, pchan->pose_head); + copy_v3_v3(poseTail, pchan->pose_tail); + + /* step 1: determine the positions for the endpoints of the bone */ + { + float vec[4], dir[3], rad; + float tailBlendFac = 1.0f; + + /* determine if the bone should still be affected by SplineIK */ + if (tree->points[index + 1] >= 1.0f) { + /* spline doesn't affect the bone anymore, so done... */ + pchan->flag |= POSE_DONE; + return; + } + else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { + /* blending factor depends on the amount of the bone still left on the chain */ + tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); + } + + /* tail endpoint */ + if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { + /* apply curve's object-mode transforms to the position + * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) + mul_m4_v3(ikData->tar->obmat, vec); + + /* convert the position to pose-space, then store it */ + mul_m4_v3(ob->imat, vec); + interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); + + /* set the new radius */ + radius = rad; + } + + /* head endpoint */ + if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { + /* apply curve's object-mode transforms to the position + * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) + mul_m4_v3(ikData->tar->obmat, vec); + + /* store the position, and convert it to pose space */ + mul_m4_v3(ob->imat, vec); + copy_v3_v3(poseHead, vec); + + /* set the new radius (it should be the average value) */ + radius = (radius + rad) / 2; + } + } + + /* step 2: determine the implied transform from these endpoints + * - splineVec: the vector direction that the spline applies on the bone + * - scaleFac: the factor that the bone length is scaled by to get the desired amount + */ + sub_v3_v3v3(splineVec, poseTail, poseHead); + scaleFac = len_v3(splineVec) / pchan->bone->length; + + /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis + * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) + */ + { + float dmat[3][3], rmat[3][3], tmat[3][3]; + float raxis[3], rangle; + + /* compute the raw rotation matrix from the bone's current matrix by extracting only the + * orientation-relevant axes, and normalizing them + */ + copy_v3_v3(rmat[0], pchan->pose_mat[0]); + copy_v3_v3(rmat[1], pchan->pose_mat[1]); + copy_v3_v3(rmat[2], pchan->pose_mat[2]); + normalize_m3(rmat); + + /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ + normalize_v3(splineVec); + + /* calculate smallest axis-angle rotation necessary for getting from the + * current orientation of the bone, to the spline-imposed direction + */ + cross_v3_v3v3(raxis, rmat[1], splineVec); + + rangle = dot_v3v3(rmat[1], splineVec); + CLAMP(rangle, -1.0f, 1.0f); + rangle = acosf(rangle); + + /* multiply the magnitude of the angle by the influence of the constraint to + * control the influence of the SplineIK effect + */ + rangle *= tree->con->enforce; + + /* construct rotation matrix from the axis-angle rotation found above + * - this call takes care to make sure that the axis provided is a unit vector first + */ + axis_angle_to_mat3(dmat, raxis, rangle); + + /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, + * while still maintaining roll control from the existing bone animation + */ + mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ + normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ + copy_m4_m3(poseMat, tmat); + } + + /* step 4: set the scaling factors for the axes */ + { + /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ + mul_v3_fl(poseMat[1], scaleFac); + + /* set the scaling factors of the x and z axes from... */ + switch (ikData->xzScaleMode) { + case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: + { + /* original scales get used */ + float scale; + + /* x-axis scale */ + scale = len_v3(pchan->pose_mat[0]); + mul_v3_fl(poseMat[0], scale); + /* z-axis scale */ + scale = len_v3(pchan->pose_mat[2]); + mul_v3_fl(poseMat[2], scale); + break; + } + case CONSTRAINT_SPLINEIK_XZS_INVERSE: + { + /* old 'volume preservation' method using the inverse scale */ + float scale; + + /* calculate volume preservation factor which is + * basically the inverse of the y-scaling factor + */ + if (fabsf(scaleFac) != 0.0f) { + scale = 1.0f / fabsf(scaleFac); + + /* we need to clamp this within sensible values */ + /* NOTE: these should be fine for now, but should get sanitised in future */ + CLAMP(scale, 0.0001f, 100000.0f); + } + else + scale = 1.0f; + + /* apply the scaling */ + mul_v3_fl(poseMat[0], scale); + mul_v3_fl(poseMat[2], scale); + break; + } + case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: + { + /* improved volume preservation based on the Stretch To constraint */ + float final_scale; + + /* as the basis for volume preservation, we use the inverse scale factor... */ + if (fabsf(scaleFac) != 0.0f) { + /* NOTE: The method here is taken wholesale from the Stretch To constraint */ + float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); + + if (bulge > 1.0f) { + if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { + float bulge_max = max_ff(ikData->bulge_max, 1.0f); + float hard = min_ff(bulge, bulge_max); + + float range = bulge_max - 1.0f; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + if (bulge < 1.0f) { + if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { + float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); + float hard = max_ff(bulge, bulge_min); + + float range = 1.0f - bulge_min; + float scale = (range > 0.0f) ? 1.0f / range : 0.0f; + float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; + + bulge = interpf(soft, hard, ikData->bulge_smooth); + } + } + + /* compute scale factor for xz axes from this value */ + final_scale = sqrtf(bulge); + } + else { + /* no scaling, so scale factor is simple */ + final_scale = 1.0f; + } + + /* apply the scaling (assuming normalised scale) */ + mul_v3_fl(poseMat[0], final_scale); + mul_v3_fl(poseMat[2], final_scale); + break; + } + } + + /* finally, multiply the x and z scaling by the radius of the curve too, + * to allow automatic scales to get tweaked still + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { + mul_v3_fl(poseMat[0], radius); + mul_v3_fl(poseMat[2], radius); + } + } + + /* step 5: set the location of the bone in the matrix */ + if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { + /* when the 'no-root' option is affected, the chain can retain + * the shape but be moved elsewhere + */ + copy_v3_v3(poseHead, pchan->pose_head); + } + else if (tree->con->enforce < 1.0f) { + /* when the influence is too low + * - blend the positions for the 'root' bone + * - stick to the parent for any other + */ + if (pchan->parent) { + copy_v3_v3(poseHead, pchan->pose_head); + } + else { + /* FIXME: this introduces popping artifacts when we reach 0.0 */ + interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); + } + } + copy_v3_v3(poseMat[3], poseHead); + + /* finally, store the new transform */ + copy_m4_m4(pchan->pose_mat, poseMat); + copy_v3_v3(pchan->pose_head, poseHead); + + /* recalculate tail, as it's now outdated after the head gets adjusted above! */ + BKE_pose_where_is_bone_tail(pchan); + + /* done! */ + pchan->flag |= POSE_DONE; +} + +/* Evaluate the chain starting from the nominated bone */ +static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) +{ + tSplineIK_Tree *tree; + + /* for each pose-tree, execute it if it is spline, otherwise just free it */ + while ((tree = pchan_root->siktree.first) != NULL) { + int i; + + /* walk over each bone in the chain, calculating the effects of spline IK + * - the chain is traversed in the opposite order to storage order (i.e. parent to children) + * so that dependencies are correct + */ + for (i = tree->chainlen - 1; i >= 0; i--) { + bPoseChannel *pchan = tree->chain[i]; + splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime); + } + + /* free the tree info specific to SplineIK trees now */ + if (tree->chain) + MEM_freeN(tree->chain); + if (tree->free_points) + MEM_freeN(tree->points); + + /* free this tree */ + BLI_freelinkN(&pchan_root->siktree, tree); + } +} + +void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime) +{ + splineik_init_tree(scene, ob, ctime); +} + +void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) +{ + splineik_execute_tree(scene, ob, pchan_root, ctime); +} + +/* *************** Depsgraph evaluation callbacks ************ */ + +void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPose *pose) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + bPoseChannel *pchan; + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + BLI_assert(ob->type == OB_ARMATURE); + + /* We demand having proper pose. */ + BLI_assert(ob->pose != NULL); + BLI_assert((ob->pose->flag & POSE_RECALC) == 0); + + /* imat is needed for solvers. */ + invert_m4_m4(ob->imat, ob->obmat); + + /* 1. clear flags */ + for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); + } + + /* 2a. construct the IK tree (standard IK) */ + BIK_initialize_tree(scene, ob, ctime); + + /* 2b. construct the Spline IK trees + * - this is not integrated as an IK plugin, since it should be able + * to function in conjunction with standard IK + */ + BKE_pose_splineik_init_tree(scene, ob, ctime); +} + +void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPoseChannel *pchan) +{ + bArmature *arm = (bArmature *)ob->data; + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + BLI_assert(ob->type == OB_ARMATURE); + if (arm->edbo || (arm->flag & ARM_RESTPOS)) { + Bone *bone = pchan->bone; + if (bone) { + copy_m4_m4(pchan->pose_mat, bone->arm_mat); + copy_v3_v3(pchan->pose_head, bone->arm_head); + copy_v3_v3(pchan->pose_tail, bone->arm_tail); + } + } + else { + /* TODO(sergey): Currently if there are constraints full transform is being + * evaluated in BKE_pose_constraints_evaluate. + */ + if (pchan->constraints.first == NULL) { + if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) { + /* pass */ + } + else { + /* TODO(sergey): Use time source node for time. */ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + } + } + } +} + +void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), + Object *ob, + bPoseChannel *pchan) +{ + Scene *scene = G.main->scene.first; + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) { + /* IK are being solved separately/ */ + } + else { + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + } +} + +void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), + bPoseChannel *pchan) +{ + float imat[4][4]; + DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name); + if (pchan->bone) { + invert_m4_m4(imat, pchan->bone->arm_mat); + mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat); + } +} + +void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPoseChannel *rootchan) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + BIK_execute_tree(scene, ob, rootchan, ctime); +} + +void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPoseChannel *rootchan) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + BKE_splineik_execute_tree(scene, ob, rootchan, ctime); +} + +void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob, + bPose *UNUSED(pose)) +{ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + BLI_assert(ob->type == OB_ARMATURE); + + /* 6. release the IK tree */ + BIK_release_tree(scene, ob, ctime); + + ob->recalc &= ~OB_RECALC_ALL; +} + +void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) +{ + BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL); + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { + printf("Proxy copy error, lib Object: %s proxy Object: %s\n", + ob->id.name + 2, ob->proxy_from->id.name + 2); + } +} diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index b6ea780576e..37bd9c5db5c 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -263,7 +263,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath /* but use new Scene pointer */ curscene = bfd->curscene; - track_undo_scene = (mode == LOAD_UNDO && curscreen && bfd->main->wm.first); + track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first); if (curscene == NULL) curscene = bfd->main->scene.first; /* empty file, we add a scene to make Blender work */ @@ -283,13 +283,17 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath /* clear_global will free G.main, here we can still restore pointers */ blo_lib_link_screen_restore(bfd->main, curscreen, curscene); - curscene = curscreen->scene; + /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */ + if (curscreen) { + curscene = curscreen->scene; + } if (track_undo_scene) { wmWindowManager *wm = bfd->main->wm.first; if (wm_scene_is_visible(wm, bfd->curscene) == false) { curscene = bfd->curscene; curscreen->scene = curscene; + BKE_screen_view3d_scene_sync(curscreen); } } } @@ -305,7 +309,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath CTX_data_main_set(C, G.main); - sound_init_main(G.main); + BKE_sound_init_main(G.main); if (bfd->user) { @@ -619,7 +623,7 @@ int BKE_write_file_userdef(const char *filepath, ReportList *reports) static void (*blender_test_break_cb)(void) = NULL; -void set_blender_test_break_cb(void (*func)(void)) +void BKE_blender_callback_test_break_set(void (*func)(void)) { blender_test_break_cb = func; } @@ -683,7 +687,7 @@ static int read_undosave(bContext *C, UndoElem *uel) } /* name can be a dynamic string */ -void BKE_write_undo(bContext *C, const char *name) +void BKE_undo_write(bContext *C, const char *name) { uintptr_t maxmem, totmem, memused; int nr /*, success */ /* UNUSED */; @@ -701,7 +705,7 @@ void BKE_write_undo(bContext *C, const char *name) while (undobase.last != curundo) { uel = undobase.last; BLI_remlink(&undobase, uel); - BLO_free_memfile(&uel->memfile); + BLO_memfile_free(&uel->memfile); MEM_freeN(uel); } @@ -723,7 +727,7 @@ void BKE_write_undo(bContext *C, const char *name) UndoElem *first = undobase.first; BLI_remlink(&undobase, first); /* the merge is because of compression */ - BLO_merge_memfile(&first->memfile, &first->next->memfile); + BLO_memfile_merge(&first->memfile, &first->next->memfile); MEM_freeN(first); } } @@ -778,7 +782,7 @@ void BKE_write_undo(bContext *C, const char *name) UndoElem *first = undobase.first; BLI_remlink(&undobase, first); /* the merge is because of compression */ - BLO_merge_memfile(&first->memfile, &first->next->memfile); + BLO_memfile_merge(&first->memfile, &first->next->memfile); MEM_freeN(first); } } @@ -817,13 +821,13 @@ void BKE_undo_step(bContext *C, int step) } } -void BKE_reset_undo(void) +void BKE_undo_reset(void) { UndoElem *uel; uel = undobase.first; while (uel) { - BLO_free_memfile(&uel->memfile); + BLO_memfile_free(&uel->memfile); uel = uel->next; } @@ -850,7 +854,7 @@ void BKE_undo_name(bContext *C, const char *name) } /* name optional */ -int BKE_undo_valid(const char *name) +bool BKE_undo_is_valid(const char *name) { if (name) { UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name)); @@ -862,15 +866,16 @@ int BKE_undo_valid(const char *name) /* get name of undo item, return null if no item with this index */ /* if active pointer, set it to 1 if true */ -const char *BKE_undo_get_name(int nr, int *active) +const char *BKE_undo_get_name(int nr, bool *r_active) { UndoElem *uel = BLI_findlink(&undobase, nr); - if (active) *active = 0; + if (r_active) *r_active = false; if (uel) { - if (active && uel == curundo) - *active = 1; + if (r_active && (uel == curundo)) { + *r_active = true; + } return uel->name; } return NULL; @@ -936,15 +941,16 @@ bool BKE_undo_save_file(const char *filename) } /* sets curscene */ -Main *BKE_undo_get_main(Scene **scene) +Main *BKE_undo_get_main(Scene **r_scene) { Main *mainp = NULL; BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL); if (bfd) { mainp = bfd->main; - if (scene) - *scene = bfd->curscene; + if (r_scene) { + *r_scene = bfd->curscene; + } MEM_freeN(bfd); } diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 4d40aba67fd..8248ea2fa37 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -80,6 +80,10 @@ #include "BKE_bpath.h" /* own include */ +#ifndef _MSC_VER +# include "BLI_strict_flags.h" +#endif + static bool checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src) { ReportList *reports = (ReportList *)userdata; @@ -206,18 +210,19 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re * \returns found: 1/0. */ #define MAX_RECUR 16 -static int findFileRecursive(char *filename_new, - const char *dirname, - const char *filename, - int *filesize, - int *recur_depth) +static bool missing_files_find__recursive( + char *filename_new, + const char *dirname, + const char *filename, + off_t *r_filesize, + int *r_recur_depth) { /* file searching stuff */ DIR *dir; struct dirent *de; BLI_stat_t status; char path[FILE_MAX]; - int size; + off_t size; bool found = false; dir = opendir(dirname); @@ -225,8 +230,8 @@ static int findFileRecursive(char *filename_new, if (dir == NULL) return found; - if (*filesize == -1) - *filesize = 0; /* dir opened fine */ + if (*r_filesize == -1) + *r_filesize = 0; /* dir opened fine */ while ((de = readdir(dir)) != NULL) { @@ -242,18 +247,18 @@ static int findFileRecursive(char *filename_new, if (STREQLEN(filename, de->d_name, FILE_MAX)) { /* name matches */ /* open the file to read its size */ size = status.st_size; - if ((size > 0) && (size > *filesize)) { /* find the biggest file */ - *filesize = size; + if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */ + *r_filesize = size; BLI_strncpy(filename_new, path, FILE_MAX); found = true; } } } else if (S_ISDIR(status.st_mode)) { /* is subdir */ - if (*recur_depth <= MAX_RECUR) { - (*recur_depth)++; - found |= findFileRecursive(filename_new, path, filename, filesize, recur_depth); - (*recur_depth)--; + if (*r_recur_depth <= MAX_RECUR) { + (*r_recur_depth)++; + found |= missing_files_find__recursive(filename_new, path, filename, r_filesize, r_recur_depth); + (*r_recur_depth)--; } } } @@ -268,14 +273,14 @@ typedef struct BPathFind_Data { bool find_all; } BPathFind_Data; -static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char *path_src) +static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src) { BPathFind_Data *data = (BPathFind_Data *)userdata; char filename_new[FILE_MAX]; - int filesize = -1; + off_t filesize = -1; int recur_depth = 0; - int found; + bool found; if (data->find_all == false) { if (BLI_exists(path_src)) { @@ -285,9 +290,10 @@ static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char filename_new[0] = '\0'; - found = findFileRecursive(filename_new, - data->searchdir, BLI_path_basename(path_src), - &filesize, &recur_depth); + found = missing_files_find__recursive( + filename_new, + data->searchdir, BLI_path_basename(path_src), + &filesize, &recur_depth); if (filesize == -1) { /* could not open dir */ BKE_reportf(data->reports, RPT_WARNING, @@ -318,13 +324,14 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis const bool find_all) { struct BPathFind_Data data = {NULL}; + const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED; data.basedir = bmain->name; data.reports = reports; data.searchdir = searchpath; data.find_all = find_all; - BKE_bpath_traverse_main(bmain, findMissingFiles_visit_cb, BKE_BPATH_TRAVERSE_ABS, (void *)&data); + BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data); } /* Run a visitor on a string, replacing the contents of the string as needed. */ @@ -366,6 +373,9 @@ static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR], BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file); + /* so functions can check old value */ + BLI_strncpy(path_dst, path_src, FILE_MAX); + if (absbase) { BLI_path_abs(path_src, absbase); } @@ -395,7 +405,7 @@ static bool rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *a } if (visit_cb(userdata, path_dst, path_src)) { - MEM_freeN((*path)); + MEM_freeN(*path); (*path) = BLI_strdup(path_dst); return true; } @@ -425,12 +435,17 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int { Image *ima; ima = (Image *)id; - if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { + if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { - if (!ima->packedfile) { - BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); - BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb); + if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) { + if (!BKE_image_has_packedfile(ima) && + /* image may have been painted onto (and not saved, T44543) */ + !BKE_image_is_dirty(ima)) + { + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb); + } } } } @@ -484,10 +499,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]); } } - else if (md->type == eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData *) md; - BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches); - } else if (md->type == eModifierType_Ocean) { OceanModifierData *omd = (OceanModifierData *) md; rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data); @@ -591,12 +602,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int } else if ((seq->type == SEQ_TYPE_IMAGE) && se) { /* might want an option not to loop over all strips */ - int len = MEM_allocN_len(se) / sizeof(*se); - int i; + unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se); + unsigned int i; if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) { /* only operate on one path */ - len = MIN2(1, len); + len = MIN2(1u, len); } for (i = 0; i < len; i++, se++) { diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 10d77921515..d5c5fb5fe43 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -68,7 +68,7 @@ static void brush_defaults(Brush *brush) brush->blend = 0; brush->flag = 0; - brush->ob_mode = OB_MODE_ALL_PAINT; + brush->ob_mode = OB_MODE_ALL_BRUSH; /* BRUSH SCULPT TOOL SETTINGS */ brush->weight = 1.0f; /* weight of brush 0 - 1.0 */ @@ -103,8 +103,8 @@ static void brush_defaults(Brush *brush) brush->jitter = 0.0f; /* BRUSH TEXTURE SETTINGS */ - default_mtex(&brush->mtex); - default_mtex(&brush->mask_mtex); + BKE_texture_mtex_default(&brush->mtex); + BKE_texture_mtex_default(&brush->mask_mtex); brush->texture_sample_bias = 0; /* value to added to texture samples */ brush->texture_overlay_alpha = 33; @@ -469,7 +469,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr) idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1); if (idtest == NULL) { /* new tex */ if (id) idtest = (ID *)BKE_texture_copy((Tex *)id); - else idtest = (ID *)add_texture(G.main, "Tex"); + else idtest = (ID *)BKE_texture_add(G.main, "Tex"); idtest->us--; } if (idtest != id) { @@ -782,13 +782,13 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, * inconsistency. */ -float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush) +const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb; } -float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush) +const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb; @@ -819,7 +819,7 @@ void BKE_brush_size_set(Scene *scene, Brush *brush, int size) brush->size = size; } -int BKE_brush_size_get(const Scene *scene, Brush *brush) +int BKE_brush_size_get(const Scene *scene, const Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size; @@ -827,7 +827,7 @@ int BKE_brush_size_get(const Scene *scene, Brush *brush) return (int)((float)size * U.pixelsize); } -int BKE_brush_use_locked_size(const Scene *scene, Brush *brush) +int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush) { const short us_flag = scene->toolsettings->unified_paint_settings.flag; @@ -836,7 +836,7 @@ int BKE_brush_use_locked_size(const Scene *scene, Brush *brush) (brush->flag & BRUSH_LOCK_SIZE); } -int BKE_brush_use_size_pressure(const Scene *scene, Brush *brush) +int BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush) { const short us_flag = scene->toolsettings->unified_paint_settings.flag; @@ -845,7 +845,7 @@ int BKE_brush_use_size_pressure(const Scene *scene, Brush *brush) (brush->flag & BRUSH_SIZE_PRESSURE); } -int BKE_brush_use_alpha_pressure(const Scene *scene, Brush *brush) +int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush) { const short us_flag = scene->toolsettings->unified_paint_settings.flag; @@ -864,7 +864,7 @@ void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojec brush->unprojected_radius = unprojected_radius; } -float BKE_brush_unprojected_radius_get(const Scene *scene, Brush *brush) +float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -883,14 +883,14 @@ void BKE_brush_alpha_set(Scene *scene, Brush *brush, float alpha) brush->alpha = alpha; } -float BKE_brush_alpha_get(const Scene *scene, Brush *brush) +float BKE_brush_alpha_get(const Scene *scene, const Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; return (ups->flag & UNIFIED_PAINT_ALPHA) ? ups->alpha : brush->alpha; } -float BKE_brush_weight_get(const Scene *scene, Brush *brush) +float BKE_brush_weight_get(const Scene *scene, const Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -920,9 +920,10 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius, } /* scale brush size to reflect a change in the brush's unprojected radius */ -void BKE_brush_scale_size(int *r_brush_size, - float new_unprojected_radius, - float old_unprojected_radius) +void BKE_brush_scale_size( + int *r_brush_size, + float new_unprojected_radius, + float old_unprojected_radius) { float scale = new_unprojected_radius; /* avoid division by zero */ diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c new file mode 100644 index 00000000000..370a2fc1887 --- /dev/null +++ b/source/blender/blenkernel/intern/cache_library.c @@ -0,0 +1,2256 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2015 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/cache_library.c + * \ingroup bke + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_fileops.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_cache_library_types.h" +#include "DNA_group_types.h" +#include "DNA_key_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_force.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" + +#include "BKE_anim.h" +#include "BKE_bvhutils.h" +#include "BKE_cache_library.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_editstrands.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_idprop.h" +#include "BKE_key.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_strands.h" + +#include "BLF_translation.h" + +#include "PTC_api.h" + +#include "BPH_mass_spring.h" + +CacheLibrary *BKE_cache_library_add(Main *bmain, const char *name) +{ + CacheLibrary *cachelib; + char basename[MAX_NAME]; + + cachelib = BKE_libblock_alloc(bmain, ID_CL, name); + + BLI_strncpy(basename, cachelib->id.name+2, sizeof(basename)); + BLI_filename_make_safe(basename); + BLI_snprintf(cachelib->output_filepath, sizeof(cachelib->output_filepath), "//cache/%s.%s", basename, PTC_get_default_archive_extension()); + + cachelib->source_mode = CACHE_LIBRARY_SOURCE_SCENE; + cachelib->display_mode = CACHE_LIBRARY_DISPLAY_MODIFIERS; + cachelib->display_flag = CACHE_LIBRARY_DISPLAY_MOTION | CACHE_LIBRARY_DISPLAY_CHILDREN; + + /* cache everything by default */ + cachelib->data_types = CACHE_TYPE_ALL; + + return cachelib; +} + +CacheLibrary *BKE_cache_library_copy(CacheLibrary *cachelib) +{ + CacheLibrary *cachelibn; + + cachelibn = BKE_libblock_copy(&cachelib->id); + + if (cachelibn->filter_group) + id_us_plus(&cachelibn->filter_group->id); + + { + CacheModifier *md; + BLI_listbase_clear(&cachelibn->modifiers); + for (md = cachelib->modifiers.first; md; md = md->next) { + BKE_cache_modifier_copy(cachelibn, md); + } + } + + cachelibn->archive_info = NULL; + + if (cachelib->id.lib) { + BKE_id_lib_local_paths(G.main, cachelib->id.lib, &cachelibn->id); + } + + return cachelibn; +} + +void BKE_cache_library_free(CacheLibrary *cachelib) +{ + BKE_cache_modifier_clear(cachelib); + + if (cachelib->filter_group) + id_us_min(&cachelib->filter_group->id); + + if (cachelib->archive_info) + BKE_cache_archive_info_free(cachelib->archive_info); +} + +void BKE_cache_library_unlink(CacheLibrary *UNUSED(cachelib)) +{ +} + +/* ========================================================================= */ + +const char *BKE_cache_item_name_prefix(int type) +{ + /* note: avoid underscores and the like here, + * the prefixes must be unique and safe when combined with arbitrary strings! + */ + switch (type) { + case CACHE_TYPE_OBJECT: return "OBJECT"; + case CACHE_TYPE_DERIVED_MESH: return "MESH"; + case CACHE_TYPE_HAIR: return "HAIR"; + case CACHE_TYPE_HAIR_PATHS: return "HAIRPATHS"; + case CACHE_TYPE_PARTICLES: return "PARTICLES"; + default: BLI_assert(false); return NULL; break; + } +} + +void BKE_cache_item_name(Object *ob, int type, int index, char *name) +{ + if (index >= 0) + sprintf(name, "%s_%s_%d", BKE_cache_item_name_prefix(type), ob->id.name+2, index); + else + sprintf(name, "%s_%s", BKE_cache_item_name_prefix(type), ob->id.name+2); +} + +int BKE_cache_item_name_length(Object *ob, int type, int index) +{ + char *str_dummy = (char *)""; + if (index >= 0) + return BLI_snprintf(str_dummy, 0, "%s_%s_%d", BKE_cache_item_name_prefix(type), ob->id.name + 2, index); + else + return BLI_snprintf(str_dummy, 0, "%s_%s", BKE_cache_item_name_prefix(type), ob->id.name + 2); +} + +eCacheReadSampleResult BKE_cache_read_result(int ptc_result) +{ + switch (ptc_result) { + case PTC_READ_SAMPLE_INVALID: return CACHE_READ_SAMPLE_INVALID; + case PTC_READ_SAMPLE_EARLY: return CACHE_READ_SAMPLE_EARLY; + case PTC_READ_SAMPLE_LATE: return CACHE_READ_SAMPLE_LATE; + case PTC_READ_SAMPLE_EXACT: return CACHE_READ_SAMPLE_EXACT; + case PTC_READ_SAMPLE_INTERPOLATED: return CACHE_READ_SAMPLE_INTERPOLATED; + default: BLI_assert(false); break; /* should never happen, enums out of sync? */ + } + return CACHE_READ_SAMPLE_INVALID; +} + +bool BKE_cache_library_validate_item(CacheLibrary *cachelib, Object *ob, int type, int index) +{ + if (!cachelib) + return false; + + if (ELEM(type, CACHE_TYPE_DERIVED_MESH)) { + if (ob->type != OB_MESH) + return false; + } + else if (ELEM(type, CACHE_TYPE_PARTICLES, CACHE_TYPE_HAIR, CACHE_TYPE_HAIR_PATHS)) { + ParticleSystem *psys = BLI_findlink(&ob->particlesystem, index); + + if (!psys) + return false; + + if (ELEM(type, CACHE_TYPE_PARTICLES)) { + if (psys->part->type != PART_EMITTER) + return false; + } + + if (ELEM(type, CACHE_TYPE_HAIR, CACHE_TYPE_HAIR_PATHS)) { + if (psys->part->type != PART_HAIR) + return false; + } + } + + return true; +} + +/* ========================================================================= */ + +/* unused + * filtering now only tags objects to exclude them from storing data, + * but does not actually remove them from the duplilist. + */ +#if 0 +void BKE_cache_library_filter_duplilist(CacheLibrary *cachelib, ListBase *duplilist) +{ + if (cachelib->filter_group) { + GroupObject *gob; + + /* tag only filter group objects as valid */ + BKE_main_id_tag_idcode(G.main, ID_OB, false); + for (gob = cachelib->filter_group->gobject.first; gob; gob = gob->next) + gob->ob->id.flag |= LIB_DOIT; + } + else { + /* all objects valid */ + BKE_main_id_tag_idcode(G.main, ID_OB, true); + } + + { + /* remove invalid duplis */ + DupliObject *dob, *dob_next; + for (dob = duplilist->first; dob; dob = dob_next) { + dob_next = dob->next; + + if (!(dob->ob->id.flag & LIB_DOIT)) { + BLI_remlink(duplilist, dob); + MEM_freeN(dob); + } + } + } + + /* clear LIB_DOIT tags */ + BKE_main_id_tag_idcode(G.main, ID_OB, false); +} +#endif + +void BKE_cache_library_tag_used_objects(CacheLibrary *cachelib) +{ + if (cachelib->filter_group) { + GroupObject *gob; + + /* tag only filter group objects as valid */ + BKE_main_id_tag_idcode(G.main, ID_OB, false); + for (gob = cachelib->filter_group->gobject.first; gob; gob = gob->next) + gob->ob->id.flag |= LIB_DOIT; + } + else { + /* all objects valid */ + BKE_main_id_tag_idcode(G.main, ID_OB, true); + } +} + +/* ========================================================================= */ + +static IDProperty *cache_library_get_metadata(CacheLibrary *cachelib, const char *name, bool create) +{ + IDProperty *idprops = IDP_GetProperties((ID *)cachelib, create); + IDProperty *metadata = NULL; + if (idprops) { + metadata = IDP_GetPropertyFromGroup(idprops, name); + if (!metadata && create) { + IDPropertyTemplate val; + val.i = 0; + metadata = IDP_New(IDP_GROUP, &val, name); + IDP_AddToGroup(idprops, metadata); + } + } + return metadata; +} + +IDProperty *BKE_cache_library_get_input_metadata(CacheLibrary *cachelib, bool create) +{ + return cache_library_get_metadata(cachelib, "input_metadata", create); +} + +IDProperty *BKE_cache_library_get_output_metadata(CacheLibrary *cachelib, bool create) +{ + return cache_library_get_metadata(cachelib, "output_metadata", create); +} + +BLI_INLINE bool path_is_dirpath(const char *path) +{ + /* last char is a slash? */ + const char *last_slash = BLI_last_slash(path); + return last_slash ? (*(last_slash + 1) == '\0') : false; +} + +bool BKE_cache_archive_path_test(CacheLibrary *cachelib, const char *path) +{ + if (BLI_path_is_rel(path)) { + if (!(G.relbase_valid || cachelib->id.lib)) + return false; + } + + return true; + +} + +void BKE_cache_archive_path_ex(const char *path, Library *lib, const char *default_filename, char *result, int max) +{ + char abspath[FILE_MAX]; + + result[0] = '\0'; + + if (BLI_path_is_rel(path)) { + if (G.relbase_valid || lib) { + const char *relbase = lib ? lib->filepath : G.main->name; + + BLI_strncpy(abspath, path, sizeof(abspath)); + BLI_path_abs(abspath, relbase); + } + else { + /* can't construct a valid path */ + return; + } + } + else { + BLI_strncpy(abspath, path, sizeof(abspath)); + } + + if (abspath[0] != '\0') { + if (path_is_dirpath(abspath) || BLI_is_dir(abspath)) { + if (default_filename && default_filename[0] != '\0') + BLI_join_dirfile(result, max, abspath, default_filename); + } + else { + BLI_strncpy(result, abspath, max); + } + } +} + +void BKE_cache_archive_input_path(CacheLibrary *cachelib, char *result, int max) +{ + BKE_cache_archive_path_ex(cachelib->input_filepath, cachelib->id.lib, NULL, result, max); +} + +void BKE_cache_archive_output_path(CacheLibrary *cachelib, char *result, int max) +{ + BKE_cache_archive_path_ex(cachelib->output_filepath, cachelib->id.lib, cachelib->id.name+2, result, max); +} + +static bool has_active_cache(CacheLibrary *cachelib) +{ + const bool is_baking = cachelib->flag & CACHE_LIBRARY_BAKING; + + /* don't read results from output archive when baking */ + if (!is_baking) { + if (cachelib->display_mode == CACHE_LIBRARY_DISPLAY_RESULT) { + return true; + } + } + + if (ELEM(cachelib->source_mode, CACHE_LIBRARY_SOURCE_CACHE, CACHE_LIBRARY_DISPLAY_MODIFIERS)) { + return true; + } + + return false; +} + +static struct PTCReaderArchive *find_active_cache(Scene *scene, CacheLibrary *cachelib) +{ + char filename[FILE_MAX]; + struct PTCReaderArchive *archive = NULL; + + const bool is_baking = cachelib->flag & CACHE_LIBRARY_BAKING; + + /* don't read results from output archive when baking */ + if (!is_baking) { + if (cachelib->display_mode == CACHE_LIBRARY_DISPLAY_RESULT) { + /* try using the output cache */ + BKE_cache_archive_output_path(cachelib, filename, sizeof(filename)); + archive = PTC_open_reader_archive(scene, filename); + } + } + + if (!archive && ELEM(cachelib->source_mode, CACHE_LIBRARY_SOURCE_CACHE, CACHE_LIBRARY_DISPLAY_MODIFIERS)) { + BKE_cache_archive_input_path(cachelib, filename, sizeof(filename)); + archive = PTC_open_reader_archive(scene, filename); + } + + /* get basic archive info */ + if (cachelib->archive_info) + BKE_cache_archive_info_clear(cachelib->archive_info); + else + cachelib->archive_info = BKE_cache_archive_info_new(); + BLI_strncpy(cachelib->archive_info->filepath, filename, sizeof(cachelib->archive_info->filepath)); + if (archive) { + IDProperty *metadata = BKE_cache_library_get_input_metadata(cachelib, true); + PTC_get_archive_info(archive, cachelib->archive_info, metadata); + } + + return archive; +} + +void BKE_cache_library_get_read_flags(CacheLibrary *cachelib, bool use_render, bool for_display, bool *read_strands_motion, bool *read_strands_children) +{ + if (!use_render && for_display) { + *read_strands_motion = cachelib->display_flag & CACHE_LIBRARY_DISPLAY_MOTION; + *read_strands_children = cachelib->display_flag & CACHE_LIBRARY_DISPLAY_CHILDREN; + } + else { + *read_strands_motion = true; + *read_strands_children = true; + } +} + +bool BKE_cache_read_dupli_cache(CacheLibrary *cachelib, DupliCache *dupcache, + Scene *scene, Group *dupgroup, float frame, bool use_render, bool for_display) +{ + bool read_strands_motion, read_strands_children, read_simdebug = G.debug & G_DEBUG_SIMDATA; + struct PTCReaderArchive *archive; + struct PTCReader *reader; + + if (!dupcache) + return false; + + dupcache->result = CACHE_READ_SAMPLE_INVALID; + + if (!dupgroup || !cachelib) + return false; + + archive = find_active_cache(scene, cachelib); + if (!archive) + return false; + + PTC_reader_archive_use_render(archive, use_render); + + BKE_cache_library_get_read_flags(cachelib, use_render, for_display, &read_strands_motion, &read_strands_children); + // TODO duplicache reader should only overwrite data that is not sequentially generated by modifiers (simulations) ... + reader = PTC_reader_duplicache(dupgroup->id.name, dupgroup, dupcache, + read_strands_motion, read_strands_children, read_simdebug); + PTC_reader_init(reader, archive); + + dupcache->result = BKE_cache_read_result(PTC_read_sample(reader, frame)); + + PTC_reader_free(reader); + PTC_close_reader_archive(archive); + + return (dupcache->result != CACHE_READ_SAMPLE_INVALID); +} + +bool BKE_cache_read_dupli_object(CacheLibrary *cachelib, DupliObjectData *data, + Scene *scene, Object *ob, float frame, bool use_render, bool for_display) +{ + bool read_strands_motion, read_strands_children; + struct PTCReaderArchive *archive; + struct PTCReader *reader; + /*eCacheReadSampleResult result;*/ /* unused */ + + if (!data || !ob || !cachelib) + return false; + + archive = find_active_cache(scene, cachelib); + if (!archive) + return false; + + PTC_reader_archive_use_render(archive, use_render); + + BKE_cache_library_get_read_flags(cachelib, use_render, for_display, &read_strands_motion, &read_strands_children); + reader = PTC_reader_duplicache_object(ob->id.name, ob, data, read_strands_motion, read_strands_children); + PTC_reader_init(reader, archive); + + /*result = */BKE_cache_read_result(PTC_read_sample(reader, frame)); + + PTC_reader_free(reader); + PTC_close_reader_archive(archive); + + return true; +} + + +void BKE_cache_library_dag_recalc_tag(EvaluationContext *UNUSED(eval_ctx), Main *bmain) +{ + CacheLibrary *cachelib; + for (cachelib = bmain->cache_library.first; cachelib; cachelib = cachelib->id.next) { + if (has_active_cache(cachelib)) + DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA | OB_RECALC_TIME); + } +} + +/* ========================================================================= */ + +CacheModifierTypeInfo cache_modifier_types[NUM_CACHE_MODIFIER_TYPES]; + +static CacheModifierTypeInfo *cache_modifier_type_get(eCacheModifier_Type type) +{ + return &cache_modifier_types[type]; +} + +static void cache_modifier_type_set(eCacheModifier_Type type, CacheModifierTypeInfo *mti) +{ + memcpy(&cache_modifier_types[type], mti, sizeof(CacheModifierTypeInfo)); +} + +const char *BKE_cache_modifier_type_name(eCacheModifier_Type type) +{ + return cache_modifier_type_get(type)->name; +} + +const char *BKE_cache_modifier_type_struct_name(eCacheModifier_Type type) +{ + return cache_modifier_type_get(type)->struct_name; +} + +int BKE_cache_modifier_type_struct_size(eCacheModifier_Type type) +{ + return cache_modifier_type_get(type)->struct_size; +} + +/* ------------------------------------------------------------------------- */ + +bool BKE_cache_modifier_unique_name(ListBase *modifiers, CacheModifier *md) +{ + if (modifiers && md) { + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + + return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(CacheModifier, name), sizeof(md->name)); + } + return false; +} + +CacheModifier *BKE_cache_modifier_add(CacheLibrary *cachelib, const char *name, eCacheModifier_Type type) +{ + CacheModifierTypeInfo *mti = cache_modifier_type_get(type); + + CacheModifier *md = MEM_callocN(mti->struct_size, "cache modifier"); + md->type = type; + + if (!name) + name = mti->name; + BLI_strncpy_utf8(md->name, name, sizeof(md->name)); + /* make sure modifier has unique name */ + BKE_cache_modifier_unique_name(&cachelib->modifiers, md); + + if (mti->init) + mti->init(md); + + BLI_addtail(&cachelib->modifiers, md); + + return md; +} + +void BKE_cache_modifier_remove(CacheLibrary *cachelib, CacheModifier *md) +{ + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + + BLI_remlink(&cachelib->modifiers, md); + + if (mti->free) + mti->free(md); + + MEM_freeN(md); +} + +void BKE_cache_modifier_clear(CacheLibrary *cachelib) +{ + CacheModifier *md, *md_next; + for (md = cachelib->modifiers.first; md; md = md_next) { + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + md_next = md->next; + + if (mti->free) + mti->free(md); + + MEM_freeN(md); + } + + BLI_listbase_clear(&cachelib->modifiers); +} + +CacheModifier *BKE_cache_modifier_copy(CacheLibrary *cachelib, CacheModifier *md) +{ + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + + CacheModifier *tmd = MEM_dupallocN(md); + + if (mti->copy) + mti->copy(md, tmd); + + BLI_addtail(&cachelib->modifiers, tmd); + + return tmd; +} + +void BKE_cache_modifier_foreachIDLink(struct CacheLibrary *cachelib, struct CacheModifier *md, CacheModifier_IDWalkFunc walk, void *userdata) +{ + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + + if (mti->foreachIDLink) + mti->foreachIDLink(md, cachelib, walk, userdata); +} + +void BKE_cache_process_dupli_cache(CacheLibrary *cachelib, CacheProcessData *data, + Scene *scene, Group *dupgroup, float frame_prev, float frame, + bool do_modifiers, bool do_strands_child_deform, bool do_strands_motion) +{ + CacheProcessContext ctx; + CacheModifier *md; + + ctx.bmain = G.main; + ctx.scene = scene; + ctx.cachelib = cachelib; + ctx.group = dupgroup; + + if (do_modifiers) { + for (md = cachelib->modifiers.first; md; md = md->next) { + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + + // TODO parent modifiers only here + if (mti->process) + mti->process(md, &ctx, data, frame, frame_prev, eCacheProcessFlag_DoStrands); + } + } + + /* deform child strands to follow parent motion */ + if (do_modifiers || do_strands_child_deform) { + struct DupliCacheIterator *it; + + it = BKE_dupli_cache_iter_new(data->dupcache); + for (; BKE_dupli_cache_iter_valid(it); BKE_dupli_cache_iter_next(it)) { + DupliObjectData *dobdata = BKE_dupli_cache_iter_get(it); + DupliObjectDataStrands *link; + + for (link = dobdata->strands.first; link; link = link->next) { + if (link->strands_children) + BKE_strands_children_deform(link->strands_children, link->strands, do_strands_motion); + } + } + BKE_dupli_cache_iter_free(it); + } + + if (do_modifiers) { + for (md = cachelib->modifiers.first; md; md = md->next) { + CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type); + + // TODO child modifiers only here + if (mti->process) + mti->process(md, &ctx, data, frame, frame_prev, eCacheProcessFlag_DoStrandsChildren); + } + } +} + +/* ------------------------------------------------------------------------- */ + +static ForceFieldVertexCache *forcefield_vertex_cache_new(void); +static void forcefield_vertex_cache_free(ForceFieldVertexCache *cache); +static void forcefield_vertex_cache_clear(ForceFieldVertexCache *cache); +static void forcefield_vertex_cache_init(ForceFieldVertexCache *cache, float frame, DerivedMesh *dm); + +static void effector_set_mesh(CacheEffector *eff, Object *ob, DerivedMesh *dm, bool create_dm, bool create_bvhtree, bool world_space) +{ + if (create_dm && dm) { + unsigned int numverts, i; + MVert *mvert, *mv; + + eff->dm = CDDM_copy(dm); + if (!eff->dm) + return; + + DM_ensure_tessface(eff->dm); + CDDM_calc_normals(eff->dm); + + numverts = eff->dm->getNumVerts(eff->dm); + mvert = eff->dm->getVertArray(eff->dm); + + if (world_space) { + /* convert to world coordinates */ + for (i = 0, mv = mvert; i < numverts; ++i, ++mv) { + mul_m4_v3(ob->obmat, mv->co); + } + } + + if (create_bvhtree) { + if (eff->treedata) + free_bvhtree_from_mesh(eff->treedata); + else + eff->treedata = MEM_callocN(sizeof(BVHTreeFromMesh), "cache effector bvhtree data"); + + bvhtree_from_mesh_faces(eff->treedata, eff->dm, 0.0, 2, 6); + } + } +} + +static void effector_set_instances(CacheEffector *eff, Object *ob, float obmat[4][4], ListBase *duplilist) +{ + DupliObject *dob; + + for (dob = duplilist->first; dob; dob = dob->next) { + CacheEffectorInstance *inst; + + if (dob->ob != ob) + continue; + + inst = MEM_callocN(sizeof(CacheEffectorInstance), "cache effector instance"); + mul_m4_m4m4(inst->mat, obmat, dob->mat); + invert_m4_m4(inst->imat, inst->mat); + + BLI_addtail(&eff->instances, inst); + } +} + +static bool forcefield_get_effector(DupliCache *dupcache, float obmat[4][4], ForceFieldCacheModifier *ffmd, CacheEffector *eff) +{ + DupliObjectData *dobdata; + + if (!ffmd->object) + return false; + + dobdata = BKE_dupli_cache_find_data(dupcache, ffmd->object); + if (!dobdata) + return false; + + effector_set_mesh(eff, dobdata->ob, dobdata->dm, true, true, false); + effector_set_instances(eff, dobdata->ob, obmat, &dupcache->duplilist); + + switch (ffmd->type) { + case eForceFieldCacheModifier_Type_Deflect: + eff->type = eCacheEffector_Type_Deflect; + break; + case eForceFieldCacheModifier_Type_Drag: + eff->type = eCacheEffector_Type_Drag; + break; + } + + eff->strength = ffmd->strength; + eff->falloff = ffmd->falloff; + eff->mindist = ffmd->min_distance; + eff->maxdist = ffmd->max_distance; + eff->double_sided = ffmd->flag & eForceFieldCacheModifier_Flag_DoubleSided; + eff->vertex_cache = ffmd->vertex_cache; + + return true; +} + +int BKE_cache_effectors_get(CacheEffector *effectors, int max, CacheLibrary *cachelib, DupliCache *dupcache, float obmat[4][4]) +{ + CacheModifier *md; + int tot = 0; + + if (tot >= max) + return tot; + + memset(effectors, 0, sizeof(CacheEffector) * max); + + for (md = cachelib->modifiers.first; md; md = md->next) { + switch (md->type) { + case eCacheModifierType_ForceField: { + ForceFieldCacheModifier *ffmd = (ForceFieldCacheModifier *)md; + if (forcefield_get_effector(dupcache, obmat, ffmd, &effectors[tot])) + tot++; + break; + } + } + + BLI_assert(tot <= max); + if (tot == max) + break; + } + + return tot; +} + +void BKE_cache_effectors_free(CacheEffector *effectors, int tot) +{ + CacheEffector *eff; + int i; + + for (i = 0, eff = effectors; i < tot; ++i, ++eff) { + BLI_freelistN(&eff->instances); + + if (eff->treedata) { + free_bvhtree_from_mesh(eff->treedata); + MEM_freeN(eff->treedata); + } + + if (eff->dm) { + eff->dm->release(eff->dm); + } + } +} + +static bool forcefield_velocity_update(DupliCache *dupcache, float obmat[4][4], float frame, ForceFieldCacheModifier *ffmd) +{ + DupliObjectData *dobdata; + bool use_vertex_cache = false; + + if (!ffmd->object) + return false; + + dobdata = BKE_dupli_cache_find_data(dupcache, ffmd->object); + if (!dobdata) + return false; + + switch (ffmd->type) { + case eForceFieldCacheModifier_Type_Drag: + use_vertex_cache = true; + break; + } + + if (use_vertex_cache) { + if (!ffmd->vertex_cache) { + ffmd->vertex_cache = forcefield_vertex_cache_new(); + } + + forcefield_vertex_cache_init(ffmd->vertex_cache, frame, dobdata->dm); + { + int i; + for (i = 0; i < ffmd->vertex_cache->totvert; ++i) { + float x[3], v[3]; + mul_v3_m4v3(x, obmat, ffmd->vertex_cache->co_prev[i]); + copy_v3_v3(v, ffmd->vertex_cache->vel[i]); + mul_mat3_m4_v3(obmat, v); + BKE_sim_debug_data_add_vector(x, v, 1,1,0, "hairsim", 45232, i); + } + } + } + + return true; +} + +void BKE_cache_effector_velocity_update(CacheLibrary *cachelib, DupliCache *dupcache, float obmat[4][4], float frame) +{ + CacheModifier *md; + + for (md = cachelib->modifiers.first; md; md = md->next) { + switch (md->type) { + case eCacheModifierType_ForceField: + forcefield_velocity_update(dupcache, obmat, frame, (ForceFieldCacheModifier *)md); + break; + } + } +} + +static bool cache_effector_falloff(const CacheEffector *eff, float distance, float *r_factor) +{ + float mindist = eff->mindist; + float maxdist = eff->maxdist; + float falloff = eff->falloff; + float range = maxdist - mindist; + + if (r_factor) *r_factor = 0.0f; + + if (range <= 0.0f) + return false; + + if (distance > eff->maxdist) + return false; + CLAMP_MIN(distance, eff->mindist); + CLAMP_MIN(falloff, 0.0f); + + if (r_factor) *r_factor = powf(1.0f - (distance - mindist) / range, falloff); + return true; +} + +typedef struct CacheEffectorTessfaceData { + int face_index; + MFace *mface; + MVert *mvert[4]; + float weight[4]; +} CacheEffectorTessfaceData; + +static void cache_effector_velocity(const CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorTessfaceData *tessface, float vel[3]) +{ + zero_v3(vel); + + if (!eff->vertex_cache) + return; + + BLI_assert(eff->vertex_cache->totvert == eff->dm->getNumVerts(eff->dm)); + + madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v1], tessface->weight[0]); + madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v2], tessface->weight[1]); + madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v3], tessface->weight[2]); + if (tessface->mface->v4) + madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v4], tessface->weight[3]); + + /* vertex cache velocities are in local space, effector results are all expected in world space */ + mul_mat3_m4_v3(inst->mat, vel); +} + +static bool cache_effector_find_nearest(CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorPoint *point, + float r_vec[3], float r_nor[3], float *r_dist, bool *r_inside, + CacheEffectorTessfaceData *r_tessface) +{ + const bool need_inside = r_dist || r_inside; + + BVHTreeNearest nearest = {0, }; + float world_near_co[3], world_near_no[3]; + float co[3], vec[3], dist; + bool inside; + + if (!eff->treedata) + return false; + + nearest.dist_sq = FLT_MAX; + + /* lookup in object space */ + mul_v3_m4v3(co, inst->imat, point->x); + + BLI_bvhtree_find_nearest(eff->treedata->tree, co, &nearest, eff->treedata->nearest_callback, eff->treedata); + if (nearest.index < 0) + return false; + + /* convert back to world space */ + mul_v3_m4v3(world_near_co, inst->mat, nearest.co); + copy_v3_v3(world_near_no, nearest.no); + mul_mat3_m4_v3(inst->mat, world_near_no); + + sub_v3_v3v3(vec, point->x, world_near_co); + dist = normalize_v3(vec); + + if (need_inside) { + inside = false; + if (!eff->double_sided) { + if (dot_v3v3(vec, world_near_no) < 0.0f) { + dist = -dist; + inside = true; + } + } + } + + if (r_vec) copy_v3_v3(r_vec, vec); + if (r_nor) copy_v3_v3(r_nor, world_near_no); + if (r_dist) *r_dist = dist; + if (r_inside) *r_inside = inside; + + if (r_tessface && eff->dm) { + CacheEffectorTessfaceData *t = r_tessface; + DerivedMesh *dm = eff->dm; + MFace *mf = dm->getTessFaceArray(dm) + nearest.index; + MVert *mverts = dm->getVertArray(dm); + + t->face_index = nearest.index; + t->mface = mf; + t->mvert[0] = &mverts[mf->v1]; + t->mvert[1] = &mverts[mf->v2]; + t->mvert[2] = &mverts[mf->v3]; + + if (mf->v4) { + t->mvert[3] = &mverts[mf->v4]; + interp_weights_face_v3(t->weight, t->mvert[0]->co, t->mvert[1]->co, t->mvert[2]->co, t->mvert[3]->co, nearest.co); + } + else { + t->mvert[3] = NULL; + interp_weights_face_v3(t->weight, t->mvert[0]->co, t->mvert[1]->co, t->mvert[2]->co, NULL, nearest.co); + } + } + + return true; +} + +static bool cache_effector_deflect(CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorPoint *point, CacheEffectorResult *result) +{ + float vec[3], dist, falloff; + bool inside; + + if (!cache_effector_find_nearest(eff, inst, point, vec, NULL, &dist, &inside, NULL)) + return false; + if (!cache_effector_falloff(eff, dist, &falloff)) + return false; + + mul_v3_v3fl(result->f, vec, eff->strength * falloff); + if (inside) + negate_v3(result->f); + return true; +} + +static bool cache_effector_drag(CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorPoint *point, CacheEffectorResult *result) +{ + float vec[3], dist, vel[3]; + float falloff; + CacheEffectorTessfaceData facedata; + + if (!cache_effector_find_nearest(eff, inst, point, vec, NULL, &dist, NULL, &facedata)) + return false; + if (!cache_effector_falloff(eff, dist, &falloff)) + return false; + + cache_effector_velocity(eff, inst, &facedata, vel); + + /* relative velocity */ + sub_v3_v3v3(vel, point->v, vel); + + mul_v3_v3fl(result->f, vel, -eff->strength * falloff); + + return true; +} + +static void cache_effector_result_init(CacheEffectorResult *result) +{ + zero_v3(result->f); +} + +static void cache_effector_result_add(CacheEffectorResult *result, const CacheEffectorResult *other) +{ + add_v3_v3(result->f, other->f); +} + +int BKE_cache_effectors_eval_ex(CacheEffector *effectors, int tot, CacheEffectorPoint *point, CacheEffectorResult *result, + bool (*filter)(void *, CacheEffector *), void *filter_data) +{ + CacheEffector *eff; + int i, applied = 0; + + cache_effector_result_init(result); + + for (i = 0, eff = effectors; i < tot; ++i, ++eff) { + const eCacheEffector_Type type = eff->type; + CacheEffectorInstance *inst; + + for (inst = eff->instances.first; inst; inst = inst->next) { + CacheEffectorResult inst_result; + cache_effector_result_init(&inst_result); + + if (filter && !filter(filter_data, eff)) + continue; + + switch (type) { + case eCacheEffector_Type_Deflect: + if (cache_effector_deflect(eff, inst, point, &inst_result)) { + cache_effector_result_add(result, &inst_result); + ++applied; + } + break; + case eCacheEffector_Type_Drag: + if (cache_effector_drag(eff, inst, point, &inst_result)) { + cache_effector_result_add(result, &inst_result); + ++applied; + } + break; + } + } + } + + return applied; +} + +int BKE_cache_effectors_eval(CacheEffector *effectors, int tot, CacheEffectorPoint *point, CacheEffectorResult *result) +{ + return BKE_cache_effectors_eval_ex(effectors, tot, point, result, NULL, NULL); +} + +/* ========================================================================= */ + +bool BKE_cache_modifier_find_object(DupliCache *dupcache, Object *ob, DupliObjectData **r_data) +{ + DupliObjectData *dobdata; + + if (!ob) + return false; + dobdata = BKE_dupli_cache_find_data(dupcache, ob); + if (!dobdata) + return false; + + if (r_data) *r_data = dobdata; + return true; +} + +bool BKE_cache_modifier_find_strands(DupliCache *dupcache, Object *ob, int hair_system, DupliObjectData **r_data, Strands **r_strands, StrandsChildren **r_children, const char **r_name) +{ + DupliObjectData *dobdata; + ParticleSystem *psys; + DupliObjectDataStrands *link; + Strands *strands; + StrandsChildren *children; + + if (!ob) + return false; + dobdata = BKE_dupli_cache_find_data(dupcache, ob); + if (!dobdata) + return false; + + psys = BLI_findlink(&ob->particlesystem, hair_system); + if (!psys || (psys->part->type != PART_HAIR)) + return false; + + strands = NULL; + children = NULL; + for (link = dobdata->strands.first; link; link = link->next) { + if (link->strands && STREQ(link->name, psys->name)) { + strands = link->strands; + children = link->strands_children; + break; + } + } + if ((r_strands && !strands) || (r_children && !children)) + return false; + + if (r_data) *r_data = dobdata; + if (r_strands) *r_strands = strands; + if (r_children) *r_children = children; + if (r_name) *r_name = psys->name; + return true; +} + +static void hairsim_params_init(HairSimParams *params) +{ + params->timescale = 1.0f; + params->substeps = 5; + + params->mass = 0.3f; + params->drag = 0.1f; + + params->stretch_stiffness = 10000.0f; + params->stretch_damping = 0.1f; + params->bend_stiffness = 100.0f; + params->bend_damping = 1.0f; + params->goal_stiffness = 0.0f; + params->goal_damping = 1.0f; + { + CurveMapping *cm = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + cm->cm[0].curve[0].x = 0.0f; + cm->cm[0].curve[0].y = 1.0f; + cm->cm[0].curve[1].x = 1.0f; + cm->cm[0].curve[1].y = 0.0f; + curvemapping_changed_all(cm); + params->goal_stiffness_mapping = cm; + } + { + CurveMapping *cm = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + cm->cm[0].curve[0].x = 0.0f; + cm->cm[0].curve[0].y = 1.0f; + cm->cm[0].curve[1].x = 1.0f; + cm->cm[0].curve[1].y = 1.0f; + curvemapping_changed_all(cm); + params->bend_stiffness_mapping = cm; + } + + params->effector_weights = BKE_add_effector_weights(NULL); +} + +static void hairsim_init(HairSimCacheModifier *hsmd) +{ + hsmd->object = NULL; + hsmd->hair_system = -1; + + hairsim_params_init(&hsmd->sim_params); +} + +static void hairsim_copy(HairSimCacheModifier *hsmd, HairSimCacheModifier *thsmd) +{ + if (hsmd->sim_params.effector_weights) + thsmd->sim_params.effector_weights = MEM_dupallocN(hsmd->sim_params.effector_weights); + if (hsmd->sim_params.goal_stiffness_mapping) + thsmd->sim_params.goal_stiffness_mapping = curvemapping_copy(hsmd->sim_params.goal_stiffness_mapping); + if (hsmd->sim_params.bend_stiffness_mapping) + thsmd->sim_params.bend_stiffness_mapping = curvemapping_copy(hsmd->sim_params.bend_stiffness_mapping); +} + +static void hairsim_free(HairSimCacheModifier *hsmd) +{ + if (hsmd->sim_params.effector_weights) + MEM_freeN(hsmd->sim_params.effector_weights); + if (hsmd->sim_params.goal_stiffness_mapping) + curvemapping_free(hsmd->sim_params.goal_stiffness_mapping); + if (hsmd->sim_params.bend_stiffness_mapping) + curvemapping_free(hsmd->sim_params.bend_stiffness_mapping); +} + +static void hairsim_foreach_id_link(HairSimCacheModifier *hsmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata) +{ + walk(userdata, cachelib, &hsmd->modifier, (ID **)(&hsmd->object)); + if (hsmd->sim_params.effector_weights) + walk(userdata, cachelib, &hsmd->modifier, (ID **)(&hsmd->sim_params.effector_weights->group)); +} + +static void hairsim_process(HairSimCacheModifier *hsmd, CacheProcessContext *ctx, CacheProcessData *data, int frame, int frame_prev, int process_flag) +{ +#define MAX_CACHE_EFFECTORS 64 + + Object *ob = hsmd->object; + Strands *strands; + float mat[4][4]; + ListBase *effectors; + CacheEffector cache_effectors[MAX_CACHE_EFFECTORS]; + int tot_cache_effectors; + struct Implicit_Data *solver_data; + + /* only applies to parent strands */ + if (!(process_flag & eCacheProcessFlag_DoStrands)) + return; + + if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hsmd->hair_system, NULL, &strands, NULL, NULL)) + return; + + /* Note: motion state data should always be created regardless of actual sim. + * This is necessary so the cache writer actually writes the first (empty) sample + * and the samples get mapped correctly to frames when reading. + */ + BKE_strands_add_motion_state(strands); + + /* skip first step and potential backward steps */ + if (frame > frame_prev) { + if (hsmd->sim_params.flag & eHairSimParams_Flag_UseGoalStiffnessCurve && hsmd->sim_params.goal_stiffness_mapping) + curvemapping_changed_all(hsmd->sim_params.goal_stiffness_mapping); + if (hsmd->sim_params.flag & eHairSimParams_Flag_UseBendStiffnessCurve && hsmd->sim_params.bend_stiffness_mapping) + curvemapping_changed_all(hsmd->sim_params.bend_stiffness_mapping); + + if (ob) + mul_m4_m4m4(mat, data->mat, ob->obmat); + else + copy_m4_m4(mat, data->mat); + + BKE_cache_effector_velocity_update(ctx->cachelib, data->dupcache, data->mat, (float)frame); + + solver_data = BPH_strands_solver_create(strands, &hsmd->sim_params); + effectors = pdInitEffectors_ex(ctx->scene, ob, NULL, data->lay, hsmd->sim_params.effector_weights, true); + tot_cache_effectors = BKE_cache_effectors_get(cache_effectors, MAX_CACHE_EFFECTORS, ctx->cachelib, data->dupcache, data->mat); + + BPH_strands_solve(strands, mat, solver_data, &hsmd->sim_params, (float)frame, (float)frame_prev, ctx->scene, effectors, cache_effectors, tot_cache_effectors); + + pdEndEffectors(&effectors); + BKE_cache_effectors_free(cache_effectors, tot_cache_effectors); + BPH_mass_spring_solver_free(solver_data); + } + +#undef MAX_CACHE_EFFECTORS +} + +CacheModifierTypeInfo cacheModifierType_HairSimulation = { + /* name */ "HairSimulation", + /* structName */ "HairSimCacheModifier", + /* structSize */ sizeof(HairSimCacheModifier), + + /* copy */ (CacheModifier_CopyFunc)hairsim_copy, + /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)hairsim_foreach_id_link, + /* process */ (CacheModifier_ProcessFunc)hairsim_process, + /* init */ (CacheModifier_InitFunc)hairsim_init, + /* free */ (CacheModifier_FreeFunc)hairsim_free, +}; + +/* ------------------------------------------------------------------------- */ + +static ForceFieldVertexCache *forcefield_vertex_cache_new(void) +{ + ForceFieldVertexCache *cache = MEM_callocN(sizeof(ForceFieldVertexCache), "force field vertex cache"); + return cache; +} + +static void forcefield_vertex_cache_free(ForceFieldVertexCache *cache) +{ + if (cache->co_prev) + MEM_freeN(cache->co_prev); + if (cache->vel) + MEM_freeN(cache->vel); + MEM_freeN(cache); +} + +static void forcefield_vertex_cache_clear(ForceFieldVertexCache *cache) +{ + if (cache->co_prev) + MEM_freeN(cache->co_prev); + if (cache->vel) + MEM_freeN(cache->vel); + memset(cache, 0, sizeof(ForceFieldVertexCache)); +} + +static void forcefield_vertex_cache_init(ForceFieldVertexCache *cache, float frame, DerivedMesh *dm) +{ + MVert *mvert = dm->getVertArray(dm); + float dframe = frame - cache->frame_prev; + float inv_dframe = dframe > 0.0f ? 1.0f / dframe : 0.0f; + bool has_co_prev = (cache->co_prev != NULL); + int totvert = dm->getNumVerts(dm); + int i; + + if (cache->totvert != totvert) { + forcefield_vertex_cache_clear(cache); + dframe = 0.0f; + } + + if (!cache->co_prev) + cache->co_prev = MEM_mallocN(sizeof(float) * 3 * totvert, "force field vertex cache vertices"); + if (!cache->vel) + cache->vel = MEM_mallocN(sizeof(float) * 3 * totvert, "force field vertex cache vertices"); + + for (i = 0; i < totvert; ++i) { + if (has_co_prev) { + sub_v3_v3v3(cache->vel[i], mvert[i].co, cache->co_prev[i]); + mul_v3_fl(cache->vel[i], inv_dframe); + } + else { + zero_v3(cache->vel[i]); + } + + copy_v3_v3(cache->co_prev[i], mvert[i].co); + } + cache->frame_prev = frame; + cache->totvert = totvert; +} + +static void forcefield_init(ForceFieldCacheModifier *ffmd) +{ + ffmd->object = NULL; + + ffmd->vertex_cache = NULL; + + ffmd->strength = 0.0f; + ffmd->falloff = 1.0f; + ffmd->min_distance = 0.0f; + ffmd->max_distance = 1.0f; +} + +static void forcefield_copy(ForceFieldCacheModifier *UNUSED(ffmd), ForceFieldCacheModifier *tffmd) +{ + tffmd->vertex_cache = NULL; +} + +static void forcefield_free(ForceFieldCacheModifier *ffmd) +{ + if (ffmd->vertex_cache) { + forcefield_vertex_cache_free(ffmd->vertex_cache); + ffmd->vertex_cache = NULL; + } +} + +static void forcefield_foreach_id_link(ForceFieldCacheModifier *ffmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata) +{ + walk(userdata, cachelib, &ffmd->modifier, (ID **)(&ffmd->object)); +} + +CacheModifierTypeInfo cacheModifierType_ForceField = { + /* name */ "ForceField", + /* structName */ "ForceFieldCacheModifier", + /* structSize */ sizeof(ForceFieldCacheModifier), + + /* copy */ (CacheModifier_CopyFunc)forcefield_copy, + /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)forcefield_foreach_id_link, + /* process */ (CacheModifier_ProcessFunc)NULL, + /* init */ (CacheModifier_InitFunc)forcefield_init, + /* free */ (CacheModifier_FreeFunc)forcefield_free, +}; + +/* ------------------------------------------------------------------------- */ + +static void shrinkwrap_init(ShrinkWrapCacheModifier *smd) +{ + smd->object = NULL; + smd->hair_system = -1; +} + +static void shrinkwrap_copy(ShrinkWrapCacheModifier *UNUSED(smd), ShrinkWrapCacheModifier *UNUSED(tsmd)) +{ +} + +static void shrinkwrap_free(ShrinkWrapCacheModifier *UNUSED(smd)) +{ +} + +static void shrinkwrap_foreach_id_link(ShrinkWrapCacheModifier *smd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata) +{ + walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->object)); + walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->target)); +} + +typedef struct ShrinkWrapCacheData { + DerivedMesh *dm; + BVHTreeFromMesh treedata; + + ListBase instances; +} ShrinkWrapCacheData; + +typedef struct ShrinkWrapCacheInstance { + struct ShrinkWrapCacheInstance *next, *prev; + + float mat[4][4]; + float imat[4][4]; +} ShrinkWrapCacheInstance; + +static void shrinkwrap_data_get_bvhtree(ShrinkWrapCacheData *data, DerivedMesh *dm, bool create_bvhtree) +{ + data->dm = CDDM_copy(dm); + if (!data->dm) + return; + + DM_ensure_tessface(data->dm); + CDDM_calc_normals(data->dm); + + if (create_bvhtree) { + bvhtree_from_mesh_faces(&data->treedata, data->dm, 0.0, 2, 6); + } +} + +static void shrinkwrap_data_get_instances(ShrinkWrapCacheData *data, Object *ob, float obmat[4][4], ListBase *duplilist) +{ + if (duplilist) { + DupliObject *dob; + + for (dob = duplilist->first; dob; dob = dob->next) { + ShrinkWrapCacheInstance *inst; + + if (dob->ob != ob) + continue; + + inst = MEM_callocN(sizeof(ShrinkWrapCacheInstance), "shrink wrap instance"); + mul_m4_m4m4(inst->mat, obmat, dob->mat); + invert_m4_m4(inst->imat, inst->mat); + + BLI_addtail(&data->instances, inst); + } + } + else { + ShrinkWrapCacheInstance *inst = MEM_callocN(sizeof(ShrinkWrapCacheInstance), "shrink wrap instance"); + mul_m4_m4m4(inst->mat, obmat, ob->obmat); + invert_m4_m4(inst->imat, inst->mat); + + BLI_addtail(&data->instances, inst); + } +} + +static void shrinkwrap_data_free(ShrinkWrapCacheData *data) +{ + BLI_freelistN(&data->instances); + + free_bvhtree_from_mesh(&data->treedata); + + if (data->dm) { + data->dm->release(data->dm); + } +} + +static void shrinkwrap_apply_vertex(ShrinkWrapCacheModifier *UNUSED(smd), ShrinkWrapCacheData *data, ShrinkWrapCacheInstance *inst, const float *point, float *out) +{ + BVHTreeNearest nearest = {0, }; + float co[3], near_co[3], near_no[3]; + + if (!data->treedata.tree) + return; + + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + + /* lookup in target space */ + mul_v3_m4v3(co, inst->imat, point); + + BLI_bvhtree_find_nearest(data->treedata.tree, co, &nearest, data->treedata.nearest_callback, &data->treedata); + if (nearest.index < 0) + return; + + /* convert back to world space */ + mul_v3_m4v3(near_co, inst->mat, nearest.co); + copy_v3_v3(near_no, nearest.no); + mul_mat3_m4_v3(inst->mat, near_no); + + { + float vec[3]; + + sub_v3_v3v3(vec, point, near_co); + + /* project along the distance vector */ + if (dot_v3v3(vec, near_no) < 0.0f) { + copy_v3_v3(out, near_co); + } + } +} + +static void shrinkwrap_apply(ShrinkWrapCacheModifier *smd, ShrinkWrapCacheData *data, Strands *strands, StrandsChildren *children, bool do_motion) +{ + /* XXX this is not great, the result depends on order of instances in the duplilist ... + * but good enough for single instance use case. + */ + ShrinkWrapCacheInstance *inst; + for (inst = data->instances.first; inst; inst = inst->next) { + + if (strands) { + StrandIterator it_strand; + for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) { + StrandVertexIterator it_vert; + for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) { + if (do_motion && strands->state) + shrinkwrap_apply_vertex(smd, data, inst, it_vert.state->co, it_vert.state->co); + else + shrinkwrap_apply_vertex(smd, data, inst, it_vert.vertex->co, it_vert.vertex->co); + } + } + } + + if (children) { + StrandChildIterator it_strand; + for (BKE_strand_child_iter_init(&it_strand, children); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) { + StrandChildVertexIterator it_vert; + for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) { + shrinkwrap_apply_vertex(smd, data, inst, it_vert.vertex->co, it_vert.vertex->co); + } + } + } + } +} + +static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext *ctx, CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), int process_flag) +{ + bool do_strands_motion = true; + + const bool dupli_target = smd->flag & eShrinkWrapCacheModifier_Flag_InternalTarget; + Object *ob = smd->object; + DupliObject *dob; + Strands *strands = NULL; + DerivedMesh *target_dm; + float mat[4][4]; + + ShrinkWrapCacheData shrinkwrap; + + /* only applies to parent strands */ + if (!(process_flag & eCacheProcessFlag_DoStrands)) + return; + + if (!BKE_cache_modifier_find_strands(data->dupcache, ob, smd->hair_system, NULL, &strands, NULL, NULL)) + return; + + if (dupli_target) { + DupliObjectData *target_data; + if (!BKE_cache_modifier_find_object(data->dupcache, smd->target, &target_data)) + return; + target_dm = target_data->dm; + } + else { + if (!smd->target) + return; + target_dm = mesh_get_derived_final(ctx->scene, smd->target, CD_MASK_BAREMESH); + } + + for (dob = data->dupcache->duplilist.first; dob; dob = dob->next) { + if (dob->ob != ob) + continue; + + memset(&shrinkwrap, 0, sizeof(shrinkwrap)); + shrinkwrap_data_get_bvhtree(&shrinkwrap, target_dm, true); + + if (dupli_target) { + /* instances are calculated relative to the strands object */ + invert_m4_m4(mat, dob->mat); + shrinkwrap_data_get_instances(&shrinkwrap, smd->target, mat, &data->dupcache->duplilist); + } + else { + /* instances are calculated relative to the strands object */ + mul_m4_m4m4(mat, data->mat, dob->mat); + invert_m4(mat); + shrinkwrap_data_get_instances(&shrinkwrap, smd->target, mat, NULL); + } + + shrinkwrap_apply(smd, &shrinkwrap, strands, NULL, do_strands_motion); + + shrinkwrap_data_free(&shrinkwrap); + + /* XXX assume a single instance ... otherwise would just overwrite previous strands data */ + break; + } +} + +CacheModifierTypeInfo cacheModifierType_ShrinkWrap = { + /* name */ "ShrinkWrap", + /* structName */ "ShrinkWrapCacheModifier", + /* structSize */ sizeof(ShrinkWrapCacheModifier), + + /* copy */ (CacheModifier_CopyFunc)shrinkwrap_copy, + /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)shrinkwrap_foreach_id_link, + /* process */ (CacheModifier_ProcessFunc)shrinkwrap_process, + /* init */ (CacheModifier_InitFunc)shrinkwrap_init, + /* free */ (CacheModifier_FreeFunc)shrinkwrap_free, +}; + +/* ------------------------------------------------------------------------- */ + +static void strandskey_init(StrandsKeyCacheModifier *skmd) +{ + skmd->object = NULL; + skmd->hair_system = -1; + + skmd->key = BKE_key_add_ex(NULL, KEY_OWNER_CACHELIB, -1); + skmd->key->type = KEY_RELATIVE; +} + +static void strandskey_copy(StrandsKeyCacheModifier *skmd, StrandsKeyCacheModifier *tskmd) +{ + tskmd->key = BKE_key_copy(skmd->key); + + tskmd->edit = NULL; +} + +static void strandskey_free(StrandsKeyCacheModifier *skmd) +{ + BKE_key_free(skmd->key); + + if (skmd->edit) { + BKE_editstrands_free(skmd->edit); + MEM_freeN(skmd->edit); + skmd->edit = NULL; + } +} + +static void strandskey_foreach_id_link(StrandsKeyCacheModifier *skmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata) +{ + walk(userdata, cachelib, &skmd->modifier, (ID **)(&skmd->object)); +} + +static void strandskey_process(StrandsKeyCacheModifier *skmd, CacheProcessContext *UNUSED(ctx), CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), int process_flag) +{ + const bool use_motion = skmd->flag & eStrandsKeyCacheModifier_Flag_UseMotionState; + Object *ob = skmd->object; + Strands *strands; + KeyBlock *actkb; + float *shape; + + /* only applies to parents */ + if (!(process_flag & eCacheProcessFlag_DoStrands)) + return; + if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands, NULL, NULL)) + return; + if (use_motion && !strands->state) + return; + + actkb = BLI_findlink(&skmd->key->block, skmd->shapenr); + shape = BKE_key_evaluate_strands(strands, skmd->key, actkb, skmd->flag & eStrandsKeyCacheModifier_Flag_ShapeLock, NULL, use_motion); + if (shape) { + StrandsVertex *vert = strands->verts; + StrandsMotionState *state = use_motion ? strands->state : NULL; + int totvert = strands->totverts; + int i; + + float *fp = shape; + for (i = 0; i < totvert; ++i) { + if (state) { + copy_v3_v3(state->co, fp); + ++state; + } + else { + copy_v3_v3(vert->co, fp); + ++vert; + } + fp += 3; + } + + MEM_freeN(shape); + } +} + +CacheModifierTypeInfo cacheModifierType_StrandsKey = { + /* name */ "StrandsKey", + /* structName */ "StrandsKeyCacheModifier", + /* structSize */ sizeof(StrandsKeyCacheModifier), + + /* copy */ (CacheModifier_CopyFunc)strandskey_copy, + /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)strandskey_foreach_id_link, + /* process */ (CacheModifier_ProcessFunc)strandskey_process, + /* init */ (CacheModifier_InitFunc)strandskey_init, + /* free */ (CacheModifier_FreeFunc)strandskey_free, +}; + +KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skmd, Strands *strands, const char *name, const bool from_mix) +{ + const bool use_motion = skmd->flag & eStrandsKeyCacheModifier_Flag_UseMotionState; + Key *key = skmd->key; + KeyBlock *kb; + bool newkey = false; + + if (key == NULL) { + key = skmd->key = BKE_key_add_ex(NULL, KEY_OWNER_CACHELIB, -1); + key->type = KEY_RELATIVE; + newkey = true; + } + else if (BLI_listbase_is_empty(&key->block)) { + newkey = true; + } + + if (newkey || from_mix == false) { + /* create from mesh */ + kb = BKE_keyblock_add_ctime(key, name, false); + BKE_keyblock_convert_from_strands(strands, key, kb, use_motion); + } + else { + /* copy from current values */ + KeyBlock *actkb = BLI_findlink(&skmd->key->block, skmd->shapenr); + bool shape_lock = skmd->flag & eStrandsKeyCacheModifier_Flag_ShapeLock; + int totelem; + float *data = BKE_key_evaluate_strands(strands, key, actkb, shape_lock, &totelem, use_motion); + + /* create new block with prepared data */ + kb = BKE_keyblock_add_ctime(key, name, false); + kb->data = data; + kb->totelem = totelem; + } + + return kb; +} + +bool BKE_cache_modifier_strands_key_get(Object *ob, StrandsKeyCacheModifier **r_skmd, DerivedMesh **r_dm, Strands **r_strands, DupliObjectData **r_dobdata, const char **r_name, float r_mat[4][4]) +{ + CacheLibrary *cachelib = ob->cache_library; + CacheModifier *md; + + if (!cachelib) + return false; + + /* ignore when the object is not actually using the cachelib */ + if (!((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && ob->dup_cache)) + return false; + + for (md = cachelib->modifiers.first; md; md = md->next) { + if (md->type == eCacheModifierType_StrandsKey) { + StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md; + DupliObjectData *dobdata; + + if (BKE_cache_modifier_find_strands(ob->dup_cache, skmd->object, skmd->hair_system, &dobdata, r_strands, NULL, r_name)) { + if (r_skmd) *r_skmd = skmd; + if (r_dm) *r_dm = dobdata->dm; + if (r_dobdata) *r_dobdata = dobdata; + + /* relative transform from the original hair object to the duplicator local space */ + /* XXX bad hack, common problem: we want to display strand edit data in the place of "the" instance, + * but in fact there can be multiple instances of the same dupli object data, so this is ambiguous ... + * For our basic use case, just pick the first dupli instance, assuming that it's the only one. + * ugh ... + */ + if (r_mat) { + DupliObject *dob; + for (dob = ob->dup_cache->duplilist.first; dob; dob = dob->next) { + if (dob->ob == skmd->object) + break; + } + if (dob) { + /* note: plain duplis from the dupli cache list are relative + * to the duplicator already! (not in world space like final duplis) + */ + copy_m4_m4(r_mat, dob->mat); + } + else + unit_m4(r_mat); + } + + return true; + } + } + } + + return false; +} + +/* ------------------------------------------------------------------------- */ + +static void haircut_init(HaircutCacheModifier *hmd) +{ + hmd->object = NULL; + hmd->hair_system = -1; +} + +static void haircut_copy(HaircutCacheModifier *UNUSED(hmd), HaircutCacheModifier *UNUSED(thmd)) +{ +} + +static void haircut_free(HaircutCacheModifier *UNUSED(hmd)) +{ +} + +static void haircut_foreach_id_link(HaircutCacheModifier *smd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata) +{ + walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->object)); + walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->target)); +} + +typedef struct HaircutCacheData { + DerivedMesh *dm; + BVHTreeFromMesh treedata; + + ListBase instances; +} HaircutCacheData; + +typedef struct HaircutCacheInstance { + struct HaircutCacheInstance *next, *prev; + + float mat[4][4]; + float imat[4][4]; +} HaircutCacheInstance; + +static void haircut_data_get_bvhtree(HaircutCacheData *data, DerivedMesh *dm, bool create_bvhtree) +{ + data->dm = CDDM_copy(dm); + if (!data->dm) + return; + + DM_ensure_tessface(data->dm); + CDDM_calc_normals(data->dm); + + if (create_bvhtree) { + bvhtree_from_mesh_faces(&data->treedata, data->dm, 0.0, 2, 6); + } +} + +static void haircut_data_get_instances(HaircutCacheData *data, Object *ob, float obmat[4][4], ListBase *duplilist) +{ + if (duplilist) { + DupliObject *dob; + + for (dob = duplilist->first; dob; dob = dob->next) { + HaircutCacheInstance *inst; + + if (dob->ob != ob) + continue; + + inst = MEM_callocN(sizeof(HaircutCacheInstance), "haircut instance"); + mul_m4_m4m4(inst->mat, obmat, dob->mat); + invert_m4_m4(inst->imat, inst->mat); + + BLI_addtail(&data->instances, inst); + } + } + else { + HaircutCacheInstance *inst = MEM_callocN(sizeof(HaircutCacheInstance), "haircut instance"); + mul_m4_m4m4(inst->mat, obmat, ob->obmat); + invert_m4_m4(inst->imat, inst->mat); + + BLI_addtail(&data->instances, inst); + } +} + +static void haircut_data_free(HaircutCacheData *data) +{ + BLI_freelistN(&data->instances); + + free_bvhtree_from_mesh(&data->treedata); + + if (data->dm) { + data->dm->release(data->dm); + } +} + +/* XXX intersection counting does not work reliably */ +#if 0 +typedef struct PointInsideBVH { + BVHTreeFromMesh bvhdata; + int num_hits; +} PointInsideBVH; + +static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + PointInsideBVH *data = userdata; + + data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit); + + if (hit->index != -1) + ++data->num_hits; +} + +/* true if the point is inside the target mesh */ +static bool haircut_test_point(HaircutCacheModifier *hmd, HaircutCacheData *data, HaircutCacheInstance *inst, const float *v) +{ + const float dir[3] = {1.0f, 0.0f, 0.0f}; + float start[3]; + PointInsideBVH userdata; + + if (!(hmd->cut_mode & eHaircutCacheModifier_CutMode_Enter)) + return false; + + userdata.bvhdata = data->treedata; + userdata.num_hits = 0; + + /* lookup in target space */ + mul_v3_m4v3(start, inst->imat, v); + + BLI_bvhtree_ray_cast_all(data->treedata.tree, start, dir, 0.0f, point_inside_bvh_cb, &userdata); + + /* for any point inside a watertight mesh the number of hits is uneven */ + return (userdata.num_hits % 2) == 1; +} +#else +/* true if the point is inside the target mesh */ +static bool haircut_test_point(HaircutCacheModifier *hmd, HaircutCacheData *data, HaircutCacheInstance *inst, const float *v) +{ + BVHTreeRayHit hit = {0, }; + float start[3], dir[3] = {0.0f, 0.0f, 1.0f}; + bool is_entering; + + if (!(hmd->cut_mode & eHaircutCacheModifier_CutMode_Enter)) + return false; + if (!data->treedata.tree) + return false; + + /* lookup in target space */ + mul_v3_m4v3(start, inst->imat, v); + + hit.index = -1; + hit.dist = FLT_MAX; + + BLI_bvhtree_ray_cast(data->treedata.tree, start, dir, 0.0f, &hit, data->treedata.raycast_callback, &data->treedata); + if (hit.index < 0) { + return false; + } + + mul_mat3_m4_v3(inst->mat, hit.no); + + is_entering = (dot_v3v3(dir, hit.no) < 0.0f); + + return !is_entering; +} +#endif + +static bool haircut_find_segment_cut(HaircutCacheModifier *hmd, HaircutCacheData *data, HaircutCacheInstance *inst, + const float *v1, const float *v2, float *r_lambda) +{ + BVHTreeRayHit hit = {0, }; + float start[3], dir[3], length; + bool is_entering; + + if (!data->treedata.tree) + return false; + + /* lookup in target space */ + mul_v3_m4v3(start, inst->imat, v1); + sub_v3_v3v3(dir, v2, v1); + mul_mat3_m4_v3(inst->imat, dir); + length = normalize_v3(dir); + + if (length == 0.0f) + return false; + + hit.index = -1; + hit.dist = length; + + BLI_bvhtree_ray_cast(data->treedata.tree, start, dir, 0.0f, &hit, data->treedata.raycast_callback, &data->treedata); + if (hit.index < 0) + return false; + + is_entering = (dot_v3v3(dir, hit.no) < 0.0f); + if ((hmd->cut_mode & eHaircutCacheModifier_CutMode_Enter && is_entering) || + (hmd->cut_mode & eHaircutCacheModifier_CutMode_Exit && !is_entering)) + { + if (r_lambda) *r_lambda = len_v3v3(hit.co, start) / length; + return true; + } + + return false; +} + +static bool haircut_find_first_strand_cut(HaircutCacheModifier *hmd, HaircutCacheData *data, StrandChildIterator *it_strand, float *r_cutoff) +{ + StrandChildVertexIterator it_vert; + int vprev = -1; + float cutoff = 0.0f; + + for (BKE_strand_child_vertex_iter_init(&it_vert, it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) { + StrandsChildVertex *verts = it_strand->verts; + bool found_cut = false; + float lambda_min = 1.0f; + HaircutCacheInstance *inst; + + if (it_vert.index == 0) { + for (inst = data->instances.first; inst; inst = inst->next) { + /* test root vertex */ + if (haircut_test_point(hmd, data, inst, verts[it_vert.index].co)) { + if (r_cutoff) *r_cutoff = 0.0f; + return true; + } + } + } + else { + for (inst = data->instances.first; inst; inst = inst->next) { + float lambda; + if (haircut_find_segment_cut(hmd, data, inst, verts[vprev].co, verts[it_vert.index].co, &lambda)) { + found_cut = true; + if (lambda < lambda_min) + lambda_min = lambda; + } + } + + if (found_cut) { + cutoff += lambda_min; + if (r_cutoff) *r_cutoff = cutoff; + return true; + } + else + cutoff += 1.0f; + } + + vprev = it_vert.index; + } + + if (r_cutoff) *r_cutoff = -1.0f; /* indicates "no cutoff" */ + return false; +} + +/* shortens the last visible segment to have exact cutoff length */ +static void haircut_strand_adjust_tip(StrandChildIterator *it_strand, float cutoff) +{ + StrandsChildCurve *curve = it_strand->curve; + + int last, end; + float *a, *b; + float t; + + if (cutoff < 0 || cutoff >= (float)(curve->numverts-1)) + return; + + last = (int)cutoff; + end = last + 1; + BLI_assert(last < curve->numverts); + BLI_assert(end < curve->numverts); + + a = it_strand->verts[last].co; + b = it_strand->verts[end].co; + t = cutoff - floorf(cutoff); + interp_v3_v3v3(b, a, b, t); +} + +static void haircut_apply(HaircutCacheModifier *hmd, CacheProcessContext *UNUSED(ctx), HaircutCacheData *data, StrandsChildren *strands) +{ + StrandChildIterator it_strand; + for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) { + float cutoff = -1.0f; + if (haircut_find_first_strand_cut(hmd, data, &it_strand, &cutoff)) { + it_strand.curve->cutoff = cutoff; + haircut_strand_adjust_tip(&it_strand, cutoff); + } + } +} + +static void haircut_process(HaircutCacheModifier *hmd, CacheProcessContext *ctx, CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), int process_flag) +{ + bool do_strands_children = (process_flag & eCacheProcessFlag_DoStrandsChildren); + const bool dupli_target = hmd->flag & eHaircutCacheModifier_Flag_InternalTarget; + Object *ob = hmd->object; + DupliObject *dob; + StrandsChildren *strands; + DerivedMesh *target_dm; + float mat[4][4]; + + HaircutCacheData haircut; + + /* only applies to children */ + if (!do_strands_children) + return; + if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hmd->hair_system, NULL, NULL, do_strands_children ? &strands : NULL, NULL)) + return; + + if (dupli_target) { + DupliObjectData *target_data; + if (!BKE_cache_modifier_find_object(data->dupcache, hmd->target, &target_data)) + return; + target_dm = target_data->dm; + } + else { + if (!hmd->target) + return; + target_dm = mesh_get_derived_final(ctx->scene, hmd->target, CD_MASK_BAREMESH); + } + + for (dob = data->dupcache->duplilist.first; dob; dob = dob->next) { + if (dob->ob != ob) + continue; + + memset(&haircut, 0, sizeof(haircut)); + haircut_data_get_bvhtree(&haircut, target_dm, true); + if (dupli_target) { + /* instances are calculated relative to the strands object */ + invert_m4_m4(mat, dob->mat); + haircut_data_get_instances(&haircut, hmd->target, mat, &data->dupcache->duplilist); + } + else { + /* instances are calculated relative to the strands object */ + mul_m4_m4m4(mat, data->mat, dob->mat); + invert_m4(mat); + haircut_data_get_instances(&haircut, hmd->target, mat, NULL); + } + + haircut_apply(hmd, ctx, &haircut, strands); + + haircut_data_free(&haircut); + + /* XXX assume a single instance ... otherwise would just overwrite previous strands data */ + break; + } +} + +CacheModifierTypeInfo cacheModifierType_Haircut = { + /* name */ "Haircut", + /* structName */ "HaircutCacheModifier", + /* structSize */ sizeof(HaircutCacheModifier), + + /* copy */ (CacheModifier_CopyFunc)haircut_copy, + /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)haircut_foreach_id_link, + /* process */ (CacheModifier_ProcessFunc)haircut_process, + /* init */ (CacheModifier_InitFunc)haircut_init, + /* free */ (CacheModifier_FreeFunc)haircut_free, +}; + +/* ------------------------------------------------------------------------- */ + +bool BKE_cache_library_uses_key(CacheLibrary *cachelib, Key *key) +{ + CacheModifier *md; + for (md = cachelib->modifiers.first; md; md = md->next) { + if (md->type == eCacheModifierType_StrandsKey) { + StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md; + if (skmd->key == key) + return true; + } + } + return false; +} + +void BKE_cache_modifier_init(void) +{ + cache_modifier_type_set(eCacheModifierType_HairSimulation, &cacheModifierType_HairSimulation); + cache_modifier_type_set(eCacheModifierType_ForceField, &cacheModifierType_ForceField); + cache_modifier_type_set(eCacheModifierType_ShrinkWrap, &cacheModifierType_ShrinkWrap); + cache_modifier_type_set(eCacheModifierType_StrandsKey, &cacheModifierType_StrandsKey); + cache_modifier_type_set(eCacheModifierType_Haircut, &cacheModifierType_Haircut); +} + +/* ========================================================================= */ + +#if 0 +static unsigned int hash_combine(unsigned int kx, unsigned int ky) +{ +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + + unsigned int a, b, c; + + a = b = c = 0xdeadbeef + (2 << 2) + 13; + a += kx; + b += ky; + + c ^= b; c -= rot(b,14); + a ^= c; a -= rot(c,11); + b ^= a; b -= rot(a,25); + c ^= b; c -= rot(b,16); + a ^= c; a -= rot(c,4); + b ^= a; b -= rot(a,14); + c ^= b; c -= rot(b,24); + + return c; + +#undef rot +} + +static unsigned int cache_archive_info_node_hash(const void *key) +{ + const CacheArchiveInfoNode *node = key; + + unsigned int hash = hash_combine(BLI_ghashutil_strhash(node->name), BLI_ghashutil_inthash(node->type)); + if (node->parent_hash != 0) + hash = hash_combine(hash, node->parent_hash); + return hash; +} + +static bool cache_archive_info_node_cmp(const CacheArchiveInfoNode *a, const CacheArchiveInfoNode *b) +{ + if (a->parent_hash != b->parent_hash) + return true; + else if (a->type != b->type) + return true; + else if (!STREQ(a->name, b->name)) + return true; + else + return false; +} +#endif + +static void cache_archive_info_node_free(CacheArchiveInfoNode *node) +{ + CacheArchiveInfoNode *child, *child_next; + for (child = node->child_nodes.first; child; child = child_next) { + child_next = child->next; + cache_archive_info_node_free(child); + } + + MEM_freeN(node); +} + +CacheArchiveInfo *BKE_cache_archive_info_new(void) +{ + CacheArchiveInfo *info = MEM_callocN(sizeof(CacheArchiveInfo), "cache archive info"); + + return info; +} + +void BKE_cache_archive_info_free(CacheArchiveInfo *info) +{ + if (info) { + if (info->root_node) + cache_archive_info_node_free(info->root_node); + + MEM_freeN(info); + } +} + +void BKE_cache_archive_info_clear(CacheArchiveInfo *info) +{ + info->filepath[0] = '\0'; + info->app_name[0] = '\0'; + info->date_written[0] = '\0'; + info->description[0] = '\0'; + + if (info->root_node) { + cache_archive_info_node_free(info->root_node); + info->root_node = NULL; + } +} + +CacheArchiveInfoNode *BKE_cache_archive_info_find_node(CacheArchiveInfo *info, CacheArchiveInfoNode *parent, + eCacheArchiveInfoNode_Type type, const char *name) +{ + if (parent) { + CacheArchiveInfoNode *child; + for (child = parent->child_nodes.first; child; child = child->next) { + if (STREQ(child->name, name) && child->type == type) + return child; + } + } + else if (info->root_node) { + if (STREQ(info->root_node->name, name) && info->root_node->type == type) + return info->root_node; + } + return NULL; +} + +CacheArchiveInfoNode *BKE_cache_archive_info_add_node(CacheArchiveInfo *info, CacheArchiveInfoNode *parent, + eCacheArchiveInfoNode_Type type, const char *name) +{ + CacheArchiveInfoNode *node; + + BLI_assert(parent || !info->root_node); + + node = MEM_callocN(sizeof(CacheArchiveInfoNode), "cache archive info node"); + node->type = type; + BLI_strncpy(node->name, name, sizeof(node->name)); + + /* these values are only optionally calculated, -1 indicates unknown */ + node->bytes_size = -1; + node->array_size = -1; + + if (parent) + BLI_addtail(&parent->child_nodes, node); + else + info->root_node = node; + + return node; +} diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 451656a9bca..87d81a9e921 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -30,16 +30,19 @@ */ #include <stdlib.h> +#include <stddef.h> #include "DNA_camera_types.h" #include "DNA_lamp_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_view3d_types.h" +#include "DNA_ID.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" #include "BKE_animsys.h" #include "BKE_camera.h" @@ -47,6 +50,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "GPU_compositing.h" @@ -71,6 +75,10 @@ void *BKE_camera_add(Main *bmain, const char *name) GPU_fx_compositor_init_dof_settings(&cam->gpu_dof); + /* stereoscopy 3d */ + cam->stereo.interocular_distance = 0.065f; + cam->stereo.convergence_distance = 30.f * 0.065f; + return cam; } @@ -138,7 +146,7 @@ void BKE_camera_make_local(Camera *cam) void BKE_camera_free(Camera *ca) { - BKE_free_animdata((ID *)ca); + BKE_animdata_free((ID *)ca); } /******************************** Camera Usage *******************************/ @@ -213,7 +221,7 @@ void BKE_camera_params_init(CameraParams *params) params->clipend = 100.0f; } -void BKE_camera_params_from_object(CameraParams *params, Object *ob) +void BKE_camera_params_from_object(CameraParams *params, const Object *ob) { if (!ob) return; @@ -255,7 +263,7 @@ void BKE_camera_params_from_object(CameraParams *params, Object *ob) } } -void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView3D *rv3d) +void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d) { /* common */ params->lens = v3d->lens; @@ -274,7 +282,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView params->shiftx *= params->zoom; params->shifty *= params->zoom; - params->zoom = 1.0f / params->zoom; + params->zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params->zoom; } else if (rv3d->persp == RV3D_ORTHO) { /* orthographic view */ @@ -283,13 +291,13 @@ void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView params->clipsta = -params->clipend; params->is_ortho = true; - /* make sure any changes to this match ED_view3d_radius_to_ortho_dist() */ + /* make sure any changes to this match ED_view3d_radius_to_dist_ortho() */ params->ortho_scale = rv3d->dist * sensor_size / v3d->lens; - params->zoom = 2.0f; + params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; } else { /* perspective view */ - params->zoom = 2.0f; + params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; } } @@ -384,8 +392,10 @@ void BKE_camera_params_compute_matrix(CameraParams *params) /***************************** Camera View Frame *****************************/ -void BKE_camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const bool do_clip, const float scale[3], - float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]) +void BKE_camera_view_frame_ex( + const Scene *scene, const Camera *camera, + const float drawsize, const bool do_clip, const float scale[3], + float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]) { float facx, facy; float depth; @@ -456,7 +466,7 @@ void BKE_camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, cons r_vec[3][0] = r_shift[0] - facx; r_vec[3][1] = r_shift[1] + facy; r_vec[3][2] = depth; } -void BKE_camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3]) +void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec[4][3]) { float dummy_asp[2]; float dummy_shift[2]; @@ -502,7 +512,9 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data) data->tot++; } -static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *params, CameraViewFrameData *data) +static void camera_frame_fit_data_init( + const Scene *scene, const Object *ob, + CameraParams *params, CameraViewFrameData *data) { float camera_rotmat_transposed_inversed[4][4]; unsigned int i; @@ -521,7 +533,7 @@ static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *p BKE_camera_params_compute_matrix(params); /* initialize callback data */ - copy_m3_m4(data->camera_rotmat, ob->obmat); + copy_m3_m4(data->camera_rotmat, (float (*)[4])ob->obmat); normalize_m3(data->camera_rotmat); /* To transform a plane which is in its homogeneous representation (4d vector), * we need the inverse of the transpose of the transform matrix... */ @@ -672,7 +684,8 @@ bool BKE_camera_view_frame_fit_to_scene( } bool BKE_camera_view_frame_fit_to_coords( - Scene *scene, float (*cos)[3], int num_cos, Object *camera_ob, float r_co[3], float *r_scale) + const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob, + float r_co[3], float *r_scale) { CameraParams params; CameraViewFrameData data_cb; @@ -690,6 +703,255 @@ bool BKE_camera_view_frame_fit_to_coords( return camera_frame_fit_calc_from_data(¶ms, &data_cb, r_co, r_scale); } +/******************* multiview matrix functions ***********************/ + +static void camera_model_matrix(Object *camera, float r_modelmat[4][4]) +{ + copy_m4_m4(r_modelmat, camera->obmat); +} + +static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4]) +{ + Camera *data = (Camera *)camera->data; + float interocular_distance, convergence_distance; + short convergence_mode, pivot; + float sizemat[4][4]; + + float fac = 1.0f; + float fac_signed; + + interocular_distance = data->stereo.interocular_distance; + convergence_distance = data->stereo.convergence_distance; + convergence_mode = data->stereo.convergence_mode; + pivot = data->stereo.pivot; + + if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) || + ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left)) + { + camera_model_matrix(camera, r_modelmat); + return; + } + else { + float size[3]; + mat4_to_size(size, camera->obmat); + size_to_mat4(sizemat, size); + } + + if (pivot == CAM_S3D_PIVOT_CENTER) + fac = 0.5f; + + fac_signed = is_left ? fac : -fac; + + /* rotation */ + if (convergence_mode == CAM_S3D_TOE) { + float angle; + float angle_sin, angle_cos; + float toeinmat[4][4]; + float rotmat[4][4]; + + unit_m4(rotmat); + + if (pivot == CAM_S3D_PIVOT_CENTER) { + fac = -fac; + fac_signed = -fac_signed; + } + + angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac; + + angle_cos = cosf(angle * fac_signed); + angle_sin = sinf(angle * fac_signed); + + rotmat[0][0] = angle_cos; + rotmat[2][0] = -angle_sin; + rotmat[0][2] = angle_sin; + rotmat[2][2] = angle_cos; + + if (pivot == CAM_S3D_PIVOT_CENTER) { + /* set the rotation */ + copy_m4_m4(toeinmat, rotmat); + /* set the translation */ + toeinmat[3][0] = interocular_distance * fac_signed; + + /* transform */ + normalize_m4_m4(r_modelmat, camera->obmat); + mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat); + + /* scale back to the original size */ + mul_m4_m4m4(r_modelmat, r_modelmat, sizemat); + } + else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */ + /* rotate perpendicular to the interocular line */ + normalize_m4_m4(r_modelmat, camera->obmat); + mul_m4_m4m4(r_modelmat, r_modelmat, rotmat); + + /* translate along the interocular line */ + unit_m4(toeinmat); + toeinmat[3][0] = -interocular_distance * fac_signed; + mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat); + + /* rotate to toe-in angle */ + mul_m4_m4m4(r_modelmat, r_modelmat, rotmat); + + /* scale back to the original size */ + mul_m4_m4m4(r_modelmat, r_modelmat, sizemat); + } + } + else { + normalize_m4_m4(r_modelmat, camera->obmat); + + /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */ + translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f); + + /* scale back to the original size */ + mul_m4_m4m4(r_modelmat, r_modelmat, sizemat); + } +} + +/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */ +void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4]) +{ + BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat); + invert_m4(r_viewmat); +} + +/* left is the default */ +static bool camera_is_left(const char *viewname) +{ + if (viewname && viewname[0] != '\0') { + return !STREQ(viewname, STEREO_RIGHT_NAME); + } + return true; +} + +void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4]) +{ + const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; + + if (!is_multiview) { + camera_model_matrix(camera, r_modelmat); + } + else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) { + camera_model_matrix(camera, r_modelmat); + } + else { /* SCE_VIEWS_SETUP_BASIC */ + const bool is_left = camera_is_left(viewname); + camera_stereo3d_model_matrix(camera, is_left, r_modelmat); + } + normalize_m4(r_modelmat); +} + +static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix) +{ + SceneRenderView *srv; + char name[MAX_NAME]; + const char *camera_name = camera->id.name + 2; + const int len_name = strlen(camera_name); + + name[0] = '\0'; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + const int len_suffix = strlen(srv->suffix); + + if (len_name < len_suffix) + continue; + + if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) { + BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix); + break; + } + } + + if (name[0] != '\0') { + Base *base = BKE_scene_base_find_by_name(scene, name); + if (base) { + return base->object; + } + } + + return camera; +} + +/* returns the camera to be used for render */ +Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname) +{ + const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; + + if (!is_multiview) { + return camera; + } + else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + return camera; + } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname); + return camera_multiview_advanced(scene, camera, suffix); + } +} + +static float camera_stereo3d_shift_x(Object *camera, const char *viewname) +{ + Camera *data = camera->data; + float shift = data->shiftx; + float interocular_distance, convergence_distance; + short convergence_mode, pivot; + bool is_left = true; + + float fac = 1.0f; + float fac_signed; + + if (viewname && viewname[0]) { + is_left = STREQ(viewname, STEREO_LEFT_NAME); + } + + interocular_distance = data->stereo.interocular_distance; + convergence_distance = data->stereo.convergence_distance; + convergence_mode = data->stereo.convergence_mode; + pivot = data->stereo.pivot; + + if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) || + ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left)) + { + return shift; + } + + if (pivot == CAM_S3D_PIVOT_CENTER) + fac = 0.5f; + + fac_signed = is_left ? fac : -fac; + + /* Note: in viewport, parallel renders as offaxis, but in render it does parallel */ + if (ELEM(convergence_mode, CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL)) { + shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) * fac_signed; + } + + return shift; +} + +float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname) +{ + const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; + Camera *data = camera->data; + + BLI_assert(camera->type == OB_CAMERA); + + if (!is_multiview) { + return data->shiftx; + } + else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) { + return data->shiftx; + } + else { /* SCE_VIEWS_SETUP_BASIC */ + return camera_stereo3d_shift_x(camera, viewname); + } +} + +void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname) +{ + if (camera->type == OB_CAMERA) { + params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname); + } +} + void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings) { if (camera->type == OB_CAMERA) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 2a38418f94d..8660f122c10 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -470,7 +470,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int a; if (cddm->pbvh && cddm->pbvh_draw) { - if (dm->numTessFaceData) { + if (BKE_pbvh_has_faces(cddm->pbvh)) { float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL); BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, @@ -527,7 +527,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, * (the same as it'll display without UV maps in textured view) */ if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { - if (dm->numTessFaceData) { + if (BKE_pbvh_has_faces(cddm->pbvh)) { GPU_set_tpage(NULL, false, false); BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false); } @@ -786,14 +786,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, if (tottri == 0) { /* avoid buffer problems in following code */ } - if (setDrawOptions == NULL) { + else if (setDrawOptions == NULL) { /* just draw the entire face array */ glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3); } else { /* we need to check if the next material changes */ int next_actualFace = dm->drawObject->triangle_to_mface[0]; - int prev_mat_nr = -1; + short prev_mat_nr = -1; for (i = 0; i < tottri; i++) { //int actualFace = dm->drawObject->triangle_to_mface[i]; @@ -912,7 +912,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, * works fine for matcap */ if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { - if (dm->numTessFaceData) { + if (BKE_pbvh_has_faces(cddm->pbvh)) { setMaterial(1, &gattribs); BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false); } @@ -927,7 +927,10 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, glShadeModel(GL_SMOOTH); - if (setDrawOptions != NULL) { + /* workaround for NVIDIA GPUs on Mac not supporting vertex arrays + interleaved formats, see T43342 */ + if ((GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_ANY) && (U.gameflags & USER_DISABLE_VBO)) || + setDrawOptions != NULL) + { DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n"); memset(&attribs, 0, sizeof(attribs)); @@ -1082,9 +1085,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, elementsize = GPU_attrib_element_size(datatypes, numdata); buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, false); if (buffer == NULL) { - GPU_buffer_unbind(); buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, true); - return; } varray = GPU_buffer_lock_stream(buffer); if (varray == NULL) { @@ -1245,7 +1246,7 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm, * works fine for matcap */ if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { - if (dm->numTessFaceData) { + if (BKE_pbvh_has_faces(cddm->pbvh)) { setMaterial(userData, 1, &gattribs); BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false); } @@ -2544,16 +2545,16 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; if (LIKELY(v1 != v2)) { - void **eh_p = BLI_edgehash_lookup_p(ehash, v1, v2); + void **val_p; - if (eh_p) { - newe[i] = GET_INT_FROM_POINTER(*eh_p); + if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { + newe[i] = GET_INT_FROM_POINTER(*val_p); } else { STACK_PUSH(olde, i); STACK_PUSH(medge, *med); newe[i] = c; - BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c)); + *val_p = SET_INT_IN_POINTER(c); c++; } } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index bf99992956a..17ed9de91e0 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -370,7 +370,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul mul_m4_v3(ob->obmat, verts->xconst); } - effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true); + effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights); /* Support for dynamic vertex groups, changing from frame to frame */ cloth_apply_vgroup ( clmd, result ); @@ -500,7 +500,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe); if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) { - BPH_cloth_solver_set_positions(clmd); cloth_to_object (ob, clmd, vertexCos); BKE_ptcache_validate(cache, framenr); @@ -779,17 +778,15 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) } } - if (clmd->sim_parms->vgroup_shrink > 0 ) - { - if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink-1)) - { - verts->shrink_factor = clmd->sim_parms->shrink_min*(1.0f-dvert->dw[j].weight)+clmd->sim_parms->shrink_max*dvert->dw [j].weight; // linear interpolation between min and max shrink factor based on weight + if (clmd->sim_parms->vgroup_shrink > 0) { + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) { + /* linear interpolation between min and max shrink factor based on weight */ + verts->shrink_factor = clmd->sim_parms->shrink_min * (1.0f - dvert->dw[j].weight) + clmd->sim_parms->shrink_max * dvert->dw [j].weight; + } + } + else { + verts->shrink_factor = clmd->sim_parms->shrink_min; } - } - else { - verts->shrink_factor = clmd->sim_parms->shrink_min; - } - } } } diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 8846eccc9f3..9ff131157ac 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -953,7 +953,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); for ( ; collpair != collision_end; collpair++ ) { - float margin_distance = collpair->distance - epsilon2; + float margin_distance = (float)(collpair->distance - (double)epsilon2); float impulse[3]; float mag_v_rel; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 89c3e4b0cfc..c5f7e12c9d0 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -994,7 +994,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM copy_v3_v3(rgb, fp); IMB_colormanagement_processor_apply_v3(cm_processor, rgb); - hist->data_luma[i] = rgb_to_luma(rgb); + hist->data_luma[i] = IMB_colormanagement_get_luminance(rgb); hist->data_r[i] = rgb[0]; hist->data_g[i] = rgb[1]; hist->data_b[i] = rgb[2]; @@ -1002,7 +1002,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM } else if (ibuf->rect) { cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x); - hist->data_luma[i] = (float)rgb_to_luma_byte(cp) / 255.0f; + hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f; hist->data_r[i] = (float)cp[0] / 255.0f; hist->data_g[i] = (float)cp[1] / 255.0f; hist->data_b[i] = (float)cp[2] / 255.0f; @@ -1124,7 +1124,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * } /* we still need luma for histogram */ - luma = rgb_to_luma(rgba); + luma = IMB_colormanagement_get_luminance(rgba); /* check for min max */ if (ycc_mode == -1) { @@ -1303,3 +1303,9 @@ void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings * { BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name)); } + +bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1, + const ColorManagedColorspaceSettings *settings2) +{ + return STREQ(settings1->name, settings2->name); +} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c38a1239f12..fa8ab14de06 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4318,7 +4318,7 @@ static void constraints_init_typeinfo(void) /* This function should be used for getting the appropriate type-info when only * a constraint type is known */ -bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type) +const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type) { /* initialize the type-info list? */ if (CTI_INIT) { @@ -4343,7 +4343,7 @@ bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type) /* This function should always be used to get the appropriate type-info, as it * has checks which prevent segfaults in some weird cases. */ -bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con) +const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con) { /* only return typeinfo for valid constraints */ if (con) @@ -4373,7 +4373,7 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_re void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user) { if (con->data) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); if (cti) { /* perform any special freeing constraint may have */ @@ -4447,7 +4447,7 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool static bConstraint *add_new_constraint_internal(const char *name, short type) { bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint"); - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type); const char *newName; /* Set up a generic constraint datablock */ @@ -4574,7 +4574,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use bConstraint *con; for (con = conlist->first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); if (cti) { if (cti->id_looper) @@ -4609,7 +4609,7 @@ void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern) BLI_duplicatelist(dst, src); for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); /* make a new copy of the constraint's data */ con->data = MEM_dupallocN(con->data); @@ -4724,7 +4724,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan) */ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintOb *cob; bConstraintTarget *ct; @@ -4791,7 +4791,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, /* Get the list of targets required for solving a constraint */ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); if (cti && cti->get_constraint_targets) { bConstraintTarget *ct; @@ -4836,7 +4836,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime) /* loop over available constraints, solving and blending them */ for (con = conlist->first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; /* these we can skip completely (invalid constraints...) */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 59f7da83925..b463a1650b7 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -928,6 +928,7 @@ int CTX_data_mode_enum(const bContext *C) else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX; else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE; else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE; + else if (ob->mode & OB_MODE_HAIR_EDIT) return CTX_MODE_HAIR; } } @@ -951,6 +952,7 @@ static const char *data_mode_strings[] = { "vertexpaint", "imagepaint", "particlemode", + "hairmode", "objectmode", NULL }; diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 911bb19a594..392aac13999 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -266,7 +266,7 @@ int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em * modifiers with on cage editing that are enabled and support computing * deform matrices */ for (i = 0; md && i <= cageIndex; i++, md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!editbmesh_modifier_is_enabled(scene, md, dm)) continue; @@ -322,7 +322,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo md = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; @@ -343,7 +343,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo } for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; @@ -377,7 +377,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[ Mesh *me = (Mesh *)ob->data; for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 2b886ef9be9..9f83ffa2577 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -147,7 +147,7 @@ void BKE_curve_free(Curve *cu) BKE_curve_editNurb_free(cu); BKE_curve_unlink(cu); - BKE_free_animdata((ID *)cu); + BKE_animdata_free((ID *)cu); if (cu->mat) MEM_freeN(cu->mat); @@ -1384,6 +1384,30 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float } } +/* forward differencing method for first derivative of cubic bezier curve */ +void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) +{ + float rt0, rt1, rt2, f; + int a; + + f = 1.0f / (float)it; + + rt0 = 3.0f * (q1 - q0); + rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2)); + rt2 = 6.0f * (q0 + q2) - 12.0f * q1; + + q0 = rt0; + q1 = f * (rt1 + rt2); + q2 = 2.0f * f * rt1; + + for (a = 0; a <= it; a++) { + *p = q0; + p = (float *)(((char *)p) + stride); + q0 += q1; + q1 += q2; + } +} + static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3], float p[3], int it, int stride) { @@ -4344,8 +4368,10 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons } else { i = nu->pntsu * nu->pntsv; - for (bp = nu->bp; i--; bp++) + for (bp = nu->bp; i--; bp++) { mul_m4_v3(mat, bp->vec); + bp->radius *= unit_scale; + } } } @@ -4422,9 +4448,6 @@ void BKE_curve_material_index_remove(Curve *cu, int index) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->mat_nr && nu->mat_nr >= index) { nu->mat_nr--; - if (curvetype == OB_CURVE) { - nu->charidx--; - } } } } @@ -4446,9 +4469,6 @@ void BKE_curve_material_index_clear(Curve *cu) for (nu = cu->nurb.first; nu; nu = nu->next) { nu->mat_nr = 0; - if (curvetype == OB_CURVE) { - nu->charidx = 0; - } } } } @@ -4475,9 +4495,6 @@ int BKE_curve_material_index_validate(Curve *cu) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->mat_nr > max_idx) { nu->mat_nr = 0; - if (curvetype == OB_CURVE) { - nu->charidx = 0; - } is_valid = false; } } @@ -4492,6 +4509,54 @@ int BKE_curve_material_index_validate(Curve *cu) } } +void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len) +{ + const int curvetype = BKE_curve_type_get(cu); + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + if (curvetype == OB_FONT) { + struct CharInfo *strinfo; + int charinfo_len, i; + + if (cu->editfont) { + EditFont *ef = cu->editfont; + strinfo = ef->textbufinfo; + charinfo_len = ef->len; + } + else { + strinfo = cu->strinfo; + charinfo_len = cu->len_wchar; + } + + for (i = 0; i <= charinfo_len; i++) { + if (strinfo[i].mat_nr > 0) { + strinfo[i].mat_nr -= 1; + MAT_NR_REMAP(strinfo[i].mat_nr); + strinfo[i].mat_nr += 1; + } + } + } + else { + Nurb *nu; + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + + if (nurbs) { + for (nu = nurbs->first; nu; nu = nu->next) { + MAT_NR_REMAP(nu->mat_nr); + } + } + } + +#undef MAT_NR_REMAP + +} + void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect) { r_rect->xmin = cu->xof + tb->x; @@ -4500,3 +4565,27 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t r_rect->xmax = r_rect->xmin + tb->w; r_rect->ymin = r_rect->ymax - tb->h; } + +/* **** Depsgraph evaluation **** */ + +void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Curve *curve) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, curve->id.name); + } + if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(curve); + } +} + +void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx), + Curve *curve) +{ + /* TODO(sergey): This will probably need to be a part of + * the modifier stack still. + */ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, curve->id.name); + } +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 149dc7c101c..403e815ce5c 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -55,6 +55,7 @@ #include "BKE_customdata.h" #include "BKE_customdata_file.h" +#include "BKE_editstrands.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh_mapping.h" @@ -1091,7 +1092,7 @@ static void layerDefault_mcol(void *data, int count) static void layerDefault_origindex(void *data, int count) { - fill_vn_i((int *)data, count, ORIGINDEX_NONE); + copy_vn_i((int *)data, count, ORIGINDEX_NONE); } static void layerInterp_bweight( @@ -1324,6 +1325,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL}, /* 42: CD_FACEMAP */ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL}, + /* 43: CD_MSURFACE_SAMPLE */ + {sizeof(MSurfaceSample), "MSurfaceSample", 1, NULL, NULL, NULL, NULL, NULL, NULL}, }; /* note, numbers are from trunk and need updating for bmesh */ @@ -1341,6 +1344,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 35-36 */ "CDGridPaintMask", "CDMVertSkin", /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace", /* 39-42 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal", "CDFaceMap", + /* 43 */ "CDMSurfaceSample", }; @@ -1378,6 +1382,17 @@ const CustomDataMask CD_MASK_BMESH = const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */ CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT; +const CustomDataMask CD_MASK_STRANDS = + CD_MASK_MVERT | CD_MASK_MEDGE | + CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MCOL | + CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | + CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | + CD_MASK_MSURFACE_SAMPLE; +const CustomDataMask CD_MASK_STRANDS_BMESH = + CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | + CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS | + CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | + CD_MASK_MSURFACE_SAMPLE; const CustomDataMask CD_MASK_EVERYTHING = CD_MASK_MVERT | CD_MASK_MSTICKY /* DEPRECATED */ | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT | @@ -1389,7 +1404,7 @@ const CustomDataMask CD_MASK_EVERYTHING = /* BMESH ONLY END */ CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; + CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP | CD_MASK_MSURFACE_SAMPLE; static const LayerTypeInfo *layerType_getInfo(int type) { @@ -1554,7 +1569,7 @@ static void CustomData_external_free(CustomData *data) void CustomData_reset(CustomData *data) { memset(data, 0, sizeof(*data)); - fill_vn_i(data->typemap, CD_NUMTYPES, -1); + copy_vn_i(data->typemap, CD_NUMTYPES, -1); } void CustomData_free(CustomData *data, int totelem) @@ -1841,7 +1856,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ newlayerdata = layerdata; } else if (size > 0) { - newlayerdata = MEM_callocN(size, layerType_getName(type)); + if (alloctype == CD_DUPLICATE && layerdata) { + newlayerdata = MEM_mallocN(size, layerType_getName(type)); + } + else { + newlayerdata = MEM_callocN(size, layerType_getName(type)); + } + if (!newlayerdata) return NULL; } @@ -2300,7 +2321,7 @@ void CustomData_interp(const CustomData *source, CustomData *dest, } } - if (count > SOURCE_BUF_SIZE) MEM_freeN(sources); + if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources); } void CustomData_swap(struct CustomData *data, int index, const int *corner_indices) @@ -2832,6 +2853,18 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) return POINTER_OFFSET(block, data->layers[n].offset); } +/*Bmesh Custom Data Functions. Should replace editmesh ones with these as well, due to more effecient memory alloc*/ +void *CustomData_bmesh_get_named(const CustomData *data, void *block, int type, const char *name) +{ + int layer_index; + + /* get the layer index of the named layer of type */ + layer_index = CustomData_get_named_layer_index(data, type, name); + if (layer_index == -1) return NULL; + + return (char *)block + data->layers[layer_index].offset; +} + bool CustomData_layer_has_math(const struct CustomData *data, int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -3858,7 +3891,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTra if (tmp_data_src) { if (UNLIKELY(sources_num > tmp_buff_size)) { tmp_buff_size = (size_t)sources_num; - tmp_data_src = MEM_reallocN(tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size); + tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size); } for (j = 0; j < sources_num; j++) { diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 8f6d4385b55..da00aecf9c0 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -1157,12 +1157,20 @@ bool BKE_object_data_transfer_dm( const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; if (!geom_map_init[VDATA]) { - if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != dm_src->getNumVerts(dm_src))) { + const int num_verts_src = dm_src->getNumVerts(dm_src); + + if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of vertices, " "'Topology' mapping cannot be used in this case"); return changed; } + if (ELEM(0, num_verts_dst, num_verts_src)) { + BKE_report(reports, RPT_ERROR, + "Source or destination meshes do not have any vertices, cannot transfer vertex data"); + return changed; + } + BKE_mesh_remap_calc_verts_from_dm( map_vert_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]); @@ -1197,12 +1205,20 @@ bool BKE_object_data_transfer_dm( const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; if (!geom_map_init[EDATA]) { - if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != dm_src->getNumEdges(dm_src))) { + const int num_edges_src = dm_src->getNumEdges(dm_src); + + if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of edges, " "'Topology' mapping cannot be used in this case"); return changed; } + if (ELEM(0, num_edges_dst, num_edges_src)) { + BKE_report(reports, RPT_ERROR, + "Source or destination meshes do not have any edges, cannot transfer edge data"); + return changed; + } + BKE_mesh_remap_calc_edges_from_dm( map_edge_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst, @@ -1248,12 +1264,20 @@ bool BKE_object_data_transfer_dm( MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); if (!geom_map_init[LDATA]) { - if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != dm_src->getNumLoops(dm_src))) { + const int num_loops_src = dm_src->getNumLoops(dm_src); + + if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of face corners, " "'Topology' mapping cannot be used in this case"); return changed; } + if (ELEM(0, num_loops_dst, num_loops_src)) { + BKE_report(reports, RPT_ERROR, + "Source or destination meshes do not have any polygons, cannot transfer loop data"); + return changed; + } + BKE_mesh_remap_calc_loops_from_dm( map_loop_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, @@ -1298,12 +1322,20 @@ bool BKE_object_data_transfer_dm( CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; if (!geom_map_init[PDATA]) { - if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != dm_src->getNumPolys(dm_src))) { + const int num_polys_src = dm_src->getNumPolys(dm_src); + + if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of faces, " "'Topology' mapping cannot be used in this case"); return changed; } + if (ELEM(0, num_polys_dst, num_polys_src)) { + BKE_report(reports, RPT_ERROR, + "Source or destination meshes do not have any polygons, cannot transfer poly data"); + return changed; + } + BKE_mesh_remap_calc_polys_from_dm( map_poly_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, loops_dst, num_loops_dst, diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 0adea59c245..88885da474b 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -649,7 +649,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ BLI_strncpy(prefix, name, sizeof(prefix)); /* first case; separator . - _ with extensions r R l L */ - if (is_char_sep(name[len - 2])) { + if ((len > 1) && is_char_sep(name[len - 2])) { is_set = true; switch (name[len - 1]) { case 'l': @@ -982,7 +982,7 @@ void BKE_defvert_extract_vgroup_to_vertweights( } } else { - fill_vn_fl(r_weights, invert_vgroup ? 1.0f : 0.0f, num_verts); + copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f); } } @@ -1008,7 +1008,7 @@ void BKE_defvert_extract_vgroup_to_edgeweights( MEM_freeN(tmp_weights); } else { - fill_vn_fl(r_weights, 0.0f, num_edges); + copy_vn_fl(r_weights, num_edges, 0.0f); } } @@ -1031,7 +1031,7 @@ void BKE_defvert_extract_vgroup_to_loopweights( MEM_freeN(tmp_weights); } else { - fill_vn_fl(r_weights, 0.0f, num_loops); + copy_vn_fl(r_weights, num_loops, 0.0f); } } @@ -1060,7 +1060,7 @@ void BKE_defvert_extract_vgroup_to_polyweights( MEM_freeN(tmp_weights); } else { - fill_vn_fl(r_weights, 0.0f, num_polys); + copy_vn_fl(r_weights, num_polys, 0.0f); } } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 00efc28988b..ffaafe94b96 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -45,6 +45,7 @@ #include "BLI_threads.h" #include "DNA_anim_types.h" +#include "DNA_cache_library_types.h" #include "DNA_camera_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" @@ -88,16 +89,25 @@ #include "depsgraph_private.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_debug.h" +#include "DEG_depsgraph_query.h" + +#ifdef WITH_LEGACY_DEPSGRAPH + static SpinLock threaded_update_lock; void DAG_init(void) { BLI_spin_init(&threaded_update_lock); + DEG_register_node_types(); } void DAG_exit(void) { BLI_spin_end(&threaded_update_lock); + DEG_free_node_types(); } /* Queue and stack operations for dag traversal @@ -484,7 +494,7 @@ static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Objec } } -static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, Object *ob, int mask) +static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Object *ob, int mask) { bConstraint *con; DagNode *node; @@ -512,7 +522,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -574,9 +584,9 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti->updateDepgraph) mti->updateDepgraph(md, dag, scene, ob, node); + if (mti->updateDepgraph) mti->updateDepgraph(md, dag, bmain, scene, ob, node); } } if (ob->parent) { @@ -620,8 +630,22 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O /* inverted relation, so addtoroot shouldn't be set to zero */ } + /* XXX Fake dependency: duplicator object becomes a child of group objects. + * This exploits the layer visibility mechanism, making the group objects update + * when the duplicator is visible (even if group objects are not visible themselves). + * It is not a true dependency, the duplicator does not in any way depend on group objects or data! + */ if (ob->transflag & OB_DUPLI) { + /* XXX In theory it would be possible to disable the visibility dependency when dupli groups are cached, + * since we use the results from the cache instead of the generated object data anyway. + * However, the caching system depends a lot on DNA objects currently and behaves unpredictably without this ... + */ +#if 0 + bool is_cached = ob->cache_library && ob->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE; + if (!is_cached && (ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { +#else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { +#endif GroupObject *go; for (go = ob->dup_group->gobject.first; go; go = go->next) { if (go->ob) { @@ -793,7 +817,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O } } - effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false); + effectors = pdInitEffectors_ex(scene, ob, psys, ob->lay, part->effector_weights, false); if (effectors) { for (eff = effectors->first; eff; eff = eff->next) { @@ -827,7 +851,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O /* object constraints */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -895,7 +919,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); } -static void build_dag_group(DagForest *dag, DagNode *scenenode, Scene *scene, Group *group, short mask) +static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask) { GroupObject *go; @@ -905,9 +929,9 @@ static void build_dag_group(DagForest *dag, DagNode *scenenode, Scene *scene, Gr group->id.flag |= LIB_DOIT; for (go = group->gobject.first; go; go = go->next) { - build_dag_object(dag, scenenode, scene, go->ob, mask); + build_dag_object(dag, scenenode, bmain, scene, go->ob, mask); if (go->ob->dup_group) - build_dag_group(dag, scenenode, scene, go->ob->dup_group, mask); + build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask); } } @@ -940,11 +964,11 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask) for (base = sce->base.first; base; base = base->next) { ob = base->object; - build_dag_object(dag, scenenode, sce, ob, mask); + build_dag_object(dag, scenenode, bmain, sce, ob, mask); if (ob->proxy) - build_dag_object(dag, scenenode, sce, ob->proxy, mask); + build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask); if (ob->dup_group) - build_dag_group(dag, scenenode, sce, ob->dup_group, mask); + build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); } BKE_main_id_tag_idcode(bmain, ID_GR, false); @@ -964,6 +988,10 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask) /* also flush custom data mask */ ((Object *)node->ob)->customdata_mask = node->customdata_mask; + + if (node->parent == NULL) { + dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); + } } } /* now set relations equal, so that when only one parent changes, the correct recalcs are found */ @@ -1329,8 +1357,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated)) { - EditorsUpdateIDCb = id_func; - EditorsUpdateSceneCb = scene_func; + if (DEG_depsgraph_use_legacy()) { + EditorsUpdateIDCb = id_func; + EditorsUpdateSceneCb = scene_func; + } + else { + /* New dependency graph. */ + DEG_editors_set_update_cb(id_func, scene_func); + } } static void dag_editors_id_update(Main *bmain, ID *id) @@ -1529,7 +1563,7 @@ static void dag_scene_build(Main *bmain, Scene *sce) Base *base; BLI_listbase_clear(&tempbase); - + build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA); dag_check_cycle(sce->theDag); @@ -1621,32 +1655,65 @@ static void dag_scene_build(Main *bmain, Scene *sce) /* clear all dependency graphs */ void DAG_relations_tag_update(Main *bmain) { - Scene *sce; - - for (sce = bmain->scene.first; sce; sce = sce->id.next) - dag_scene_free(sce); + if (DEG_depsgraph_use_legacy()) { + Scene *sce; + for (sce = bmain->scene.first; sce; sce = sce->id.next) { + dag_scene_free(sce); + } + } + else { + /* New dependency graph. */ + DEG_relations_tag_update(bmain); + } } /* rebuild dependency graph only for a given scene */ void DAG_scene_relations_rebuild(Main *bmain, Scene *sce) { - dag_scene_free(sce); - DAG_scene_relations_update(bmain, sce); + if (DEG_depsgraph_use_legacy()) { + dag_scene_free(sce); + DAG_scene_relations_update(bmain, sce); + } + else { + /* New dependency graph. */ + DEG_scene_relations_rebuild(bmain, sce); + } } /* create dependency graph if it was cleared or didn't exist yet */ void DAG_scene_relations_update(Main *bmain, Scene *sce) { - if (!sce->theDag) - dag_scene_build(bmain, sce); + if (DEG_depsgraph_use_legacy()) { + if (!sce->theDag) + dag_scene_build(bmain, sce); + } + else { + /* New dependency graph. */ + DEG_scene_relations_update(bmain, sce); + } +} + +void DAG_scene_relations_validate(Main *bmain, Scene *sce) +{ + if (!DEG_depsgraph_use_legacy()) { + DEG_debug_scene_relations_validate(bmain, sce); + } } void DAG_scene_free(Scene *sce) { - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; + if (DEG_depsgraph_use_legacy()) { + if (sce->theDag) { + free_forest(sce->theDag); + MEM_freeN(sce->theDag); + sce->theDag = NULL; + } + } + else { + if (sce->depsgraph) { + DEG_graph_free(sce->depsgraph); + sce->depsgraph = NULL; + } } } @@ -1889,7 +1956,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho DagAdjList *itA; Object *ob; int lasttime; - + + if (!DEG_depsgraph_use_legacy()) { + return; + } + if (sce->theDag == NULL) { printf("DAG zero... not allowed to happen!\n"); DAG_scene_relations_update(bmain, sce); @@ -2015,7 +2086,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) if (ob->constraints.first) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2141,6 +2212,10 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) } } + /* invalidate dupli cache */ + if (ob->dup_cache) + ob->dup_cache->flag |= DUPCACHE_FLAG_DIRTY; + if (ob->recalc & OB_RECALC_OB) lib_id_recalc_tag(bmain, &ob->id); if (ob->recalc & OB_RECALC_DATA) @@ -2229,6 +2304,90 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const b } } +void DAG_scene_update_group_flags(Main *bmain, + Scene *scene, + Group *group, + unsigned int lay, + const bool do_time, + const bool do_invisible_flush) +{ + DagNode *root_node = scene->theDag->DagNode.first, *node; + GroupObject *go; + DagNodeQueue *queue; + + /* Tag all possible objects for update. */ + DAG_scene_update_flags(bmain, scene, lay, do_time, do_invisible_flush); + + /* Initialize colors of nodes. */ + for (node = root_node; node != NULL; node = node->next) { + node->color = DAG_WHITE; + node->scheduled = false; + } + + /* Tag nodes which corresponds to objects which are to be updated. */ + for (go = group->gobject.first; go != NULL; go = go->next) { + if (go->ob != NULL) { + node = dag_find_node(scene->theDag, go->ob); + if (node != NULL) { + node->scheduled = true; + } + } + } + + /* Flush schedule flags to parent. */ + queue = queue_create(DAGQUEUEALLOC); + for (node = root_node; node != NULL; node = node->next) { + if (node->color == DAG_WHITE) { + push_stack(queue, node); + node->color = DAG_GRAY; + while (queue->count) { + DagNode *current_node = get_top_node_queue(queue); + DagAdjList *itA; + bool skip = false; + /* Check if all child nodes were scheduled. */ + for (itA = current_node->child; itA; itA = itA->next) { + if (itA->node->color == DAG_WHITE) { + itA->node->color = DAG_GRAY; + push_stack(queue, itA->node); + skip = true; + break; + } + } + /* Check if there are scheduled children and if so schedule + * current node as well since it's needed for chidlren. + */ + if (!skip) { + current_node = pop_queue(queue); + if (current_node->type == ID_OB) { + for (itA = current_node->child; itA; itA = itA->next) { + if (itA->node->scheduled) { + current_node->scheduled = true; + break; + } + } + } + node->color = DAG_BLACK; + } + } + } + } + queue_delete(queue); + + /* Clear recalc flags from objects which corresponds to nodes which are + * not needed for the interesting group update. + */ + for (node = root_node; node != NULL; node = node->next) { + if (node->type == ID_OB) { + Object *object = node->ob; + if (!node->scheduled) { + object->recalc &= ~OB_RECALC_ALL; + } + } + node->color = DAG_WHITE; + node->scheduled = false; + } +} + /* struct returned by DagSceneLayer */ typedef struct DagSceneLayer { struct DagSceneLayer *next, *prev; @@ -2300,7 +2459,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb) } } -static void dag_group_on_visible_update(Group *group) +static void dag_group_on_visible_update(Scene *scene, Group *group) { GroupObject *go; @@ -2322,7 +2481,7 @@ static void dag_group_on_visible_update(Group *group) } if (go->ob->dup_group) - dag_group_on_visible_update(go->ob->dup_group); + dag_group_on_visible_update(scene, go->ob->dup_group); } } @@ -2330,7 +2489,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) { ListBase listbase; DagSceneLayer *dsl; - + + if (!DEG_depsgraph_use_legacy()) { + /* Inform new dependnecy graphs about visibility changes. */ + DEG_on_visible_update(bmain, do_time); + return; + } + /* get list of visible scenes and layers */ dag_current_scene_layers(bmain, &listbase); @@ -2357,7 +2522,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) oblay = (node) ? node->lay : ob->lay; if ((oblay & lay) & ~scene->lay_updated) { - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + /* TODO(sergey): Why do we need armature here now but didn't need before? */ + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) { ob->recalc |= OB_RECALC_DATA; lib_id_recalc_tag(bmain, &ob->id); } @@ -2375,7 +2541,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) lib_id_recalc_tag(bmain, &ob->id); } if (ob->dup_group) - dag_group_on_visible_update(ob->dup_group); + dag_group_on_visible_update(scene, ob->dup_group); } } @@ -2550,7 +2716,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) for (obt = bmain->object.first; obt; obt = obt->id.next) { bConstraint *con; for (con = obt->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { @@ -2600,6 +2766,21 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) } } } + + /* set flags based on CacheLibrary */ + if (idtype == ID_CL) { + for (obt = bmain->object.first; obt; obt = obt->id.next) { + if (!(ob && obt == ob) && ((ID *)obt->cache_library == id)) { + obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA); + lib_id_recalc_tag(bmain, &obt->id); + lib_id_recalc_data_tag(bmain, &obt->id); + + /* invalidate dupli cache */ + if (obt->dup_cache) + obt->dup_cache->flag |= DUPCACHE_FLAG_DIRTY; + } + } + } /* camera's matrix is used to orient reconstructed stuff, * so it should happen tracking-related constraints recalculation @@ -2623,7 +2804,12 @@ void DAG_ids_flush_tagged(Main *bmain) ListBase *lbarray[MAX_LIBARRAY]; int a; bool do_flush = false; - + + if (!DEG_depsgraph_use_legacy()) { + DEG_ids_flush_tagged(bmain); + return; + } + /* get list of visible scenes and layers */ dag_current_scene_layers(bmain, &listbase); @@ -2667,6 +2853,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) int a; bool updated = false; + if (!DEG_depsgraph_use_legacy()) { + DEG_ids_check_recalc(bmain, scene, time); + return; + } + /* loop over all ID types */ a = set_listbasepointers(bmain, lbarray); @@ -2783,6 +2974,11 @@ void DAG_ids_clear_recalc(Main *bmain) void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) { + if (!DEG_depsgraph_use_legacy()) { + DEG_id_tag_update_ex(bmain, id, flag); + return; + } + if (id == NULL) return; if (G.debug & G_DEBUG_DEPSGRAPH) { @@ -2934,7 +3130,7 @@ void DAG_pose_sort(Object *ob) addtoroot = 0; } for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -3174,6 +3370,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object) { DagNode *node; + if (!DEG_depsgraph_use_legacy()) { + return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); + } + if (scene->theDag == NULL) { /* Happens when converting objects to mesh from a python script * after modifying scene graph. @@ -3212,3 +3412,286 @@ bool DAG_is_acyclic(Scene *scene) { return scene->theDag->is_acyclic; } + +#else + +/* ********************************************************************* + * Stubs to avoid linking issues and make sure legacy crap is not used * + * ********************************************************************* + */ + +DagNodeQueue *queue_create(int UNUSED(slots)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +void queue_raz(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void queue_delete(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +DagNode *pop_queue(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagForest *dag_init(void) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagForest *build_dag(Main *UNUSED(bmain), + Scene *UNUSED(sce), + short UNUSED(mask)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +void free_forest(DagForest *UNUSED(Dag)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +void dag_add_relation(DagForest *UNUSED(forest), + DagNode *UNUSED(fob1), + DagNode *UNUSED(fob2), + short UNUSED(rel), + const char *UNUSED(name)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +/* debug test functions */ + +void graph_print_queue(DagNodeQueue *UNUSED(nqueue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void graph_print_adj_list(DagForest *UNUSED(dag)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void DAG_scene_flush_update(Main *UNUSED(bmain), + Scene *UNUSED(sce), + unsigned int UNUSED(lay), + const short UNUSED(time)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +void DAG_scene_update_flags(Main *UNUSED(bmain), + Scene *UNUSED(scene), + unsigned int UNUSED(lay), + const bool UNUSED(do_time), + const bool UNUSED(do_invisible_flush)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +/* ******************* DAG FOR ARMATURE POSE ***************** */ + +void DAG_pose_sort(Object *UNUSED(ob)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); +} + +/* ************************ DAG FOR THREADED UPDATE ********************* */ + +void DAG_threaded_update_begin(Scene *UNUSED(scene), + void (*func)(void *node, void *user_data), + void *UNUSED(user_data)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + (void)func; +} + +void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v), + void (*func)(void *node, void *user_data), + void *UNUSED(user_data)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + (void)func; +} + +/* ************************ DAG querying ********************* */ + +Object *DAG_get_node_object(void *UNUSED(node_v)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return NULL; +} + +const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return "INVALID"; +} + +bool DAG_is_acyclic(Scene *UNUSED(scene)) +{ + BLI_assert(!"Should not be used with new dependnecy graph"); + return false; +} + +/* ************************************ + * This functions are to be supported * + * ************************************ + */ + +void DAG_init(void) +{ + DEG_register_node_types(); +} + +void DAG_exit(void) +{ + DEG_free_node_types(); +} + +/* ************************ API *********************** */ + +void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func, + DEG_EditorUpdateSceneCb scene_func) +{ + DEG_editors_set_update_cb(id_func, scene_func); +} + +/* Tag all relations for update. */ +void DAG_relations_tag_update(Main *bmain) +{ + DEG_relations_tag_update(bmain); +} + +/* Rebuild dependency graph only for a given scene. */ +void DAG_scene_relations_rebuild(Main *bmain, Scene *scene) +{ + DEG_scene_relations_rebuild(bmain, scene); +} + +/* Create dependency graph if it was cleared or didn't exist yet. */ +void DAG_scene_relations_update(Main *bmain, Scene *scene) +{ + DEG_scene_relations_update(bmain, scene); +} + +void DAG_scene_relations_validate(Main *bmain, Scene *scene) +{ + DEG_debug_scene_relations_validate(bmain, scene); +} + +void DAG_scene_free(Scene *scene) +{ + DEG_scene_graph_free(scene); +} + +void DAG_on_visible_update(Main *bmain, const bool do_time) +{ + DEG_on_visible_update(bmain, do_time); +} + +void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) +{ + DEG_ids_check_recalc(bmain, scene, time); +} + +void DAG_id_tag_update(ID *id, short flag) +{ + DEG_id_tag_update_ex(G.main, id, flag); +} + +void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) +{ + DEG_id_tag_update_ex(bmain, id, flag); +} + +void DAG_id_type_tag(Main *bmain, short idtype) +{ + DEG_id_type_tag(bmain, idtype); +} + +int DAG_id_type_tagged(Main *bmain, short idtype) +{ + return DEG_id_type_tagged(bmain, idtype); +} + +void DAG_ids_clear_recalc(Main *bmain) +{ + DEG_ids_clear_recalc(bmain); +} + +short DAG_get_eval_flags_for_object(Scene *scene, void *object) +{ + return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); +} + +void DAG_ids_flush_tagged(Main *bmain) +{ + DEG_ids_flush_tagged(bmain); +} + +/* ************************ DAG DEBUGGING ********************* */ + +void DAG_print_dependencies(Main *UNUSED(bmain), + Scene *scene, + Object *UNUSED(ob)) +{ + DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false); +} + +#endif diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index dd92a82bed2..336d2c1a59b 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -53,6 +53,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_object.h" #include "BKE_mball.h" +#include "BKE_mball_tessellate.h" #include "BKE_curve.h" #include "BKE_key.h" #include "BKE_anim.h" @@ -763,7 +764,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, pretessellatePoint = NULL; for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, required_mode)) continue; @@ -832,7 +833,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, if (pretessellatePoint) { for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -933,7 +934,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, } for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); ModifierApplyFlag appf = app_flag; md->scene = scene; @@ -1164,7 +1165,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final, orcodm = create_orco_dm(scene, ob); for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -1434,9 +1435,8 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu, return; } - if (ELEM(cu->bevfac1_mapping, - CU_BEVFAC_MAP_SEGMENT, - CU_BEVFAC_MAP_SPLINE)) + if (ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) || + ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE)) { for (i = 0; i < SEGMENTSU(nu); i++) { total_length += bl->seglen[i]; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 762b24dfdf8..ce9e85c6813 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -527,7 +527,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int flags, int parent /* also update constraint targets */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { @@ -579,7 +579,7 @@ static void scene_setSubframe(Scene *scene, float subframe) scene->r.subframe = subframe; } -static int surface_getBrushFlags(DynamicPaintSurface *surface, Scene *scene) +static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene) { Base *base = NULL; GroupObject *go = NULL; @@ -1447,7 +1447,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for MEM_freeN(temp_data); } -static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surface) +static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface) { PaintSurfaceData *sData = surface->data; PaintPoint *pPoint = (PaintPoint *)sData->type_data; @@ -1595,7 +1595,7 @@ static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surf } /* clears surface data back to zero */ -void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface) +void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface) { PaintSurfaceData *sData = surface->data; if (sData && sData->type_data) { @@ -1620,7 +1620,7 @@ void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface) } /* completely (re)initializes surface (only for point cache types)*/ -bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface) +bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface) { int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface); /* free existing data */ @@ -1647,7 +1647,7 @@ bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface) } /* make sure allocated surface size matches current requirements */ -static bool dynamicPaint_checkSurfaceData(Scene *scene, DynamicPaintSurface *surface) +static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface) { if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) { return dynamicPaint_resetSurface(scene, surface); @@ -2964,15 +2964,16 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c /** * Mix color values to canvas point. * - * \param surface canvas surface - * \param index surface point index - * \param paintFlags paint object flags - * \param paintColor,Alpha,Wetness to be mixed paint values - * \param timescale value used to adjust time dependent + * \param surface: Canvas surface + * \param index: Surface point index + * \param paintFlags: paint object flags + * \param paintColor,paintAlpha,paintWetness: To be mixed paint values + * \param timescale: Value used to adjust time dependent * operations when using substeps */ -static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags, - const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale) +static void dynamicPaint_mixPaintColors( + DynamicPaintSurface *surface, int index, int paintFlags, + const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale) { PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index]; @@ -4220,7 +4221,7 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s /* Init force data if required */ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { float vel[3] = {0}; - ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true); + ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights); /* allocate memory for force data (dir vector + strength) */ *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces"); @@ -4696,7 +4697,7 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob return ret; } -static int surface_needsVelocityData(DynamicPaintSurface *surface, Scene *scene) +static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene) { if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) return 1; @@ -4716,7 +4717,7 @@ static int surface_needsAccelerationData(DynamicPaintSurface *surface) } /* Prepare for surface step by creating PaintBakeNormal data */ -static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Scene *scene, Object *ob) +static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob) { PaintSurfaceData *sData = surface->data; PaintAdjData *adj_data = sData->adj_data; diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 082edb01efd..fbce501f57f 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -521,8 +521,6 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, GLenum poly_prev = GL_ZERO; GLenum shade_prev = GL_ZERO; - (void)setMaterial; /* UNUSED */ - /* currently unused -- each original face is handled separately */ (void)compareDrawOptions; @@ -539,6 +537,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, } if (bmdm->vertexCos) { + short prev_mat_nr = -1; + /* add direct access */ const float (*vertexCos)[3] = bmdm->vertexCos; const float (*vertexNos)[3]; @@ -569,8 +569,14 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, setDrawOptions(userData, BM_elem_index_get(efa))); if (draw_option != DM_DRAW_OPTION_SKIP) { const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ - if (setMaterial) - setMaterial(efa->mat_nr + 1, NULL); + + if (efa->mat_nr != prev_mat_nr) { + if (setMaterial) { + setMaterial(efa->mat_nr + 1, NULL); + } + prev_mat_nr = efa->mat_nr; + } + if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ if (poly_prev != GL_ZERO) glEnd(); @@ -645,6 +651,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, } } else { + short prev_mat_nr = -1; + BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE); for (i = 0; i < tottri; i++) { @@ -661,8 +669,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, if (draw_option != DM_DRAW_OPTION_SKIP) { const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ - if (setMaterial) - setMaterial(efa->mat_nr + 1, NULL); + if (efa->mat_nr != prev_mat_nr) { + if (setMaterial) { + setMaterial(efa->mat_nr + 1, NULL); + } + prev_mat_nr = efa->mat_nr; + } if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ @@ -985,7 +997,7 @@ static void emDM_drawMappedFacesTex(DerivedMesh *dm, * ... because the material may use layer names to select different UV's * see: [#34378] */ -static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face) +static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face, const int face_index) { BMVert *eve = loop->v; int i; @@ -1028,7 +1040,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col); } if (attribs->tottang) { - int index = i * 4 + index_in_face; + int index = face_index * 4 + index_in_face; const float *tang = (attribs->tang.array) ? attribs->tang.array[index] : zero; glVertexAttrib4fvARB(attribs->tang.gl_index, tang); } @@ -1100,14 +1112,14 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, if (vertexCos) { glNormal3fv(polyNos[BM_elem_index_get(efa)]); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); } } else { glNormal3fv(efa->no); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(ltri[fi]->v->co); } } @@ -1116,7 +1128,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, if (vertexCos) { for (fi = 0; fi < 3; fi++) { const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(vertexNos[j]); glVertex3fv(vertexCos[j]); @@ -1124,7 +1136,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, } else { for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(ltri[fi]->v->no); glVertex3fv(ltri[fi]->v->co); @@ -1204,14 +1216,14 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm, if (vertexCos) { glNormal3fv(polyNos[BM_elem_index_get(efa)]); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); } } else { glNormal3fv(efa->no); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); glVertex3fv(ltri[fi]->v->co); } } @@ -1220,7 +1232,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm, if (vertexCos) { for (fi = 0; fi < 3; fi++) { const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(vertexNos[j]); glVertex3fv(vertexCos[j]); @@ -1228,7 +1240,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm, } else { for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(ltri[fi]->v->no); glVertex3fv(ltri[fi]->v->co); @@ -1968,7 +1980,7 @@ static void statvis_calc_thickness( BLI_assert(min <= max); - fill_vn_fl(face_dists, em->bm->totface, max); + copy_vn_fl(face_dists, em->bm->totface, max); if (use_jit) { int j; @@ -2223,7 +2235,7 @@ static void statvis_calc_sharp( (void)vertexCos; /* TODO */ - fill_vn_fl(vert_angles, em->bm->totvert, -M_PI); + 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) { @@ -2253,7 +2265,7 @@ static void statvis_calc_sharp( } void BKE_editmesh_statvis_calc(BMEditMesh *em, DerivedMesh *dm, - MeshStatVis *statvis) + const MeshStatVis *statvis) { EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; BLI_assert(dm == NULL || dm->type == DM_TYPE_EDITBMESH); diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 2247b91df1d..87a5c6f149f 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -246,3 +246,21 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype) break; } } + +float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3] +{ + BMIter iter; + BMVert *eve; + float (*orco)[3]; + int i; + + orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + copy_v3_v3(orco[i], eve->co); + } + + *r_numVerts = em->bm->totvert; + + return orco; +} diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c new file mode 100644 index 00000000000..fcf98dfc2ee --- /dev/null +++ b/source/blender/blenkernel/intern/editstrands.c @@ -0,0 +1,272 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/editstrands.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_mempool.h" + +#include "DNA_cache_library_types.h" +#include "DNA_customdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_strands_types.h" + +#include "BKE_bvhutils.h" +#include "BKE_cache_library.h" +#include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" +#include "BKE_editstrands.h" +#include "BKE_effect.h" +#include "BKE_mesh_sample.h" +#include "BKE_particle.h" + +#include "BPH_strands.h" + +#include "intern/bmesh_strands_conv.h" + +/* mat can be used to transform the dm into another space, + * in case the edited object is not the active object: + * mat = inv(M_act) * M_edit + */ +BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm, float mat[4][4]) +{ + BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__); + + es->bm = bm; + es->root_dm = CDDM_copy(root_dm); + + if (mat) { + DerivedMesh *dm = es->root_dm; + MVert *mv = dm->getVertArray(dm); + int totvert = dm->getNumVerts(dm), i; + for (i = 0; i < totvert; ++i, ++mv) { + mul_m4_v3(mat, mv->co); + } + } + + return es; +} + +BMEditStrands *BKE_editstrands_copy(BMEditStrands *es) +{ + BMEditStrands *es_copy = MEM_callocN(sizeof(BMEditStrands), __func__); + *es_copy = *es; + + es_copy->bm = BM_mesh_copy(es->bm); + es_copy->root_dm = CDDM_copy(es->root_dm); + + return es_copy; +} + +/** + * \brief Return the BMEditStrands for a given object + */ +BMEditStrands *BKE_editstrands_from_object(Object *ob) +{ + { + ParticleSystem *psys = psys_get_current(ob); + if (psys && psys->hairedit) + return psys->hairedit; + } + + { + StrandsKeyCacheModifier *skmd; + if (BKE_cache_modifier_strands_key_get(ob, &skmd, NULL, NULL, NULL, NULL, NULL)) { + if (skmd->edit) + return skmd->edit; + } + } + + return NULL; +} + +void BKE_editstrands_update_linked_customdata(BMEditStrands *es) +{ + BMesh *bm = es->bm; + + /* this is done for BMEditMesh, but should never exist for strands */ + BLI_assert(!CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)); +} + +/*does not free the BMEditStrands struct itself*/ +void BKE_editstrands_free(BMEditStrands *es) +{ + if (es->bm) + BM_mesh_free(es->bm); + if (es->root_dm) + es->root_dm->release(es->root_dm); +} + +/* === constraints === */ + +BMEditStrandsLocations BKE_editstrands_get_locations(BMEditStrands *edit) +{ + BMesh *bm = edit->bm; + BMEditStrandsLocations locs = MEM_mallocN(3*sizeof(float) * bm->totvert, "editstrands locations"); + + BMVert *v; + BMIter iter; + int i; + + BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, i) { + copy_v3_v3(locs[i], v->co); + } + + return locs; +} + +void BKE_editstrands_free_locations(BMEditStrandsLocations locs) +{ + MEM_freeN(locs); +} + +void BKE_editstrands_solve_constraints(Object *ob, BMEditStrands *es, BMEditStrandsLocations orig) +{ + BKE_editstrands_ensure(es); + + BPH_strands_solve_constraints(ob, es, orig); +} + +static void editstrands_calc_segment_lengths(BMesh *bm) +{ + BMVert *root; + BMIter iter; + + BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) { + BMVert *v, *vprev = NULL; + BMIter iter_strand; + BM_ITER_STRANDS_ELEM(v, &iter_strand, root, BM_VERTS_OF_STRAND) { + if (vprev) { + float length = len_v3v3(v->co, vprev->co); + BM_elem_float_data_named_set(&bm->vdata, vprev, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, length); + } + vprev = v; + } + if (vprev) { + /* set last to 0 */ + BM_elem_float_data_named_set(&bm->vdata, vprev, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, 0.0f); + } + } +} + +void BKE_editstrands_ensure(BMEditStrands *es) +{ + BM_strands_cd_flag_ensure(es->bm, 0); + + if (es->flag & BM_STRANDS_DIRTY_SEGLEN) { + editstrands_calc_segment_lengths(es->bm); + + es->flag &= ~BM_STRANDS_DIRTY_SEGLEN; + } +} + + +/* === cache shape key conversion === */ + +BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, float mat[4][4], int act_key_nr, DerivedMesh *dm) +{ + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_STRANDS(strands); + BMesh *bm; + + DM_ensure_tessface(dm); + + bm = BM_mesh_create(&allocsize); + BM_strands_bm_from_strands(bm, strands, mat, key, dm, true, act_key_nr); + editstrands_calc_segment_lengths(bm); + + return bm; +} + +struct Strands *BKE_cache_strands_from_bmesh(BMEditStrands *edit, struct Key *key, float mat[4][4], DerivedMesh *dm) +{ + BMesh *bm = edit ? edit->bm : NULL; + Strands *strands = NULL; + + if (bm && dm) { + BVHTreeFromMesh bvhtree = {NULL}; + + DM_ensure_tessface(dm); + + bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); + + strands = BM_strands_bm_to_strands(bm, strands, mat, key, dm, &bvhtree); + + free_bvhtree_from_mesh(&bvhtree); + } + + return strands; +} + + +/* === particle conversion === */ + +BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_PSYS(psys); + BMesh *bm; + + bm = BM_mesh_create(&allocsize); + + if (psmd && psmd->dm) { + DM_ensure_tessface(psmd->dm); + + BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, /*psys->shapenr*/ -1); + + editstrands_calc_segment_lengths(bm); + } + + return bm; +} + +void BKE_particles_from_bmesh(Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + BMesh *bm = psys->hairedit ? psys->hairedit->bm : NULL; + + if (bm) { + if (psmd && psmd->dm) { + BVHTreeFromMesh bvhtree = {NULL}; + + DM_ensure_tessface(psmd->dm); + + bvhtree_from_mesh_faces(&bvhtree, psmd->dm, 0.0, 2, 6); + + BM_strands_bm_to_psys(bm, ob, psys, psmd->dm, &bvhtree); + + free_bvhtree_from_mesh(&bvhtree); + } + } +} diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index a9bf499cd65..4842b40bf84 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -203,18 +203,17 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec } /* returns ListBase handle with objects taking part in the effecting */ -ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, - EffectorWeights *weights, bool precalc) +ListBase *pdInitEffectors_ex(Scene *scene, Object *ob_src, ParticleSystem *psys_src, int layers, + EffectorWeights *weights, bool precalc) { Base *base; - unsigned int layer= ob_src->lay; ListBase *effectors = NULL; if (weights->group) { GroupObject *go; for (go= weights->group->gobject.first; go; go= go->next) { - if ( (go->ob->lay & layer) ) { + if ( (go->ob->lay & layers) ) { if ( go->ob->pd && go->ob->pd->forcefield ) add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src); @@ -229,9 +228,9 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src } else { for (base = scene->base.first; base; base= base->next) { - if ( (base->lay & layer) ) { + if ( (base->lay & layers) ) { if ( base->object->pd && base->object->pd->forcefield ) - add_object_to_effectors(&effectors, scene, weights, base->object, ob_src); + add_object_to_effectors(&effectors, scene, weights, base->object, ob_src); if ( base->object->particlesystem.first ) { ParticleSystem *psys= base->object->particlesystem.first; @@ -249,6 +248,12 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src return effectors; } +ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, + EffectorWeights *weights) +{ + return pdInitEffectors_ex(scene, ob_src, psys_src, ob_src->lay, weights, true); +} + void pdEndEffectors(ListBase **effectors) { if (*effectors) { @@ -1125,10 +1130,10 @@ static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem) BLI_ghash_insert(debug_data->gh, elem, elem); } -void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash) +void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], + float r, float g, float b, const char *category, unsigned int hash) { unsigned int category_hash = BLI_ghashutil_strhash_p(category); - SimDebugElement *elem; if (!_sim_debug_data) { if (G.debug & G_DEBUG_SIMDATA) @@ -1137,6 +1142,16 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[ return; } + BKE_sim_debug_data_add_element_ex(_sim_debug_data, type, v1, v2, r, g, b, category_hash, hash); +} + +void BKE_sim_debug_data_add_element_ex(SimDebugData *debug_data, int type, const float v1[3], const float v2[3], + float r, float g, float b, unsigned int category_hash, unsigned int hash) +{ + SimDebugElement *elem; + if (!debug_data) + return; + elem = MEM_callocN(sizeof(SimDebugElement), "sim debug data element"); elem->type = type; elem->category_hash = category_hash; @@ -1147,17 +1162,22 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[ copy_v3_v3(elem->v1, v1); copy_v3_v3(elem->v2, v2); - debug_data_insert(_sim_debug_data, elem); + debug_data_insert(debug_data, elem); } void BKE_sim_debug_data_remove_element(unsigned int hash) { + BKE_sim_debug_data_remove_element_ex(_sim_debug_data, hash); +} + +void BKE_sim_debug_data_remove_element_ex(SimDebugData *debug_data, unsigned int hash) +{ SimDebugElement dummy; - if (!_sim_debug_data) + if (!debug_data) return; dummy.hash = hash; - BLI_ghash_remove(_sim_debug_data->gh, &dummy, NULL, debug_element_free); + BLI_ghash_remove(debug_data->gh, &dummy, NULL, debug_element_free); } void BKE_sim_debug_data_clear(void) @@ -1180,7 +1200,7 @@ void BKE_sim_debug_data_clear_category(const char *category) GHashIterator iter; BLI_ghashIterator_init(&iter, _sim_debug_data->gh); while (!BLI_ghashIterator_done(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */ if (elem->category_hash == category_hash) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 81321b9dbc2..6e58513e38e 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -46,6 +46,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_easing.h" +#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLF_translation.h" @@ -69,6 +70,10 @@ #define SMALL -1.0e-10 #define SELECT 1 +#ifdef WITH_PYTHON +static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; +#endif + /* ************************** Data-Level Functions ************************* */ /* ---------------------- Freeing --------------------------- */ @@ -309,19 +314,23 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, return matches; } -FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt, bAction **action, bool *r_driven) +FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt, + bAction **action, bool *r_driven, bool *r_special) { - return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven); + return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven, r_special); } -FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, - AnimData **animdata, bAction **action, bool *r_driven) +FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **animdata, + bAction **action, bool *r_driven, bool *r_special) { FCurve *fcu = NULL; PointerRNA tptr = *ptr; if (animdata) *animdata = NULL; *r_driven = false; + *r_special = false; + + if (action) *action = NULL; /* there must be some RNA-pointer + property combon */ if (prop && tptr.id.data && RNA_property_animateable(&tptr, prop)) { @@ -342,10 +351,15 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro path = RNA_path_from_ID_to_property(&tptr, prop); } + // XXX: the logic here is duplicated with a function up above if (path) { /* animation takes priority over drivers */ - if (adt->action && adt->action->curves.first) + if (adt->action && adt->action->curves.first) { fcu = list_find_fcurve(&adt->action->curves, path, rnaindex); + + if (fcu && action) + *action = adt->action; + } /* if not animated, check if driven */ if (!fcu && (adt->drivers.first)) { @@ -375,6 +389,32 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro } } } + + /* if we still haven't found anything, check whether it's a "special" property */ + if ((fcu == NULL) && (adt && adt->nla_tracks.first)) { + NlaTrack *nlt; + const char *propname = RNA_property_identifier(prop); + + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + NlaStrip *strip; + + if (fcu) + break; + + /* FIXME: need to do recursive search here for correctness, + * but this will do for most use cases (i.e. interactive editing), + * where nested strips can't be easily edited + */ + for (strip = nlt->strips.first; strip; strip = strip->next) { + fcu = list_find_fcurve(&strip->fcurves, propname, rnaindex); + + if (fcu) { + *r_special = true; + break; + } + } + } + } } MEM_SAFE_FREE(path); } @@ -1496,7 +1536,7 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = { }; /* Get driver variable typeinfo */ -static DriverVarTypeInfo *get_dvar_typeinfo(int type) +static const DriverVarTypeInfo *get_dvar_typeinfo(int type) { /* check if valid type */ if ((type >= 0) && (type < MAX_DVAR_TYPES)) @@ -1540,7 +1580,7 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar) /* Change the type of driver variable */ void driver_change_variable_type(DriverVar *dvar, int type) { - DriverVarTypeInfo *dvti = get_dvar_typeinfo(type); + const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type); /* sanity check */ if (ELEM(NULL, dvar, dvti)) @@ -1664,7 +1704,7 @@ ChannelDriver *fcurve_copy_driver(ChannelDriver *driver) /* Evaluate a Driver Variable to get a value that contributes to the final */ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) { - DriverVarTypeInfo *dvti; + const DriverVarTypeInfo *dvti; /* sanity check */ if (ELEM(NULL, driver, dvar)) @@ -1772,7 +1812,9 @@ static float evaluate_driver(ChannelDriver *driver, const float evaltime) /* this evaluates the expression using Python, and returns its result: * - on errors it reports, then returns 0.0f */ + BLI_mutex_lock(&python_driver_lock); driver->curval = BPY_driver_exec(driver, evaltime); + BLI_mutex_unlock(&python_driver_lock); } #else /* WITH_PYTHON*/ (void)evaltime; diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index af0db5e1c47..6e78d08b508 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -1040,7 +1040,7 @@ static void fmods_init_typeinfo(void) /* This function should be used for getting the appropriate type-info when only * a F-Curve modifier type is known */ -FModifierTypeInfo *get_fmodifier_typeinfo(int type) +const FModifierTypeInfo *get_fmodifier_typeinfo(int type) { /* initialize the type-info list? */ if (FMI_INIT) { @@ -1065,7 +1065,7 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type) /* This function should always be used to get the appropriate type-info, as it * has checks which prevent segfaults in some weird cases. */ -FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm) +const FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm) { /* only return typeinfo for valid modifiers */ if (fcm) @@ -1079,7 +1079,7 @@ FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm) /* Add a new F-Curve Modifier to the given F-Curve of a certain type */ FModifier *add_fmodifier(ListBase *modifiers, int type) { - FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); + const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); FModifier *fcm; /* sanity checks */ @@ -1119,7 +1119,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type) /* Make a copy of the specified F-Modifier */ FModifier *copy_fmodifier(FModifier *src) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src); FModifier *dst; /* sanity check */ @@ -1153,7 +1153,7 @@ void copy_fmodifiers(ListBase *dst, ListBase *src) BLI_duplicatelist(dst, src); for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm; srcfcm = srcfcm->next, fcm = fcm->next) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); /* make a new copy of the F-Modifier's data */ fcm->data = MEM_dupallocN(fcm->data); @@ -1167,7 +1167,7 @@ void copy_fmodifiers(ListBase *dst, ListBase *src) /* Remove and free the given F-Modifier from the given stack */ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); /* sanity check */ if (fcm == NULL) @@ -1266,7 +1266,7 @@ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype) /* find the first mdifier fitting these criteria */ for (fcm = modifiers->first; fcm; fcm = fcm->next) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); short mOk = 1, aOk = 1; /* by default 1, so that when only one test, won't fail */ /* check if applicable ones are fullfilled */ @@ -1296,7 +1296,7 @@ FModifierStackStorage *evaluate_fmodifiers_storage_new(ListBase *modifiers) } for (fcm = modifiers->last; fcm; fcm = fcm->prev) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); if (fmi == NULL) { continue; @@ -1398,7 +1398,10 @@ float evaluate_time_fmodifiers(FModifierStackStorage *storage, ListBase *modifie /* sanity checks */ if (ELEM(NULL, modifiers, modifiers->last)) return evaltime; - + + if (fcu->flag & FCURVE_MOD_OFF) + return evaltime; + /* Starting from the end of the stack, calculate the time effects of various stacked modifiers * on the time the F-Curve should be evaluated at. * @@ -1410,7 +1413,7 @@ float evaluate_time_fmodifiers(FModifierStackStorage *storage, ListBase *modifie * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates) */ for (fcm = modifiers->last; fcm; fcm = fcm->prev) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); if (fmi == NULL) continue; @@ -1455,10 +1458,13 @@ void evaluate_value_fmodifiers(FModifierStackStorage *storage, ListBase *modifie /* sanity checks */ if (ELEM(NULL, modifiers, modifiers->first)) return; + + if (fcu->flag & FCURVE_MOD_OFF) + return; /* evaluate modifiers */ for (fcm = modifiers->first; fcm; fcm = fcm->next) { - FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); if (fmi == NULL) continue; diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index cc9ad63d451..f6c4263cff7 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -179,7 +179,7 @@ static FreestyleLineSet *alloc_lineset(void) return (FreestyleLineSet *)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set"); } -FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name) +FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name) { int lineset_index = BLI_listbase_count(&config->linesets); @@ -187,7 +187,7 @@ FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char BLI_addtail(&config->linesets, (void *)lineset); BKE_freestyle_lineset_set_active_index(config, lineset_index); - lineset->linestyle = BKE_linestyle_new("LineStyle", NULL); + lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle"); lineset->flags |= FREESTYLE_LINESET_ENABLED; lineset->selection = FREESTYLE_SEL_VISIBILITY | FREESTYLE_SEL_EDGE_TYPES | FREESTYLE_SEL_IMAGE_BORDER; lineset->qi = FREESTYLE_QI_VISIBLE; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index dd2155505fb..38a84296ca6 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -119,7 +119,7 @@ void BKE_gpencil_free(bGPdata *gpd) /* free animation data */ if (gpd->adt) { - BKE_free_animdata(&gpd->id); + BKE_animdata_free(&gpd->id); gpd->adt = NULL; } } @@ -129,11 +129,11 @@ void BKE_gpencil_free(bGPdata *gpd) /* add a new gp-frame to the given layer */ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe) { - bGPDframe *gpf, *gf; + bGPDframe *gpf = NULL, *gf = NULL; short state = 0; /* error checking (neg frame only if they are not allowed in Blender!) */ - if ((gpl == NULL) || ((U.flag & USER_NONEGFRAMES) && (cframe <= 0))) + if (gpl == NULL) return NULL; /* allocate memory for this frame */ @@ -160,8 +160,14 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe) /* check whether frame was added successfully */ if (state == -1) { + printf("Error: Frame (%d) existed already for this layer. Using existing frame\n", cframe); + + /* free the newly created one, and use the old one instead */ MEM_freeN(gpf); - printf("Error: frame (%d) existed already for this layer\n", cframe); + + /* return existing frame instead... */ + BLI_assert(gf != NULL); + gpf = gf; } else if (state == 0) { /* add to end then! */ @@ -388,8 +394,6 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew) /* error checking */ if (gpl == NULL) return NULL; - /* No reason to forbid negative frames when they are allowed in Blender! */ - if ((U.flag & USER_NONEGFRAMES) && cframe <= 0) cframe = 1; /* check if there is already an active frame */ if (gpl->actframe) { diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index ae3ab833a87..78f8a42ffe6 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_cache_library_types.h" #include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" @@ -45,7 +46,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" - +#include "BKE_cache_library.h" #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_group.h" @@ -318,7 +319,7 @@ bool BKE_group_is_animated(Group *group, Object *UNUSED(parent)) GroupObject *go; #if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */ - if (parent->nlastrips.first) + if (parent && parent->nlastrips.first) return 1; #endif @@ -385,7 +386,7 @@ void BKE_group_handle_recalc_and_update(EvaluationContext *eval_ctx, Scene *scen * but when its enabled at some point it will need to be changed so as not to update so much - campbell */ /* if animated group... */ - if (parent->nlastrips.first) { + if (parent && parent->nlastrips.first) { int cfrao; /* switch to local time */ diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 8bda957f187..daf39116d76 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLI_string.h" #include "BKE_icons.h" #include "BKE_global.h" /* only for G.background test */ @@ -53,6 +54,10 @@ #include "GPU_extensions.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" +#include "IMB_thumbs.h" + /* GLOBALS */ static GHash *gIcons = NULL; @@ -61,6 +66,7 @@ static int gNextIconId = 1; static int gFirstIconId = 1; +static GHash *gCachedPreviews = NULL; static void icon_free(void *val) { @@ -105,30 +111,50 @@ void BKE_icons_init(int first_dyn_id) gFirstIconId = first_dyn_id; if (!gIcons) - gIcons = BLI_ghash_int_new("icons_init gh"); + gIcons = BLI_ghash_int_new(__func__); + + if (!gCachedPreviews) { + gCachedPreviews = BLI_ghash_str_new(__func__); + } } void BKE_icons_free(void) { - if (gIcons) + if (gIcons) { BLI_ghash_free(gIcons, NULL, icon_free); - gIcons = NULL; + gIcons = NULL; + } + + if (gCachedPreviews) { + BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc); + gCachedPreviews = NULL; + } } -PreviewImage *BKE_previewimg_create(void) +static PreviewImage *previewimg_create_ex(size_t deferred_data_size) { PreviewImage *prv_img = NULL; int i; - prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv"); + prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv"); + memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */ + + if (deferred_data_size) { + prv_img->use_deferred = true; + } for (i = 0; i < NUM_ICON_SIZES; ++i) { - prv_img->changed[i] = 1; + prv_img->flag[i] |= PRV_CHANGED; prv_img->changed_timestamp[i] = 0; } return prv_img; } +PreviewImage *BKE_previewimg_create(void) +{ + return previewimg_create_ex(0); +} + void BKE_previewimg_freefunc(void *link) { PreviewImage *prv = (PreviewImage *)link; @@ -138,7 +164,6 @@ void BKE_previewimg_freefunc(void *link) for (i = 0; i < NUM_ICON_SIZES; ++i) { if (prv->rect[i]) { MEM_freeN(prv->rect[i]); - prv->rect[i] = NULL; } if (prv->gputexture[i]) GPU_texture_free(prv->gputexture[i]); @@ -156,6 +181,26 @@ void BKE_previewimg_free(PreviewImage **prv) } } +void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size) +{ + MEM_SAFE_FREE(prv->rect[size]); + if (prv->gputexture[size]) { + GPU_texture_free(prv->gputexture[size]); + } + prv->h[size] = prv->w[size] = 0; + prv->flag[size] |= PRV_CHANGED; + prv->flag[size] &= ~PRV_USER_EDITED; + prv->changed_timestamp[size] = 0; +} + +void BKE_previewimg_clear(struct PreviewImage *prv) +{ + int i; + for (i = 0; i < NUM_ICON_SIZES; ++i) { + BKE_previewimg_clear_single(prv, i); + } +} + PreviewImage *BKE_previewimg_copy(PreviewImage *prv) { PreviewImage *prv_img = NULL; @@ -167,79 +212,186 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv) if (prv->rect[i]) { prv_img->rect[i] = MEM_dupallocN(prv->rect[i]); } - else { - prv_img->rect[i] = NULL; - } prv_img->gputexture[i] = NULL; } } return prv_img; } -void BKE_previewimg_free_id(ID *id) +PreviewImage **BKE_previewimg_id_get_p(ID *id) { - if (GS(id->name) == ID_MA) { - Material *mat = (Material *)id; - BKE_previewimg_free(&mat->preview); - } - else if (GS(id->name) == ID_TE) { - Tex *tex = (Tex *)id; - BKE_previewimg_free(&tex->preview); - } - else if (GS(id->name) == ID_WO) { - World *wo = (World *)id; - BKE_previewimg_free(&wo->preview); + switch (GS(id->name)) { +#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } + ID_PRV_CASE(ID_MA, Material); + ID_PRV_CASE(ID_TE, Tex); + ID_PRV_CASE(ID_WO, World); + ID_PRV_CASE(ID_LA, Lamp); + ID_PRV_CASE(ID_IM, Image); + ID_PRV_CASE(ID_BR, Brush); +#undef ID_PRV_CASE } - else if (GS(id->name) == ID_LA) { - Lamp *la = (Lamp *)id; - BKE_previewimg_free(&la->preview); - } - else if (GS(id->name) == ID_IM) { - Image *img = (Image *)id; - BKE_previewimg_free(&img->preview); + + return NULL; +} + +void BKE_previewimg_id_free(ID *id) +{ + PreviewImage **prv_p = BKE_previewimg_id_get_p(id); + if (prv_p) { + BKE_previewimg_free(prv_p); } - else if (GS(id->name) == ID_BR) { - Brush *br = (Brush *)id; - BKE_previewimg_free(&br->preview); +} + +PreviewImage *BKE_previewimg_id_ensure(ID *id) +{ + PreviewImage **prv_p = BKE_previewimg_id_get_p(id); + + if (prv_p) { + if (*prv_p == NULL) { + *prv_p = BKE_previewimg_create(); + } + return *prv_p; } + + return NULL; } -PreviewImage *BKE_previewimg_get(ID *id) +PreviewImage *BKE_previewimg_cached_get(const char *name) { - PreviewImage *prv_img = NULL; + return BLI_ghash_lookup(gCachedPreviews, name); +} - if (GS(id->name) == ID_MA) { - Material *mat = (Material *)id; - if (!mat->preview) mat->preview = BKE_previewimg_create(); - prv_img = mat->preview; +/** + * Generate an empty PreviewImage, if not yet existing. + */ +PreviewImage *BKE_previewimg_cached_ensure(const char *name) +{ + PreviewImage *prv = NULL; + void **prv_p; + + if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &prv_p, (GHashKeyCopyFP)BLI_strdup)) { + *prv_p = BKE_previewimg_create(); } - else if (GS(id->name) == ID_TE) { - Tex *tex = (Tex *)id; - if (!tex->preview) tex->preview = BKE_previewimg_create(); - prv_img = tex->preview; + prv = *prv_p; + BLI_assert(prv); + + return prv; +} + +/** + * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing. + */ +PreviewImage *BKE_previewimg_cached_thumbnail_read( + const char *name, const char *path, const int source, bool force_update) +{ + PreviewImage *prv = NULL; + void **prv_p; + + prv_p = BLI_ghash_lookup_p(gCachedPreviews, name); + + if (prv_p) { + prv = *prv_p; + BLI_assert(prv); } - else if (GS(id->name) == ID_WO) { - World *wo = (World *)id; - if (!wo->preview) wo->preview = BKE_previewimg_create(); - prv_img = wo->preview; + + if (prv && force_update) { + const char *prv_deferred_data = PRV_DEFERRED_DATA(prv); + if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) { + /* If same path, no need to re-allocate preview, just clear it up. */ + BKE_previewimg_clear(prv); + } + else { + BKE_previewimg_free(&prv); + } } - else if (GS(id->name) == ID_LA) { - Lamp *la = (Lamp *)id; - if (!la->preview) la->preview = BKE_previewimg_create(); - prv_img = la->preview; + + if (!prv) { + /* We pack needed data for lazy loading (source type, in a single char, and path). */ + const size_t deferred_data_size = strlen(path) + 2; + char *deferred_data; + + prv = previewimg_create_ex(deferred_data_size); + deferred_data = PRV_DEFERRED_DATA(prv); + deferred_data[0] = source; + memcpy(&deferred_data[1], path, deferred_data_size - 1); + + force_update = true; } - else if (GS(id->name) == ID_IM) { - Image *img = (Image *)id; - if (!img->preview) img->preview = BKE_previewimg_create(); - prv_img = img->preview; + + if (force_update) { + if (prv_p) { + *prv_p = prv; + } + else { + BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv); + } } - else if (GS(id->name) == ID_BR) { - Brush *br = (Brush *)id; - if (!br->preview) br->preview = BKE_previewimg_create(); - prv_img = br->preview; + + return prv; +} + +void BKE_previewimg_cached_release(const char *name) +{ + PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); + + if (prv) { + if (prv->icon_id) { + BKE_icon_delete(prv->icon_id); + } + BKE_previewimg_freefunc(prv); } +} - return prv_img; +/** Handle deferred (lazy) loading/generation of preview image, if needed. + * For now, only used with file thumbnails. */ +void BKE_previewimg_ensure(PreviewImage *prv, const int size) +{ + if (prv->use_deferred) { + const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]); + const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]); + + if (do_icon || do_preview) { + ImBuf *thumb; + char *prv_deferred_data = PRV_DEFERRED_DATA(prv); + int source = prv_deferred_data[0]; + char *path = &prv_deferred_data[1]; + int icon_w, icon_h; + + thumb = IMB_thumb_manage(path, THB_LARGE, source); + + if (thumb) { + /* PreviewImage assumes premultiplied alhpa... */ + IMB_premultiply_alpha(thumb); + + if (do_preview) { + prv->w[ICON_SIZE_PREVIEW] = thumb->x; + prv->h[ICON_SIZE_PREVIEW] = thumb->y; + prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect); + prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED); + } + if (do_icon) { + if (thumb->x > thumb->y) { + icon_w = ICON_RENDER_DEFAULT_HEIGHT; + icon_h = (thumb->y * icon_w) / thumb->x + 1; + } + else if (thumb->x < thumb->y) { + icon_h = ICON_RENDER_DEFAULT_HEIGHT; + icon_w = (thumb->x * icon_h) / thumb->y + 1; + } + else { + icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT; + } + + IMB_scaleImBuf(thumb, icon_w, icon_h); + prv->w[ICON_SIZE_ICON] = icon_w; + prv->h[ICON_SIZE_ICON] = icon_h; + prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect); + prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED); + } + IMB_freeImBuf(thumb); + } + } + } } void BKE_icon_changed(int id) @@ -251,20 +403,20 @@ void BKE_icon_changed(int id) icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id)); if (icon) { - PreviewImage *prv = BKE_previewimg_get((ID *)icon->obj); + PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj); /* all previews changed */ if (prv) { int i; for (i = 0; i < NUM_ICON_SIZES; ++i) { - prv->changed[i] = 1; + prv->flag[i] |= PRV_CHANGED; prv->changed_timestamp[i]++; } } } } -int BKE_icon_getid(struct ID *id) +int BKE_icon_id_ensure(struct ID *id) { Icon *new_icon = NULL; @@ -277,11 +429,11 @@ int BKE_icon_getid(struct ID *id) id->icon_id = get_next_free_id(); if (!id->icon_id) { - printf("BKE_icon_getid: Internal error - not enough IDs\n"); + printf("%s: Internal error - not enough IDs\n", __func__); return 0; } - new_icon = MEM_callocN(sizeof(Icon), "texicon"); + new_icon = MEM_mallocN(sizeof(Icon), __func__); new_icon->obj = id; new_icon->type = GS(id->name); @@ -295,6 +447,40 @@ int BKE_icon_getid(struct ID *id) return id->icon_id; } +/** + * Return icon id of given preview, or create new icon if not found. + */ +int BKE_icon_preview_ensure(PreviewImage *preview) +{ + Icon *new_icon = NULL; + + if (!preview || G.background) + return 0; + + if (preview->icon_id) + return preview->icon_id; + + preview->icon_id = get_next_free_id(); + + if (!preview->icon_id) { + printf("%s: Internal error - not enough IDs\n", __func__); + return 0; + } + + new_icon = MEM_mallocN(sizeof(Icon), __func__); + + new_icon->obj = preview; + new_icon->type = 0; /* Special, tags as non-ID icon/preview. */ + + /* next two lines make sure image gets created */ + new_icon->drawinfo = NULL; + new_icon->drawinfo_free = NULL; + + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon); + + return preview->icon_id; +} + Icon *BKE_icon_get(int icon_id) { Icon *icon = NULL; @@ -302,7 +488,7 @@ Icon *BKE_icon_get(int icon_id) icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); if (!icon) { - printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id); + printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id); return NULL; } @@ -311,23 +497,42 @@ Icon *BKE_icon_get(int icon_id) void BKE_icon_set(int icon_id, struct Icon *icon) { - Icon *old_icon = NULL; + void **val_p; - old_icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); - - if (old_icon) { - printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id); + if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) { + printf("%s: Internal error, icon already set: %d\n", __func__, icon_id); return; } - BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), icon); + *val_p = icon; } -void BKE_icon_delete(struct ID *id) +void BKE_icon_id_delete(struct ID *id) { - if (!id->icon_id) return; /* no icon defined for library object */ BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free); id->icon_id = 0; } + +/** + * Remove icon and free data. + */ +void BKE_icon_delete(int icon_id) +{ + Icon *icon; + + if (!icon_id) return; /* no icon defined for library object */ + + icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL); + + if (icon) { + if (icon->type) { + ((ID *)(icon->obj))->icon_id = 0; + } + else { + ((PreviewImage *)(icon->obj))->icon_id = 0; + } + icon_free(icon); + } +} diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 1b7a03ec80e..47a4414f324 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -53,6 +53,7 @@ static IDType idtypes[] = { { ID_AC, "Action", "actions", IDTYPE_FLAGS_ISLINKABLE }, { ID_AR, "Armature", "armatures", IDTYPE_FLAGS_ISLINKABLE }, { ID_BR, "Brush", "brushes", IDTYPE_FLAGS_ISLINKABLE }, + { ID_CL, "CacheLibrary", "cache_libraries", IDTYPE_FLAGS_ISLINKABLE }, { ID_CA, "Camera", "cameras", IDTYPE_FLAGS_ISLINKABLE }, { ID_CU, "Curve", "curves", IDTYPE_FLAGS_ISLINKABLE }, { ID_GD, "GPencil", "grease_pencil", IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 9be09e99bcc..09934c872f7 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -75,6 +75,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_packedFile.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_node.h" #include "BKE_sequencer.h" /* seq_foreground_frame_get() */ @@ -99,6 +100,12 @@ static SpinLock image_spin; +/* prototypes */ +static size_t image_num_files(struct Image *ima); +static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock); +static void image_update_views_format(Image *ima, ImageUser *iuser); +static void image_add_view(Image *ima, const char *viewname, const char *filepath); + /* max int, to indicate we don't store sequences in ibuf */ #define IMA_NO_INDEX 0x7FEFEFEF @@ -257,6 +264,46 @@ static void image_free_cached_frames(Image *image) } } +static void image_free_packedfiles(Image *ima) +{ + while (ima->packedfiles.last) { + ImagePackedFile *imapf = ima->packedfiles.last; + if (imapf->packedfile) { + freePackedFile(imapf->packedfile); + } + BLI_remlink(&ima->packedfiles, imapf); + MEM_freeN(imapf); + } +} + +void BKE_image_free_packedfiles(Image *ima) +{ + image_free_packedfiles(ima); +} + +static void image_free_views(Image *ima) +{ + BLI_freelistN(&ima->views); +} + +void BKE_image_free_views(Image *image) +{ + image_free_views(image); +} + +static void image_free_anims(Image *ima) +{ + while (ima->anims.last) { + ImageAnim *ia = ima->anims.last; + if (ia->anim) { + IMB_free_anim(ia->anim); + ia->anim = NULL; + } + BLI_remlink(&ima->anims, ia); + MEM_freeN(ia); + } +} + /** * Simply free the image data from memory, * on display the image can load again (except for render buffers). @@ -265,8 +312,7 @@ void BKE_image_free_buffers(Image *ima) { image_free_cached_frames(ima); - if (ima->anim) IMB_free_anim(ima->anim); - ima->anim = NULL; + image_free_anims(ima); if (ima->rr) { RE_FreeRenderResult(ima->rr); @@ -290,11 +336,10 @@ void BKE_image_free(Image *ima) int a; BKE_image_free_buffers(ima); - if (ima->packedfile) { - freePackedFile(ima->packedfile); - ima->packedfile = NULL; - } - BKE_icon_delete(&ima->id); + + image_free_packedfiles(ima); + + BKE_icon_id_delete(&ima->id); ima->id.icon_id = 0; BKE_previewimg_free(&ima->preview); @@ -305,6 +350,9 @@ void BKE_image_free(Image *ima) ima->renders[a] = NULL; } } + + image_free_views(ima); + MEM_freeN(ima->stereo3d_format); } /* only image block itself */ @@ -328,7 +376,9 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ ima->flag |= IMA_VIEW_AS_RENDER; BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings); + ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format"); } + return ima; } @@ -359,6 +409,22 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) } } +static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) +{ + const ImagePackedFile *imapf_src; + + BLI_listbase_clear(lb_dst); + for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) { + ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)"); + BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath)); + + if (imapf_src->packedfile) + imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile); + + BLI_addtail(lb_dst, imapf_dst); + } +} + /* empty image block, of similar type and filename */ Image *BKE_image_copy(Main *bmain, Image *ima) { @@ -381,8 +447,10 @@ Image *BKE_image_copy(Main *bmain, Image *ima) BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings); - if (ima->packedfile) - nima->packedfile = dupPackedFile(ima->packedfile); + copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles); + + nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format); + BLI_duplicatelist(&nima->views, &ima->views); if (ima->id.lib) { BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id); @@ -686,7 +754,9 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists) BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id)); if (BLI_path_cmp(strtest, str) == 0) { - if (ima->anim == NULL || ima->id.us == 0) { + if ((BKE_image_has_anim(ima) == false) || + (ima->id.us == 0)) + { ima->id.us++; /* officially should not, it doesn't link here! */ if (ima->ok == 0) ima->ok = IMA_OK; @@ -774,13 +844,14 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char } /* adds new image block, creates ImBuf and initializes color */ -Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4]) +Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d) { /* on save, type is changed to FILE in editsima.c */ Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST); if (ima) { - ImBuf *ibuf; + size_t view_id; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; /* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */ ima->gen_x = width; @@ -790,13 +861,21 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei ima->gen_depth = depth; copy_v4_v4(ima->gen_color, color); - ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings); - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + for (view_id = 0; view_id < 2; view_id++) { + ImBuf *ibuf; + ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings); + image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0); - /* image_assign_ibuf puts buffer to the cache, which increments user counter. */ - IMB_freeImBuf(ibuf); + /* image_assign_ibuf puts buffer to the cache, which increments user counter. */ + IMB_freeImBuf(ibuf); + if (!stereo3d) break; + + image_add_view(ima, names[view_id], ""); + } ima->ok = IMA_OK_LOADED; + if (stereo3d) + ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW; } return ima; @@ -805,12 +884,16 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei /* Create an image image from ibuf. The refcount of ibuf is increased, * caller should take care to drop its reference by calling * IMB_freeImBuf if needed. */ -Image *BKE_image_add_from_imbuf(ImBuf *ibuf) +Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name) { /* on save, type is changed to FILE in editsima.c */ Image *ima; - ima = image_alloc(G.main, BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE); + if (name == NULL) { + name = BLI_path_basename(ibuf->name); + } + + ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE); if (ima) { BLI_strncpy(ima->name, ibuf->name, FILE_MAX); @@ -821,18 +904,79 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf) return ima; } +/* packs rects from memory as PNG + * convert multiview images to R_IMF_VIEWS_INDIVIDUAL + */ +static void image_memorypack_multiview(Image *ima) +{ + ImageView *iv; + size_t i; + + image_free_packedfiles(ima); + + for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) { + ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0); + + ibuf->ftype = PNG; + ibuf->planes = R_IMF_PLANES_RGBA; + + /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */ + if (ima->views_format == R_IMF_VIEWS_STEREO_3D) { + const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX}; + BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], ""); + } + + IMB_saveiff(ibuf, iv->filepath, IB_rect | IB_mem); + + if (ibuf->encodedbuffer == NULL) { + printf("memory save for pack error\n"); + IMB_freeImBuf(ibuf); + image_free_packedfiles(ima); + return; + } + else { + ImagePackedFile *imapf; + PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); + + pf->data = ibuf->encodedbuffer; + pf->size = ibuf->encodedsize; + + imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"); + BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + imapf->packedfile = pf; + BLI_addtail(&ima->packedfiles, imapf); + + ibuf->encodedbuffer = NULL; + ibuf->encodedsize = 0; + ibuf->userflags &= ~IB_BITMAPDIRTY; + } + IMB_freeImBuf(ibuf); + } + + if (ima->source == IMA_SRC_GENERATED) { + ima->source = IMA_SRC_FILE; + ima->type = IMA_TYPE_IMAGE; + } + ima->views_format = R_IMF_VIEWS_INDIVIDUAL; +} + /* packs rect from memory as PNG */ void BKE_image_memorypack(Image *ima) { - ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); + ImBuf *ibuf; - if (ibuf == NULL) + if ((ima->flag & IMA_IS_MULTIVIEW)) { + image_memorypack_multiview(ima); return; - if (ima->packedfile) { - freePackedFile(ima->packedfile); - ima->packedfile = NULL; } + ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); + + if (ibuf == NULL) + return; + + image_free_packedfiles(ima); + ibuf->ftype = PNG; ibuf->planes = R_IMF_PLANES_RGBA; @@ -841,11 +985,17 @@ void BKE_image_memorypack(Image *ima) printf("memory save for pack error\n"); } else { + ImagePackedFile *imapf; PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); pf->data = ibuf->encodedbuffer; pf->size = ibuf->encodedsize; - ima->packedfile = pf; + + imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"); + BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + imapf->packedfile = pf; + BLI_addtail(&ima->packedfiles, imapf); + ibuf->encodedbuffer = NULL; ibuf->encodedsize = 0; ibuf->userflags &= ~IB_BITMAPDIRTY; @@ -859,6 +1009,53 @@ void BKE_image_memorypack(Image *ima) IMB_freeImBuf(ibuf); } +void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath) +{ + const size_t totfiles = image_num_files(ima); + + if (totfiles == 1) { + ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"); + BLI_addtail(&ima->packedfiles, imapf); + imapf->packedfile = newPackedFile(reports, ima->name, basepath); + if (imapf->packedfile) { + BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + } + else { + BLI_freelinkN(&ima->packedfiles, imapf); + } + } + else { + ImageView *iv; + for (iv = ima->views.first; iv; iv = iv->next) { + ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"); + BLI_addtail(&ima->packedfiles, imapf); + + imapf->packedfile = newPackedFile(reports, iv->filepath, basepath); + if (imapf->packedfile) { + BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath)); + } + else { + BLI_freelinkN(&ima->packedfiles, imapf); + } + } + } +} + +void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len) +{ + const size_t totfiles = image_num_files(ima); + + if (totfiles != 1) { + BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently..."); + } + else { + ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__); + BLI_addtail(&ima->packedfiles, imapf); + imapf->packedfile = newPackedFileMemory(data, data_len); + BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath)); + } +} + void BKE_image_tag_time(Image *ima) { ima->lastused = PIL_check_seconds_timer_i(); @@ -1259,7 +1456,7 @@ char BKE_imtype_from_arg(const char *imtype_arg) else return R_IMF_IMTYPE_INVALID; } -static bool image_path_ensure_ext(char *string, const char imtype, const ImageFormatData *im_format) +static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format) { const char *extension = NULL; const char *extension_test; @@ -1311,7 +1508,7 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo } #endif #ifdef WITH_OPENEXR - else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) { + else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) { if (!BLI_testextensie(string, extension_test = ".exr")) extension = extension_test; } @@ -1369,14 +1566,14 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo } } -bool BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format) +int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format) { - return image_path_ensure_ext(string, im_format->imtype, im_format); + return do_add_image_extension(string, im_format->imtype, im_format); } -bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype) +int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype) { - return image_path_ensure_ext(string, imtype, NULL); + return do_add_image_extension(string, imtype, NULL); } void BKE_imformat_defaults(ImageFormatData *im_format) @@ -1861,28 +2058,65 @@ void BKE_image_stamp_buf( #undef BUFF_MARGIN_Y } -void BKE_imbuf_stamp_info(Scene *scene, Object *camera, struct ImBuf *ibuf) +void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderResult *rr) { - struct StampData stamp_data; + struct StampData *stamp_data; + + if (!(scene && scene->r.stamp & R_STAMP_ALL)) + return; + + if (!rr->stamp_data) { + stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data"); + } + else { + stamp_data = rr->stamp_data; + } - if (!ibuf) return; + stampdata(scene, camera, stamp_data, 0); - /* fill all the data values, no prefix */ - stampdata(scene, camera, &stamp_data, 0); + if (!rr->stamp_data) { + rr->stamp_data = stamp_data; + } +} - if (stamp_data.file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data.file); - if (stamp_data.note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data.note); - if (stamp_data.date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data.date); - if (stamp_data.marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data.marker); - if (stamp_data.time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data.time); - if (stamp_data.frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data.frame); - if (stamp_data.camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data.camera); - if (stamp_data.cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data.cameralens); - if (stamp_data.scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data.scene); - if (stamp_data.strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data.strip); - if (stamp_data.rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data.rendertime); + +void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf) +{ + struct StampData *stamp_data = rr->stamp_data; + + if (!ibuf || !stamp_data) return; + + if (stamp_data->file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data->file); + if (stamp_data->note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data->note); + if (stamp_data->date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data->date); + if (stamp_data->marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data->marker); + if (stamp_data->time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data->time); + if (stamp_data->frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data->frame); + if (stamp_data->camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data->camera); + if (stamp_data->cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data->cameralens); + if (stamp_data->scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data->scene); + if (stamp_data->strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data->strip); + if (stamp_data->rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data->rendertime); } +void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback) +{ + if (!callback || !stamp_data) return; + + if (stamp_data->file[0]) callback(data, "File", stamp_data->file); + if (stamp_data->note[0]) callback(data, "Note", stamp_data->note); + if (stamp_data->date[0]) callback(data, "Date", stamp_data->date); + if (stamp_data->marker[0]) callback(data, "Marker", stamp_data->marker); + if (stamp_data->time[0]) callback(data, "Time", stamp_data->time); + if (stamp_data->frame[0]) callback(data, "Frame", stamp_data->frame); + if (stamp_data->camera[0]) callback(data, "Camera", stamp_data->camera); + if (stamp_data->cameralens[0]) callback(data, "Lens", stamp_data->cameralens); + if (stamp_data->scene[0]) callback(data, "Scene", stamp_data->scene); + if (stamp_data->strip[0]) callback(data, "Strip", stamp_data->strip); + if (stamp_data->rendertime[0]) callback(data, "RenderTime", stamp_data->rendertime); +} + + bool BKE_imbuf_alpha_test(ImBuf *ibuf) { int tot; @@ -1908,14 +2142,12 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf) /* note: imf->planes is ignored here, its assumed the image channels * are already set */ -int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) +void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf) { char imtype = imf->imtype; char compress = imf->compress; char quality = imf->quality; - int ok; - if (imtype == R_IMF_IMTYPE_IRIS) { ibuf->ftype = IMAGIC; } @@ -1952,7 +2184,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) } #endif #ifdef WITH_OPENEXR - else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) { + else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) { ibuf->ftype = OPENEXR; if (imf->depth == R_IMF_CHAN_DEPTH_16) ibuf->ftype |= OPENEXR_HALF; @@ -2036,6 +2268,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) if (quality < 10) quality = 90; ibuf->ftype = JPG | quality; } +} + +int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) +{ + int ok; + + BKE_imbuf_write_prepare(ibuf, imf); BLI_make_existing_file(name); @@ -2070,18 +2309,18 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, return ok; } -int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, const char *name, struct ImageFormatData *imf) +int BKE_imbuf_write_stamp(Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name, struct ImageFormatData *imf) { if (scene && scene->r.stamp & R_STAMP_ALL) - BKE_imbuf_stamp_info(scene, camera, ibuf); + BKE_imbuf_stamp_info(rr, ibuf); return BKE_imbuf_write(ibuf, name, imf); } - -static void image_path_makepicstring( +static void do_makepicstring( char *string, const char *base, const char *relbase, int frame, const char imtype, - const ImageFormatData *im_format, const short use_ext, const short use_frames) + const ImageFormatData *im_format, const short use_ext, const short use_frames, + const char *suffix) { if (string == NULL) return; BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */ @@ -2090,22 +2329,25 @@ static void image_path_makepicstring( if (use_frames) BLI_path_frame(string, frame, 4); + if (suffix) + BLI_path_suffix(string, FILE_MAX, suffix, ""); + if (use_ext) - image_path_ensure_ext(string, imtype, im_format); + do_add_image_extension(string, imtype, im_format); } void BKE_image_path_from_imformat( char *string, const char *base, const char *relbase, int frame, - const ImageFormatData *im_format, const bool use_ext, const bool use_frames) + const ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix) { - image_path_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames); + do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix); } void BKE_image_path_from_imtype( char *string, const char *base, const char *relbase, int frame, - const char imtype, const bool use_ext, const bool use_frames) + const char imtype, const bool use_ext, const bool use_frames, const char *view) { - image_path_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames); + do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames, view); } struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]) @@ -2181,6 +2423,71 @@ Image *BKE_image_verify_viewer(int type, const char *name) return ima; } +static void image_viewer_create_views(const RenderData *rd, Image *ima) +{ + if ((rd->scemode & R_MULTIVIEW) == 0) { + image_add_view(ima, "", ""); + } + else { + SceneRenderView *srv; + for (srv = rd->views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) + continue; + image_add_view(ima, srv->name, ""); + } + } +} + +/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */ +void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser) +{ + bool do_reset; + const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0; + + BLI_lock_thread(LOCK_DRAW_IMAGE); + + if (BKE_scene_multiview_is_stereo3d(rd)) { + ima->flag |= IMA_IS_STEREO; + ima->flag |= IMA_IS_MULTIVIEW; + } + else { + ima->flag &= ~IMA_IS_STEREO; + ima->flag &= ~IMA_IS_MULTIVIEW; + iuser->flag &= ~IMA_SHOW_STEREO; + } + + /* see if all scene render views are in the image view list */ + do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views)); + + /* multiview also needs to be sure all the views are synced */ + if (is_multiview && !do_reset) { + SceneRenderView *srv; + ImageView *iv; + + for (iv = ima->views.first; iv; iv = iv->next) { + srv = BLI_findstring(&rd->views, iv->name, offsetof(SceneRenderView, name)); + if ((srv == NULL) || (BKE_scene_multiview_is_render_view_active(rd, srv) == false)) { + do_reset = true; + break; + } + } + } + + if (do_reset) { + BLI_spin_lock(&image_spin); + + image_free_cached_frames(ima); + BKE_image_free_views(ima); + + /* add new views */ + image_viewer_create_views(rd, ima); + + BLI_spin_unlock(&image_spin); + } + + BLI_unlock_thread(LOCK_DRAW_IMAGE); +} + void BKE_image_walk_all_users(const Main *mainp, void *customdata, void callback(Image *ima, ImageUser *iuser, void *customdata)) { @@ -2238,6 +2545,33 @@ static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdat } } +static void image_init_imageuser(Image *ima, ImageUser *iuser) +{ + RenderResult *rr = ima->rr; + + iuser->multi_index = 0; + iuser->layer = iuser->view = 0; + iuser->passtype = SCE_PASS_COMBINED; + + if (rr) { + RenderLayer *rl = rr->layers.first; + + if (rl) { + RenderPass *rp = rl->passes.first; + + if (rp) + iuser->passtype = rp->passtype; + } + + BKE_image_multilayer_index(rr, iuser); + } +} + +void BKE_image_init_imageuser(Image *ima, ImageUser *iuser) +{ + image_init_imageuser(ima, iuser); +} + void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) { if (ima == NULL) @@ -2248,8 +2582,13 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) switch (signal) { case IMA_SIGNAL_FREE: BKE_image_free_buffers(ima); - if (iuser) + + if (iuser) { iuser->ok = 1; + if (iuser->scene) { + image_update_views_format(ima, iuser); + } + } break; case IMA_SIGNAL_SRC_CHANGE: if (ima->type == IMA_TYPE_UV_TEST) @@ -2301,23 +2640,41 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) case IMA_SIGNAL_RELOAD: /* try to repack file */ - if (ima->packedfile) { - PackedFile *pf; - pf = newPackedFile(NULL, ima->name, ID_BLEND_PATH(G.main, &ima->id)); - if (pf) { - freePackedFile(ima->packedfile); - ima->packedfile = pf; - BKE_image_free_buffers(ima); + if (BKE_image_has_packedfile(ima)) { + const size_t totfiles = image_num_files(ima); + + if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) { + /* in case there are new available files to be loaded */ + image_free_packedfiles(ima); + BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id)); } else { - printf("ERROR: Image not available. Keeping packed image\n"); + ImagePackedFile *imapf; + for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { + PackedFile *pf; + pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(G.main, &ima->id)); + if (pf) { + freePackedFile(imapf->packedfile); + imapf->packedfile = pf; + } + else { + printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath); + } + } } + + if (BKE_image_has_packedfile(ima)) + BKE_image_free_buffers(ima); } else BKE_image_free_buffers(ima); - if (iuser) + if (iuser) { iuser->ok = 1; + if (iuser->scene) { + image_update_views_format(ima, iuser); + } + } break; case IMA_SIGNAL_USER_NEW_IMAGE: @@ -2325,8 +2682,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) iuser->ok = 1; if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) { if (ima->type == IMA_TYPE_MULTILAYER) { - iuser->multi_index = 0; - iuser->layer = iuser->pass = 0; + image_init_imageuser(ima, iuser); } } } @@ -2368,44 +2724,113 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) return NULL; if (iuser) { - short index = 0, rl_index = 0, rp_index; + short index = 0, rv_index, rl_index = 0; + bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr); + + rv_index = is_stereo ? iuser->multiview_eye : iuser->view; + if (RE_HasFakeLayer(rr)) rl_index += 1; for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) { - rp_index = 0; - for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++, rp_index++) - if (iuser->layer == rl_index && iuser->pass == rp_index) + for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++) { + if (iuser->layer == rl_index && + iuser->passtype == rpass->passtype && + rv_index == rpass->view_id) + { break; + } + } if (rpass) break; } - - if (rpass) - iuser->multi_index = index; - else - iuser->multi_index = 0; + iuser->multi_index = (rpass ? index : 0); } + if (rpass == NULL) { rl = rr->layers.first; if (rl) rpass = rl->passes.first; + + if (rpass && iuser) + iuser->passtype = rpass->passtype; } return rpass; } +void BKE_image_multiview_index(Image *ima, ImageUser *iuser) +{ + if (iuser) { + bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO); + if (is_stereo) { + iuser->multi_index = iuser->multiview_eye; + } + else { + if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) { + iuser->multi_index = iuser->view = 0; + } + else { + iuser->multi_index = iuser->view; + } + } + } +} + +/* if layer or pass changes, we need an index for the imbufs list */ +/* note it is called for rendered results, but it doesnt use the index! */ +/* and because rendered results use fake layer/passes, don't correct for wrong indices here */ +bool BKE_image_is_multilayer(Image *ima) +{ + if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) { + if (ima->type == IMA_TYPE_MULTILAYER) { + return true; + } + } + else if (ima->source == IMA_SRC_VIEWER) { + if (ima->type == IMA_TYPE_R_RESULT) { + return true; + } + } + return false; +} + +static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr) +{ + if (rr) { + if (RE_RenderResult_is_stereo(rr)) { + ima->flag |= IMA_IS_STEREO; + ima->flag |= IMA_IS_MULTIVIEW; + } + else { + ima->flag &= ~IMA_IS_STEREO; + if (BLI_listbase_count_ex(&rr->views, 2) > 1) + ima->flag |= IMA_IS_MULTIVIEW; + else + ima->flag &= ~IMA_IS_MULTIVIEW; + } + } + else { + ima->flag &= ~IMA_IS_STEREO; + ima->flag &= ~IMA_IS_MULTIVIEW; + } +} + RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) { + RenderResult *rr = NULL; if (ima->rr) { - return ima->rr; + rr = ima->rr; } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - return RE_AcquireResultRead(RE_GetRender(scene->id.name)); + rr = RE_AcquireResultRead(RE_GetRender(scene->id.name)); else - return ima->renders[ima->render_slot]; + rr = ima->renders[ima->render_slot]; + + /* set proper multiview flag */ + image_init_multilayer_multiview_flag(ima, rr); } - else - return NULL; + + return rr; } void BKE_image_release_renderresult(Scene *scene, Image *ima) @@ -2419,6 +2844,18 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima) } } +bool BKE_image_is_openexr(struct Image *ima) +{ +#ifdef WITH_OPENEXR + if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) { + return BLI_testextensie(ima->name, ".exr"); + } +#else + UNUSED_VARS(ima); +#endif + return false; +} + void BKE_image_backup_render(Scene *scene, Image *ima) { /* called right before rendering, ima->renders contains render @@ -2439,8 +2876,155 @@ void BKE_image_backup_render(Scene *scene, Image *ima) ima->last_render_slot = slot; } +/**************************** multiview save openexr *********************************/ +#ifdef WITH_OPENEXR +static const char *image_get_view_cb(void *base, const size_t view_id) +{ + Image *ima = base; + ImageView *iv = BLI_findlink(&ima->views, view_id); + return iv ? iv->name : ""; +} +#endif /* WITH_OPENEXR */ + +#ifdef WITH_OPENEXR +static ImBuf *image_get_buffer_cb(void *base, const size_t view_id) +{ + Image *ima = base; + ImageUser iuser = {0}; + + iuser.view = view_id; + iuser.ok = 1; + + BKE_image_multiview_index(ima, &iuser); + + return image_acquire_ibuf(ima, &iuser, NULL); +} +#endif /* WITH_OPENEXR */ + +bool BKE_image_save_openexr_multiview(Image *ima, ImBuf *ibuf, const char *filepath, const int flags) +{ +#ifdef WITH_OPENEXR + char name[FILE_MAX]; + bool ok; + + BLI_strncpy(name, filepath, sizeof(name)); + BLI_path_abs(name, G.main->name); + + ibuf->userdata = ima; + ok = IMB_exr_multiview_save(ibuf, name, flags, BLI_listbase_count(&ima->views), image_get_view_cb, image_get_buffer_cb); + ibuf->userdata = NULL; + + return ok; +#else + UNUSED_VARS(ima, ibuf, filepath, flags); + return false; +#endif +} + +/**************************** multiview load openexr *********************************/ + +static void image_add_view(Image *ima, const char *viewname, const char *filepath) +{ + ImageView *iv; + + iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View"); + BLI_strncpy(iv->name, viewname, sizeof(iv->name)); + BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath)); + + /* For stereo drawing we need to ensure: + * STEREO_LEFT_NAME == STEREO_LEFT_ID and + * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */ + + if (STREQ(viewname, STEREO_LEFT_NAME)) { + BLI_addhead(&ima->views, iv); + } + else if (STREQ(viewname, STEREO_RIGHT_NAME)) { + ImageView *left_iv = BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)); + + if (left_iv == NULL) { + BLI_addhead(&ima->views, iv); + } + else { + BLI_insertlinkafter(&ima->views, left_iv, iv); + } + } + else { + BLI_addtail(&ima->views, iv); + } +} + +#ifdef WITH_OPENEXR +static void image_add_view_cb(void *base, const char *str) +{ + Image *ima = base; + image_add_view(ima, str, ima->name); +} + +static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const int frame) +{ + Image *ima = base; + size_t id; + bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL); + const char *colorspace = ima->colorspace_settings.name; + const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); + + if (ibuf == NULL) + return; + + id = BLI_findstringindex(&ima->views, str, offsetof(ImageView, name)); + + if (id == -1) + return; + + if (ibuf->channels >= 3) + IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, + colorspace, to_colorspace, predivide); + + image_assign_ibuf(ima, ibuf, id, frame); + IMB_freeImBuf(ibuf); +} +#endif /* WITH_OPENEXR */ + +#ifdef WITH_OPENEXR +static void image_update_multiview_flags(Image *ima) +{ + if (BLI_listbase_count_ex(&ima->views, 2) > 1) { + ima->flag |= IMA_IS_MULTIVIEW; + + if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) && + BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name))) + { + ima->flag |= IMA_IS_STEREO; + } + else { + ima->flag &= ~IMA_IS_STEREO; + } + } + else { + ima->flag &= ~IMA_IS_STEREO; + ima->flag &= ~IMA_IS_MULTIVIEW; + } +} +#endif /* WITH_OPENEXR */ + /* after imbuf load, openexr type can return with a exrhandle open */ /* in that case we have to build a render-result */ +#ifdef WITH_OPENEXR +static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame) +{ + image_free_views(ima); + + IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame); + + image_update_multiview_flags(ima); + + IMB_exr_close(ibuf->userdata); +} +#endif /* WITH_OPENEXR */ + +/* after imbuf load, openexr type can return with a exrhandle open */ +/* in that case we have to build a render-result */ +#ifdef WITH_OPENEXR static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) { const char *colorspace = ima->colorspace_settings.name; @@ -2448,21 +3032,23 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y); -#ifdef WITH_OPENEXR IMB_exr_close(ibuf->userdata); -#endif ibuf->userdata = NULL; if (ima->rr) ima->rr->framenr = framenr; + + /* set proper multiview flag */ + image_init_multilayer_multiview_flag(ima, ima->rr); } +#endif /* WITH_OPENEXR */ /* common stuff to do with images after loading */ static void image_initialize_after_load(Image *ima, ImBuf *ibuf) { /* preview is NULL when it has never been used as an icon before */ if (G.background == 0 && ima->preview == NULL) - BKE_icon_changed(BKE_icon_getid(&ima->id)); + BKE_icon_changed(BKE_icon_id_ensure(&ima->id)); /* fields */ if (ima->flag & IMA_FIELDS) { @@ -2488,18 +3074,41 @@ static int imbuf_alpha_flags_for_image(Image *ima) return flag; } -static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) +/* the number of files will vary according to the stereo format */ +static size_t image_num_files(Image *ima) +{ + const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + + if (!is_multiview) { + return 1; + } + else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) { + return 1; + } + /* R_IMF_VIEWS_INDIVIDUAL */ + else { + return BLI_listbase_count(&ima->views); + } +} + +static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id, bool *r_assign) { struct ImBuf *ibuf; char name[FILE_MAX]; int flag; + ImageUser iuser_t; /* XXX temp stuff? */ if (ima->lastframe != frame) ima->tpageflag |= IMA_TPAGE_REFRESH; ima->lastframe = frame; - BKE_image_user_file_path(iuser, ima, name); + + if (iuser) + iuser_t = *iuser; + + iuser_t.view = view_id; + BKE_image_user_file_path(&iuser_t, ima, name); flag = IB_rect | IB_multilayer; flag |= imbuf_alpha_flags_for_image(ima); @@ -2520,25 +3129,78 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) #ifdef WITH_OPENEXR /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ if (ibuf->ftype == OPENEXR && ibuf->userdata) { - image_create_multilayer(ima, ibuf, frame); - ima->type = IMA_TYPE_MULTILAYER; - IMB_freeImBuf(ibuf); - ibuf = NULL; + /* handle singlelayer multiview case assign ibuf based on available views */ + if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) { + image_create_multiview(ima, ibuf, frame); + IMB_freeImBuf(ibuf); + ibuf = NULL; + } + else if (IMB_exr_has_multilayer(ibuf->userdata)) { + /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ + image_create_multilayer(ima, ibuf, frame); + ima->type = IMA_TYPE_MULTILAYER; + IMB_freeImBuf(ibuf); + ibuf = NULL; + } } else { image_initialize_after_load(ima, ibuf); - image_assign_ibuf(ima, ibuf, 0, frame); + *r_assign = true; } #else image_initialize_after_load(ima, ibuf); - image_assign_ibuf(ima, ibuf, 0, frame); + *r_assign = true; #endif } - else - ima->ok = 0; - if (iuser) - iuser->ok = ima->ok; + return ibuf; +} + +static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) +{ + struct ImBuf *ibuf = NULL; + const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const size_t totfiles = image_num_files(ima); + bool assign = false; + + if (!is_multiview) { + ibuf = load_sequence_single(ima, iuser, frame, 0, &assign); + if (assign) { + image_assign_ibuf(ima, ibuf, 0, frame); + } + } + else { + size_t i; + struct ImBuf **ibuf_arr; + const size_t totviews = BLI_listbase_count(&ima->views); + + ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs"); + + for (i = 0; i < totfiles; i++) + ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign); + + if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D) + IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); + + /* return the original requested ImBuf */ + ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)]; + + if (assign) { + for (i = 0; i < totviews; i++) { + image_assign_ibuf(ima, ibuf_arr[i], i, frame); + } + } + + /* "remove" the others (decrease their refcount) */ + for (i = 0; i < totviews; i++) { + if (ibuf_arr[i] != ibuf) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + + /* cleanup */ + MEM_freeN(ibuf_arr); + } return ibuf; } @@ -2595,46 +3257,52 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f return ibuf; } - -static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) +static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id) { struct ImBuf *ibuf = NULL; + ImageAnim *ia; - ima->lastframe = frame; + ia = BLI_findlink(&ima->anims, view_id); - if (ima->anim == NULL) { + if (ia->anim == NULL) { char str[FILE_MAX]; int flags = IB_rect; + ImageUser iuser_t; + if (ima->flag & IMA_DEINTERLACE) { flags |= IB_animdeinterlace; } - BKE_image_user_file_path(iuser, ima, str); + if (iuser) + iuser_t = *iuser; + + iuser_t.view = view_id; + + BKE_image_user_file_path(&iuser_t, ima, str); /* FIXME: make several stream accessible in image editor, too*/ - ima->anim = openanim(str, IB_rect, 0, ima->colorspace_settings.name); + ia->anim = openanim(str, flags, 0, ima->colorspace_settings.name); /* let's initialize this user */ - if (ima->anim && iuser && iuser->frames == 0) - iuser->frames = IMB_anim_get_duration(ima->anim, + if (ia->anim && iuser && iuser->frames == 0) + iuser->frames = IMB_anim_get_duration(ia->anim, IMB_TC_RECORD_RUN); } - if (ima->anim) { - int dur = IMB_anim_get_duration(ima->anim, + if (ia->anim) { + int dur = IMB_anim_get_duration(ia->anim, IMB_TC_RECORD_RUN); int fra = frame - 1; if (fra < 0) fra = 0; if (fra > (dur - 1)) fra = dur - 1; ibuf = IMB_makeSingleUser( - IMB_anim_absolute(ima->anim, fra, + IMB_anim_absolute(ia->anim, fra, IMB_TC_RECORD_RUN, IMB_PROXY_NONE)); if (ibuf) { image_initialize_after_load(ima, ibuf); - image_assign_ibuf(ima, ibuf, 0, frame); } else ima->ok = 0; @@ -2642,67 +3310,225 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) else ima->ok = 0; + return ibuf; +} + +static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) +{ + struct ImBuf *ibuf = NULL; + const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const size_t totfiles = image_num_files(ima); + size_t i; + + if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) { + image_free_anims(ima); + + for (i = 0; i < totfiles; i++) { + /* allocate the ImageAnim */ + ImageAnim *ia = MEM_callocN(sizeof(ImageAnim), "Image Anim"); + BLI_addtail(&ima->anims, ia); + } + } + + if (!is_multiview) { + ibuf = load_movie_single(ima, iuser, frame, 0); + image_assign_ibuf(ima, ibuf, 0, frame); + } + else { + struct ImBuf **ibuf_arr; + const size_t totviews = BLI_listbase_count(&ima->views); + + ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs"); + + for (i = 0; i < totfiles; i++) { + ibuf_arr[i] = load_movie_single(ima, iuser, frame, i); + } + + if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D) + IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); + + for (i = 0; i < totviews; i++) { + if (ibuf_arr[i]) { + image_assign_ibuf(ima, ibuf_arr[i], i, frame); + } + else { + ima->ok = 0; + } + } + + /* return the original requested ImBuf */ + ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)]; + + /* "remove" the others (decrease their refcount) */ + for (i = 0; i < totviews; i++) { + if (ibuf_arr[i] != ibuf) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + + /* cleanup */ + MEM_freeN(ibuf_arr); + } + if (iuser) iuser->ok = ima->ok; return ibuf; } -/* warning, 'iuser' can be NULL */ -static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) +static ImBuf *load_image_single( + Image *ima, ImageUser *iuser, int cfra, + const size_t view_id, + const bool has_packed, + bool *r_assign) { - struct ImBuf *ibuf; - char str[FILE_MAX]; - int assign = 0, flag; - - /* always ensure clean ima */ - BKE_image_free_buffers(ima); + char filepath[FILE_MAX]; + struct ImBuf *ibuf = NULL; + int flag; /* is there a PackedFile with this image ? */ - if (ima->packedfile) { + if (has_packed) { + ImagePackedFile *imapf; + flag = IB_rect | IB_multilayer; flag |= imbuf_alpha_flags_for_image(ima); - ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag, - ima->colorspace_settings.name, "<packed data>"); + imapf = BLI_findlink(&ima->packedfiles, view_id); + if (imapf->packedfile) { + ibuf = IMB_ibImageFromMemory( + (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag, + ima->colorspace_settings.name, "<packed data>"); + } } else { + ImageUser iuser_t; + flag = IB_rect | IB_multilayer | IB_metadata; flag |= imbuf_alpha_flags_for_image(ima); - /* get the right string */ + /* get the correct filepath */ BKE_image_user_frame_calc(iuser, cfra, 0); - BKE_image_user_file_path(iuser, ima, str); + + if (iuser) + iuser_t = *iuser; + else + iuser_t.framenr = ima->lastframe; + + iuser_t.view = view_id; + + BKE_image_user_file_path(&iuser_t, ima, filepath); /* read ibuf */ - ibuf = IMB_loadiffname(str, flag, ima->colorspace_settings.name); + ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name); } if (ibuf) { - /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ +#ifdef WITH_OPENEXR if (ibuf->ftype == OPENEXR && ibuf->userdata) { - image_create_multilayer(ima, ibuf, cfra); - ima->type = IMA_TYPE_MULTILAYER; - IMB_freeImBuf(ibuf); - ibuf = NULL; + if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) { + /* handle singlelayer multiview case assign ibuf based on available views */ + image_create_multiview(ima, ibuf, cfra); + IMB_freeImBuf(ibuf); + ibuf = NULL; + } + else if (IMB_exr_has_multilayer(ibuf->userdata)) { + /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ + image_create_multilayer(ima, ibuf, cfra); + ima->type = IMA_TYPE_MULTILAYER; + IMB_freeImBuf(ibuf); + ibuf = NULL; + } } else { image_initialize_after_load(ima, ibuf); - assign = 1; + *r_assign = true; /* check if the image is a font image... */ detectBitmapFont(ibuf); /* make packed file for autopack */ - if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK)) - ima->packedfile = newPackedFile(NULL, str, ID_BLEND_PATH(G.main, &ima->id)); + if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) { + ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile"); + BLI_addtail(&ima->packedfiles, imapf); + + BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath)); + imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id)); + } } +#else + image_initialize_after_load(ima, ibuf); + *r_assign = true; +#endif } - else + else { ima->ok = 0; + } - if (assign) - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + return ibuf; +} + +/* warning, 'iuser' can be NULL + * note: Image->views was already populated (in image_update_views_format) + */ +static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) +{ + struct ImBuf *ibuf = NULL; + bool assign = false; + const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0; + const size_t totfiles = image_num_files(ima); + bool has_packed = BKE_image_has_packedfile(ima); + + /* always ensure clean ima */ + BKE_image_free_buffers(ima); + + /* this should never happen, but just playing safe */ + if (has_packed) { + if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) { + image_free_packedfiles(ima); + has_packed = false; + } + } + + if (!is_multiview) { + ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign); + if (assign) { + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + } + } + else { + size_t i; + struct ImBuf **ibuf_arr; + const size_t totviews = BLI_listbase_count(&ima->views); + BLI_assert(totviews > 0); + + ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs"); + + for (i = 0; i < totfiles; i++) + ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign); + + if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D) + IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); + + /* return the original requested ImBuf */ + i = iuser && iuser->multi_index < totviews ? iuser->multi_index : 0; + ibuf = ibuf_arr[i]; + + if (assign) { + for (i = 0; i < totviews; i++) { + image_assign_ibuf(ima, ibuf_arr[i], i, 0); + } + } + + /* "remove" the others (decrease their refcount) */ + for (i = 0; i < totviews; i++) { + if (ibuf_arr[i] != ibuf) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + + /* cleanup */ + MEM_freeN(ibuf_arr); + } if (iuser) iuser->ok = ima->ok; @@ -2749,37 +3575,43 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) /* showing RGBA result itself (from compo/sequence) or * like exr, using layers etc */ /* always returns a single ibuf, also during render progress */ -static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_r) +static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock) { Render *re; RenderResult rres; + RenderView *rv; float *rectf, *rectz; unsigned int *rect; float dither; - int channels, layer, pass; + int channels, layer, passtype; ImBuf *ibuf; int from_render = (ima->render_slot == ima->last_render_slot); + int actview; bool byte_buffer_in_display_space = false; if (!(iuser && iuser->scene)) return NULL; /* if we the caller is not going to release the lock, don't give the image */ - if (!lock_r) + if (!r_lock) return NULL; re = RE_GetRender(iuser->scene->id.name); channels = 4; layer = iuser->layer; - pass = iuser->pass; + passtype = iuser->passtype; + actview = iuser->view; + + if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO)) + actview = iuser->multiview_eye; if (from_render) { - RE_AcquireResultImage(re, &rres); + RE_AcquireResultImage(re, &rres, actview); } else if (ima->renders[ima->render_slot]) { rres = *(ima->renders[ima->render_slot]); - rres.have_combined = rres.rectf != NULL; + rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL; } else memset(&rres, 0, sizeof(RenderResult)); @@ -2790,16 +3622,30 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ return NULL; } - /* release is done in BKE_image_release_ibuf using lock_r */ + /* release is done in BKE_image_release_ibuf using r_lock */ if (from_render) { BLI_lock_thread(LOCK_VIEWER); - *lock_r = re; + *r_lock = re; + rv = NULL; + } + else { + rv = BLI_findlink(&rres.views, actview); + if (rv == NULL) + rv = rres.views.first; } /* this gives active layer, composite or sequence result */ - rect = (unsigned int *)rres.rect32; - rectf = rres.rectf; - rectz = rres.rectz; + if (rv == NULL) { + rect = (unsigned int *)rres.rect32; + rectf = rres.rectf; + rectz = rres.rectz; + } + else { + rect = (unsigned int *)rv->rect32; + rectf = rv->rectf; + rectz = rv->rectz; + } + dither = iuser->scene->r.dither_intensity; /* combined layer gets added as first layer */ @@ -2819,24 +3665,27 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ if (rl) { RenderPass *rpass; - /* there's no combined pass, is in renderlayer itself */ - if (pass == 0) { - rectf = rl->rectf; - if (rectf == NULL) { + for (rpass = rl->passes.first; rpass; rpass = rpass->next) { + if (passtype == rpass->passtype && + actview == rpass->view_id) + { + break; + } + } + + if (rpass) { + channels = rpass->channels; + rectf = rpass->rect; + + if (!rectf) { /* Happens when Save Buffers is enabled. * Use display buffer stored in the render layer. */ rect = (unsigned int *) rl->display_buffer; byte_buffer_in_display_space = true; } - } - else { - rpass = BLI_findlink(&rl->passes, pass - 1); - if (rpass) { - channels = rpass->channels; - rectf = rpass->rect; - dither = 0.0f; /* don't dither passes */ - } + + dither = 0.0f; /* don't dither passes */ } for (rpass = rl->passes.first; rpass; rpass = rpass->next) @@ -2925,9 +3774,31 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ return ibuf; } +static size_t image_get_multiview_index(Image *ima, ImageUser *iuser) +{ + const bool is_multilayer = BKE_image_is_multilayer(ima); + const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL); + int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX; + + if (is_multilayer) { + return iuser ? iuser->multi_index : index; + } + else if (is_backdrop) { + if ((ima->flag & IMA_IS_STEREO)) { + /* backdrop hackaround (since there is no iuser */ + return ima->eye; + } + } + else if ((ima->flag & IMA_IS_MULTIVIEW)) { + return iuser ? iuser->multi_index : index; + } + + return index; +} + static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index) { - int frame = 0, index = 0; + int frame = 0, index = image_get_multiview_index(ima, iuser); /* see if we already have an appropriate ibuf, with image source and type */ if (ima->source == IMA_SRC_MOVIE) { @@ -2939,7 +3810,6 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame } else if (ima->type == IMA_TYPE_MULTILAYER) { frame = iuser ? iuser->framenr : ima->lastframe; - index = iuser ? iuser->multi_index : IMA_NO_INDEX; } } @@ -2956,12 +3826,12 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index) { ImBuf *ibuf = NULL; - int frame = 0, index = 0; + int frame = 0, index = image_get_multiview_index(ima, iuser); /* see if we already have an appropriate ibuf, with image source and type */ if (ima->source == IMA_SRC_MOVIE) { frame = iuser ? iuser->framenr : ima->lastframe; - ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame); /* XXX temp stuff? */ if (ima->lastframe != frame) ima->tpageflag |= IMA_TPAGE_REFRESH; @@ -2970,7 +3840,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, else if (ima->source == IMA_SRC_SEQUENCE) { if (ima->type == IMA_TYPE_IMAGE) { frame = iuser ? iuser->framenr : ima->lastframe; - ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame); /* XXX temp stuff? */ if (ima->lastframe != frame) { @@ -2990,18 +3860,17 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, } else if (ima->type == IMA_TYPE_MULTILAYER) { frame = iuser ? iuser->framenr : ima->lastframe; - index = iuser ? iuser->multi_index : IMA_NO_INDEX; ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame); } } else if (ima->source == IMA_SRC_FILE) { if (ima->type == IMA_TYPE_IMAGE) - ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0); else if (ima->type == IMA_TYPE_MULTILAYER) - ibuf = image_get_cached_ibuf_for_index_frame(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0); } else if (ima->source == IMA_SRC_GENERATED) { - ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0); } else if (ima->source == IMA_SRC_VIEWER) { /* always verify entirely, not that this shouldn't happen @@ -3037,13 +3906,13 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser) * * not thread-safe, so callee should worry about thread locks */ -static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) +static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf = NULL; int frame = 0, index = 0; - if (lock_r) - *lock_r = NULL; + if (r_lock) + *r_lock = NULL; /* quick reject tests */ if (!image_quick_test(ima, iuser)) @@ -3085,31 +3954,31 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) if (ima->gen_depth == 0) ima->gen_depth = 24; ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type, ima->gen_color, &ima->colorspace_settings); - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + image_assign_ibuf(ima, ibuf, index, 0); ima->ok = IMA_OK_LOADED; } else if (ima->source == IMA_SRC_VIEWER) { if (ima->type == IMA_TYPE_R_RESULT) { /* always verify entirely, and potentially * returns pointer to release later */ - ibuf = image_get_render_result(ima, iuser, lock_r); + ibuf = image_get_render_result(ima, iuser, r_lock); } else if (ima->type == IMA_TYPE_COMPOSITE) { /* requires lock/unlock, otherwise don't return image */ - if (lock_r) { + if (r_lock) { /* unlock in BKE_image_release_ibuf */ BLI_lock_thread(LOCK_VIEWER); - *lock_r = ima; + *r_lock = ima; /* XXX anim play for viewer nodes not yet supported */ frame = 0; // XXX iuser ? iuser->framenr : 0; - ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame); if (!ibuf) { /* Composite Viewer, all handled in compositor */ /* fake ibuf, will be filled in compositor */ - ibuf = IMB_allocImBuf(256, 256, 32, IB_rect); - image_assign_ibuf(ima, ibuf, 0, frame); + ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat); + image_assign_ibuf(ima, ibuf, index, frame); } } } @@ -3133,13 +4002,13 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) * * references the result, BKE_image_release_ibuf should be used to de-reference */ -ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) +ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf; BLI_spin_lock(&image_spin); - ibuf = image_acquire_ibuf(ima, iuser, lock_r); + ibuf = image_acquire_ibuf(ima, iuser, r_lock); BLI_spin_unlock(&image_spin); @@ -3409,7 +4278,13 @@ void BKE_image_update_frame(const Main *bmain, int cfra) void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) { - BLI_strncpy(filepath, ima->name, FILE_MAX); + if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) { + ImageView *iv = BLI_findlink(&ima->views, iuser->view); + BLI_strncpy(filepath, iv->filepath, FILE_MAX); + } + else { + BLI_strncpy(filepath, ima->name, FILE_MAX); + } if (ima->source == IMA_SRC_SEQUENCE) { char head[FILE_MAX], tail[FILE_MAX]; @@ -3545,6 +4420,16 @@ int BKE_image_sequence_guess_offset(Image *image) return atoi(num); } +bool BKE_image_has_anim(Image *ima) +{ + return (BLI_listbase_is_empty(&ima->anims) == false); +} + +bool BKE_image_has_packedfile(Image *ima) +{ + return (BLI_listbase_is_empty(&ima->packedfiles) == false); +} + /** * Checks the image buffer changes (not keyframed values) * @@ -3675,3 +4560,88 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) return ibuf; } + +static void image_update_views_format(Image *ima, ImageUser *iuser) +{ + SceneRenderView *srv; + ImageView *iv; + Scene *scene = iuser->scene; + const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) && + ((ima->flag & IMA_USE_VIEWS) != 0); + + /* reset the image views */ + BKE_image_free_views(ima); + + if (!is_multiview) { + goto monoview; + } + else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) { + size_t i; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + + ima->flag |= IMA_IS_MULTIVIEW; + ima->flag |= IMA_IS_STEREO; + + for (i = 0; i < 2; i++) { + image_add_view(ima, names[i], ima->name); + } + return; + } + else { + /* R_IMF_VIEWS_INDIVIDUAL */ + char prefix[FILE_MAX] = {'\0'}; + char *name = ima->name; + char *ext = NULL; + + BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext); + + if (prefix[0] == '\0') { + goto monoview; + } + + /* create all the image views */ + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { + char filepath[FILE_MAX]; + BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext); + image_add_view(ima, srv->name, filepath); + } + } + + /* check if the files are all available */ + iv = ima->views.last; + while (iv) { + int file; + char str[FILE_MAX]; + + BLI_strncpy(str, iv->filepath, sizeof(str)); + BLI_path_abs(str, G.main->name); + + /* exists? */ + file = BLI_open(str, O_BINARY | O_RDONLY, 0); + if (file == -1) { + ImageView *iv_del = iv; + iv = iv->prev; + BLI_remlink(&ima->views, iv_del); + MEM_freeN(iv_del); + } + else { + iv = iv->prev; + close(file); + } + } + + /* all good */ + if (BLI_listbase_count_ex(&ima->views, 2) > 1) { + ima->flag |= IMA_IS_MULTIVIEW; + if (BKE_scene_multiview_is_stereo3d(&scene->r)) + ima->flag |= IMA_IS_STEREO; + } + else { +monoview: + ima->flag &= ~IMA_IS_STEREO; + ima->flag &= ~IMA_IS_MULTIVIEW; + BKE_image_free_views(ima); + } + } +} diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 09ce9484a69..6d37f3ae006 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1712,7 +1712,7 @@ void do_versions_ipos_to_animato(Main *main) /* check if object has any animation data */ if (ob->nlastrips.first) { /* Add AnimData block */ - BKE_id_add_animdata(id); + BKE_animdata_add_id(id); /* IPO first to take into any non-NLA'd Object Animation */ if (ob->ipo) { @@ -1735,7 +1735,7 @@ void do_versions_ipos_to_animato(Main *main) } else if ((ob->ipo) || (ob->action)) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Action first - so that Action name get conserved */ if (ob->action) { @@ -1776,7 +1776,7 @@ void do_versions_ipos_to_animato(Main *main) /* check PoseChannels for constraints with local data */ if (ob->pose) { /* Verify if there's AnimData block */ - BKE_id_add_animdata(id); + BKE_animdata_add_id(id); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { @@ -1802,7 +1802,7 @@ void do_versions_ipos_to_animato(Main *main) */ if (con->ipo) { /* Verify if there's AnimData block, just in case */ - BKE_id_add_animdata(id); + BKE_animdata_add_id(id); /* although this was the constraint's local IPO, we still need to provide con * so that drivers can be added properly... @@ -1819,7 +1819,7 @@ void do_versions_ipos_to_animato(Main *main) /* check constraint channels - we need to remove them anyway... */ if (ob->constraintChannels.first) { /* Verify if there's AnimData block */ - BKE_id_add_animdata(id); + BKE_animdata_add_id(id); for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) { /* get pointer to next Constraint Channel */ @@ -1857,7 +1857,7 @@ void do_versions_ipos_to_animato(Main *main) */ if (key->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert Shapekey data... */ ipo_to_animdata(id, key->ipo, NULL, NULL, NULL); @@ -1879,7 +1879,7 @@ void do_versions_ipos_to_animato(Main *main) /* we're only interested in the IPO */ if (ma->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert Material data... */ ipo_to_animdata(id, ma->ipo, NULL, NULL, NULL); @@ -1901,7 +1901,7 @@ void do_versions_ipos_to_animato(Main *main) /* we're only interested in the IPO */ if (wo->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert World data... */ ipo_to_animdata(id, wo->ipo, NULL, NULL, NULL); @@ -1921,7 +1921,7 @@ void do_versions_ipos_to_animato(Main *main) if (ed && ed->seqbasep) { Sequence *seq; - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); SEQ_BEGIN(ed, seq) { @@ -1977,7 +1977,7 @@ void do_versions_ipos_to_animato(Main *main) /* we're only interested in the IPO */ if (te->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert Texture data... */ ipo_to_animdata(id, te->ipo, NULL, NULL, NULL); @@ -1999,7 +1999,7 @@ void do_versions_ipos_to_animato(Main *main) /* we're only interested in the IPO */ if (ca->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert Camera data... */ ipo_to_animdata(id, ca->ipo, NULL, NULL, NULL); @@ -2021,7 +2021,7 @@ void do_versions_ipos_to_animato(Main *main) /* we're only interested in the IPO */ if (la->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert Lamp data... */ ipo_to_animdata(id, la->ipo, NULL, NULL, NULL); @@ -2043,7 +2043,7 @@ void do_versions_ipos_to_animato(Main *main) /* we're only interested in the IPO */ if (cu->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_id_add_animdata(id); + AnimData *adt = BKE_animdata_add_id(id); /* Convert Curve data... */ ipo_to_animdata(id, cu->ipo, NULL, NULL, NULL); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index f598be0298a..092dd90041f 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -52,12 +52,14 @@ #include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "DNA_strands_types.h" #include "DNA_texture_types.h" #include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_customdata.h" #include "BKE_deform.h" +#include "BKE_pointcache.h" #include "BKE_global.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -65,25 +67,26 @@ #include "BKE_particle.h" #include "BKE_editmesh.h" #include "BKE_scene.h" +#include "BKE_strands.h" #include "RNA_access.h" #include "RE_render_ext.h" -#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */ -#define KEY_MODE_BPOINT 1 -#define KEY_MODE_BEZTRIPLE 2 - /* old defines from DNA_ipo_types.h for data-type, stored in DNA - don't modify! */ #define IPO_FLOAT 4 #define IPO_BEZTRIPLE 100 #define IPO_BPOINT 101 +#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */ +#define KEY_MODE_BPOINT 1 +#define KEY_MODE_BEZTRIPLE 2 + void BKE_key_free(Key *key) { KeyBlock *kb; - BKE_free_animdata((ID *)key); + BKE_animdata_free((ID *)key); while ((kb = BLI_pophead(&key->block))) { if (kb->data) @@ -103,78 +106,82 @@ void BKE_key_free_nolib(Key *key) } } -Key *BKE_key_add(ID *id) /* common function */ +static void key_set_elemstr(short fromtype, char *r_elemstr, int *r_elemsize) { - Key *key; - char *el; - - key = BKE_libblock_alloc(G.main, ID_KE, "Key"); - - key->type = KEY_NORMAL; - BKE_key_set_from_id(key, id); - - key->uidgen = 1; - /* XXX the code here uses some defines which will soon be deprecated... */ - switch (GS(id->name)) { - case ID_ME: - el = key->elemstr; - - el[0] = 3; - el[1] = IPO_FLOAT; - el[2] = 0; - - key->elemsize = 12; - + char elemtype = IPO_FLOAT; + char numelem = 0; + int elemsize = 0; + + switch (fromtype) { + case KEY_OWNER_MESH: + numelem = 3; + elemtype = IPO_FLOAT; + elemsize = 12; break; - case ID_LT: - el = key->elemstr; - - el[0] = 3; - el[1] = IPO_FLOAT; - el[2] = 0; - - key->elemsize = 12; - + case KEY_OWNER_LATTICE: + numelem = 3; + elemtype = IPO_FLOAT; + elemsize = 12; break; - case ID_CU: - el = key->elemstr; - - el[0] = 4; - el[1] = IPO_BPOINT; - el[2] = 0; - - key->elemsize = 16; - + case KEY_OWNER_CURVE: + numelem = 4; + elemtype = IPO_BPOINT; + elemsize = 16; + break; + case KEY_OWNER_PARTICLES: + numelem = 3; + elemtype = IPO_FLOAT; + elemsize = 12; + break; + case KEY_OWNER_CACHELIB: + numelem = 3; + elemtype = IPO_FLOAT; + elemsize = 12; break; } - return key; + r_elemstr[0] = numelem; + r_elemstr[1] = elemtype; + r_elemstr[2] = 0; + *r_elemsize = elemsize; } -Key *BKE_key_add_particles(Object *ob, ParticleSystem *psys) /* particles are "special" */ +Key *BKE_key_add_ex(ID *from, int fromtype, int fromindex) /* common function */ { Key *key; - char *el; key = BKE_libblock_alloc(G.main, ID_KE, "Key"); key->type = KEY_NORMAL; - BKE_key_set_from_particles(key, ob, psys); - + key->from = from; + key->fromtype = fromtype; + key->fromindex = fromindex; + key->uidgen = 1; - el = key->elemstr; - - el[0] = 3; - el[1] = IPO_FLOAT; - el[2] = 0; - - key->elemsize = 12; + key_set_elemstr(fromtype, key->elemstr, &key->elemsize); return key; } +Key *BKE_key_add(ID *id) +{ + int fromtype = 0; + switch (GS(id->name)) { + case ID_ME: fromtype = KEY_OWNER_MESH; break; + case ID_CU: fromtype = KEY_OWNER_CURVE; break; + case ID_LT: fromtype = KEY_OWNER_LATTICE; break; + default: BLI_assert(false); break; /* other fromtypes should use the _ex version for specifying the type */ + } + return BKE_key_add_ex(id, fromtype, -1); +} + +Key *BKE_key_add_particles(Object *ob, ParticleSystem *psys) /* particles are "special" */ +{ + return BKE_key_add_ex((ID *)ob, KEY_OWNER_PARTICLES, BLI_findindex(&ob->particlesystem, psys)); +} + Key *BKE_key_copy(Key *key) { Key *keyn; @@ -284,11 +291,11 @@ void BKE_key_set_from_id(Key *key, ID *id) if (key) { key->from = id; switch (GS(id->name)) { - case ID_ME: key->from_extra.type = KEY_OWNER_MESH; break; - case ID_CU: key->from_extra.type = KEY_OWNER_CURVE; break; - case ID_LT: key->from_extra.type = KEY_OWNER_LATTICE; break; + case ID_ME: key->fromtype = KEY_OWNER_MESH; break; + case ID_CU: key->fromtype = KEY_OWNER_CURVE; break; + case ID_LT: key->fromtype = KEY_OWNER_LATTICE; break; } - key->from_extra.index = -1; + key->fromindex = -1; } } @@ -296,8 +303,8 @@ void BKE_key_set_from_particles(Key *key, Object *ob, ParticleSystem *psys) { if (key) { key->from = (ID *)ob; - key->from_extra.type = KEY_OWNER_PARTICLES; - key->from_extra.index = BLI_findindex(&ob->particlesystem, psys); + key->fromtype = KEY_OWNER_PARTICLES; + key->fromindex = BLI_findindex(&ob->particlesystem, psys); } } @@ -565,7 +572,7 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char ** if (kb == actkb) { /* this hack makes it possible to edit shape keys in * edit mode with shape keys blending applied */ - if (key->from_extra.type == KEY_OWNER_MESH) { + if (key->from && key->fromtype == KEY_OWNER_MESH) { Mesh *me; BMVert *eve; BMIter iter; @@ -597,7 +604,11 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char ** /* currently only the first value of 'ofs' may be set. */ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs) { - switch (key->from_extra.type) { + /* some types allow NULL for key->from */ + if (!key->from && !ELEM(key->fromtype, KEY_OWNER_CACHELIB)) + return false; + + switch (key->fromtype) { case KEY_OWNER_MESH: *ofs = sizeof(float) * 3; *poinsize = *ofs; @@ -620,12 +631,15 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs = sizeof(float) * 3; *poinsize = *ofs; break; - + case KEY_OWNER_CACHELIB: + *ofs = sizeof(float) * 3; + *poinsize = *ofs; + break; + default: BLI_assert(!"invalid 'key->from' ID type"); return false; } - return true; } @@ -747,6 +761,87 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key if (freekref) MEM_freeN(freekref); } +static void cp_key_strands(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode) +{ + float ktot = 0.0, kd = 0.0; + int elemsize, poinsize = 0, a, ofs, flagflo = 0; + char *k1, *freek1; + + /* currently always 0, in future key_pointer_size may assign */ + ofs = 0; + + if (!key_pointer_size(key, mode, &poinsize, &ofs)) + return; + + if (end > tot) end = tot; + + if (tot != kb->totelem) { + ktot = 0.0; + flagflo = 1; + if (kb->totelem) { + kd = kb->totelem / (float)tot; + } + else { + return; + } + } + + k1 = key_block_get_data(key, actkb, kb, &freek1); + + /* this exception is needed curves with multiple splines */ + if (start != 0) { + + poin += poinsize * start; + + if (flagflo) { + ktot += start * kd; + a = (int)floor(ktot); + if (a) { + ktot -= a; + k1 += a * key->elemsize; + } + } + else { + k1 += start * key->elemsize; + } + } + + /* just do it here, not above! */ + elemsize = key->elemsize; + if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3; + + for (a = start; a < end; a++) { + if (weights) { + if (*weights != 0.0f) + madd_v3_v3fl((float *)poin, (float *)k1, *weights); + weights++; + } + else { + add_v3_v3((float *)poin, (float *)k1); + } + + poin += ofs; + + /* are we going to be nasty? */ + if (flagflo) { + ktot += kd; + while (ktot >= 1.0f) { + ktot -= 1.0f; + k1 += elemsize; + } + } + else { + k1 += elemsize; + } + + if (mode == KEY_MODE_BEZTRIPLE) { + a += 2; + } + } + + if (freek1) MEM_freeN(freek1); +} + static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const int start, int end, char *out, const int tot) { Nurb *nu; @@ -781,7 +876,8 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba { KeyBlock *kb; int *ofsp, ofs[3], elemsize, b; - char *cp, *poin, *reffrom, *from, elemstr[8]; + char *poin, *reffrom, *from; + char elemstr[8]; int poinsize, keyblock_index; /* currently always 0, in future key_pointer_size may assign */ @@ -812,23 +908,25 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba /* only with value, and no difference allowed */ if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) { - KeyBlock *refb; float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL; char *freefrom = NULL, *freereffrom = NULL; - /* reference now can be any block */ - refb = BLI_findlink(&key->block, kb->relative); - if (refb == NULL) continue; - poin = basispoin; from = key_block_get_data(key, actkb, kb, &freefrom); - reffrom = key_block_get_data(key, actkb, refb, &freereffrom); + { + /* reference now can be any block */ + KeyBlock *refb = BLI_findlink(&key->block, kb->relative); + if (refb == NULL) continue; + + reffrom = key_block_get_data(key, actkb, refb, &freereffrom); + } poin += start * poinsize; reffrom += key->elemsize * start; // key elemsize yes! from += key->elemsize * start; for (b = start; b < end; b++) { + char *cp; weight = weights ? (*weights * icuval) : icuval; @@ -877,6 +975,57 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba } } +void BKE_key_evaluate_strands_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb, + float **per_keyblock_weights, const int mode) +{ + KeyBlock *kb; + int ofs, elemsize, b; + char *poin, *from; + int poinsize, keyblock_index; + + if (!key_pointer_size(key, mode, &poinsize, &ofs)) + return; + + if (end > tot) end = tot; + + /* just here, not above! */ + elemsize = key->elemsize; + if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3; + + for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) { + if (kb != key->refkey) { + float icuval = kb->curval; + + /* only with value, and no difference allowed */ + if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) { + float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL; + char *freefrom = NULL; + + poin = basispoin; + from = key_block_get_data(key, actkb, kb, &freefrom); + + poin += start * poinsize; + from += key->elemsize * start; + + for (b = start; b < end; b++) { + float delta[3]; + + weight = weights ? (*weights * icuval) : icuval; + + sub_v3_v3v3(delta, (float *)from, (float *)poin); + madd_v3_v3fl((float *)poin, delta, weight); + + poin += ofs; + from += elemsize; + if (mode == KEY_MODE_BEZTRIPLE) b += 2; + if (weights) weights++; + } + + if (freefrom) MEM_freeN(freefrom); + } + } + } +} static void do_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode) { @@ -1053,6 +1202,200 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key k1 += elemsize; } } + else { + k1 += elemsize; + } + } + if (flagdo & 2) { + if (flagflo & 2) { + k2tot += k2d; + while (k2tot >= 1.0f) { + k2tot -= 1.0f; + k2 += elemsize; + } + } + else { + k2 += elemsize; + } + } + if (flagdo & 4) { + if (flagflo & 4) { + k3tot += k3d; + while (k3tot >= 1.0f) { + k3tot -= 1.0f; + k3 += elemsize; + } + } + else { + k3 += elemsize; + } + } + if (flagdo & 8) { + if (flagflo & 8) { + k4tot += k4d; + while (k4tot >= 1.0f) { + k4tot -= 1.0f; + k4 += elemsize; + } + } + else { + k4 += elemsize; + } + } + + if (mode == KEY_MODE_BEZTRIPLE) a += 2; + } + + if (freek1) MEM_freeN(freek1); + if (freek2) MEM_freeN(freek2); + if (freek3) MEM_freeN(freek3); + if (freek4) MEM_freeN(freek4); +} + +static void do_key_strands(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode) +{ + float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0; + float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0; + int a, ofs; + int flagdo = 15, flagflo = 0, elemsize, poinsize = 0; + char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4; + + /* currently always 0, in future key_pointer_size may assign */ + if (!key_pointer_size(key, mode, &poinsize, &ofs)) + return; + + if (end > tot) end = tot; + + k1 = key_block_get_data(key, actkb, k[0], &freek1); + k2 = key_block_get_data(key, actkb, k[1], &freek2); + k3 = key_block_get_data(key, actkb, k[2], &freek3); + k4 = key_block_get_data(key, actkb, k[3], &freek4); + + /* test for more or less points (per key!) */ + if (tot != k[0]->totelem) { + k1tot = 0.0; + flagflo |= 1; + if (k[0]->totelem) { + k1d = k[0]->totelem / (float)tot; + } + else { + flagdo -= 1; + } + } + if (tot != k[1]->totelem) { + k2tot = 0.0; + flagflo |= 2; + if (k[0]->totelem) { + k2d = k[1]->totelem / (float)tot; + } + else { + flagdo -= 2; + } + } + if (tot != k[2]->totelem) { + k3tot = 0.0; + flagflo |= 4; + if (k[0]->totelem) { + k3d = k[2]->totelem / (float)tot; + } + else { + flagdo -= 4; + } + } + if (tot != k[3]->totelem) { + k4tot = 0.0; + flagflo |= 8; + if (k[0]->totelem) { + k4d = k[3]->totelem / (float)tot; + } + else { + flagdo -= 8; + } + } + + /* this exception is needed for curves with multiple splines */ + if (start != 0) { + + poin += poinsize * start; + + if (flagdo & 1) { + if (flagflo & 1) { + k1tot += start * k1d; + a = (int)floor(k1tot); + if (a) { + k1tot -= a; + k1 += a * key->elemsize; + } + } + else { + k1 += start * key->elemsize; + } + } + if (flagdo & 2) { + if (flagflo & 2) { + k2tot += start * k2d; + a = (int)floor(k2tot); + if (a) { + k2tot -= a; + k2 += a * key->elemsize; + } + } + else { + k2 += start * key->elemsize; + } + } + if (flagdo & 4) { + if (flagflo & 4) { + k3tot += start * k3d; + a = (int)floor(k3tot); + if (a) { + k3tot -= a; + k3 += a * key->elemsize; + } + } + else { + k3 += start * key->elemsize; + } + } + if (flagdo & 8) { + if (flagflo & 8) { + k4tot += start * k4d; + a = (int)floor(k4tot); + if (a) { + k4tot -= a; + k4 += a * key->elemsize; + } + } + else { + k4 += start * key->elemsize; + } + } + + } + + /* only here, not above! */ + elemsize = key->elemsize; + if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3; + + for (a = start; a < end; a++) { + + zero_v3((float *)poin); + madd_v3_v3fl((float *)poin, (float *)k1, t[0]); + madd_v3_v3fl((float *)poin, (float *)k2, t[1]); + madd_v3_v3fl((float *)poin, (float *)k3, t[2]); + madd_v3_v3fl((float *)poin, (float *)k4, t[3]); + + poin += ofs; + + /* lets do it the difficult way: when keys have a different size */ + if (flagdo & 1) { + if (flagflo & 1) { + k1tot += k1d; + while (k1tot >= 1.0f) { + k1tot -= 1.0f; + k1 += elemsize; + } + } else k1 += elemsize; } if (flagdo & 2) { @@ -1173,6 +1516,21 @@ static float *get_object_weights_array(Object *ob, char *vgroup, WeightsArrayCac return NULL; } +static float *get_weights_array_strands(Strands *strands, const char *UNUSED(vgroup), bool is_refkey, WeightsArrayCache *UNUSED(cache)) +{ + int totvert = strands->totverts; + + if (is_refkey) { + /* for the refkey, return zero weights, so the refkey actually uses the unmodified data */ + float *weights = MEM_callocN(totvert * sizeof(float), "weights"); + return weights; + } + else { + /* TODO no vgroup support for strands yet */ + return NULL; + } +} + float **BKE_keyblock_get_per_block_object_weights(Object *ob, Key *key, WeightsArrayCache *cache) { KeyBlock *keyblock; @@ -1280,6 +1638,26 @@ float **BKE_keyblock_get_per_block_particle_weights(Object *ob, ParticleSystem * return per_keyblock_weights; } +float **BKE_keyblock_strands_get_per_block_weights(Strands *strands, Key *key, WeightsArrayCache *cache) +{ + KeyBlock *keyblock; + float **per_keyblock_weights; + int keyblock_index; + + per_keyblock_weights = + MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey, + "per keyblock weights"); + + for (keyblock = key->block.first, keyblock_index = 0; + keyblock; + keyblock = keyblock->next, keyblock_index++) + { + per_keyblock_weights[keyblock_index] = get_weights_array_strands(strands, keyblock->vgroup, keyblock == key->refkey, cache); + } + + return per_keyblock_weights; +} + void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache) { int a; @@ -1554,10 +1932,114 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem) return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0); } +static void do_strands_key(Strands *strands, Key *key, KeyBlock *actkb, char *out, const int tot) +{ + KeyBlock *k[4]; + float t[4]; + int flag = 0; + + if (key->type == KEY_RELATIVE) { + WeightsArrayCache cache = {0, NULL}; + float **per_keyblock_weights ; + per_keyblock_weights = BKE_keyblock_strands_get_per_block_weights(strands, key, &cache); + BKE_key_evaluate_strands_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); + } + else { + const float ctime_scaled = key->ctime / 100.0f; + + flag = setkeys(ctime_scaled, &key->block, k, t, 0); + + if (flag == 0) { + do_key_strands(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY); + } + else { + cp_key_strands(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY); + } + } +} + +float *BKE_key_evaluate_strands_ex(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem, float *arr, size_t arr_size) +{ + char *out; + int tot = 0, size = 0; + + if (key == NULL || BLI_listbase_is_empty(&key->block)) + return NULL; + + /* compute size of output array */ + tot = strands->totverts; + size = tot * 3 * sizeof(float); + /* if nothing to interpolate, cancel */ + if (tot == 0 || size == 0) + return NULL; + + /* allocate array */ + if (arr == NULL) { + out = MEM_callocN(size, "BKE_key_evaluate_strands out"); + } + else { + if (arr_size != size) { + return NULL; + } + + out = (char *)arr; + } + + if (lock_shape && actkb) { + /* shape locked, copy the locked shape instead of blending */ + float *weights; + + if (actkb->flag & KEYBLOCK_MUTE) + actkb = key->refkey; + + /* XXX weights not supported for strands yet */ + weights = get_weights_array_strands(strands, actkb->vgroup, actkb == key->refkey, NULL); + + cp_key_strands(0, tot, tot, out, key, actkb, actkb, weights, 0); + + if (weights) + MEM_freeN(weights); + } + else { + do_strands_key(strands, key, actkb, out, tot); + } + + if (r_totelem) { + *r_totelem = tot; + } + return (float *)out; +} + +float *BKE_key_evaluate_strands(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem, bool use_motion) +{ + size_t size = sizeof(float) * 3 * strands->totverts; + float *data = MEM_mallocN(size, "strands shape key data"); + float *result; + float *fp; + int i; + + if (use_motion && strands->state) { + for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3) + copy_v3_v3(fp, strands->state[i].co); + } + else { + for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3) + copy_v3_v3(fp, strands->verts[i].co); + } + + result = BKE_key_evaluate_strands_ex(strands, key, actkb, lock_shape, r_totelem, data, size); + if (result != data) + MEM_freeN(data); + + return result; +} + /* returns key coordinates when key applied, NULL otherwise */ float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfra, int *r_totelem, float *arr, size_t arr_size) { + const bool use_editmode = (ob->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current(ob) && (psys->edit || psys->pointcache->edit) && !psys->renderdata; Key *key = psys->key; KeyBlock *actkb = BKE_keyblock_from_particles(psys); char *out; @@ -1592,7 +2074,21 @@ float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfr /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */ BKE_key_set_from_particles(key, ob, psys); - if (ob->shapeflag & OB_SHAPE_LOCK) { + if (use_editmode) { + /* in edit mode, only evaluate the active shape */ + KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1); + + if (kb && (kb->flag & KEYBLOCK_MUTE)) + kb = key->refkey; + + if (kb == NULL) { + kb = key->block.first; + psys->shapenr = 1; + } + + cp_key(0, tot, tot, out, key, actkb, kb, NULL, 0); + } + else if (ob->shapeflag & OB_SHAPE_LOCK) { /* shape locked, copy the locked shape instead of blending */ KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1); float *weights; @@ -1626,25 +2122,37 @@ float *BKE_key_evaluate_particles(Object *ob, ParticleSystem *psys, float cfra, return BKE_key_evaluate_particles_ex(ob, psys, cfra, r_totelem, NULL, 0); } -Key *BKE_key_from_object(Object *ob) +Key **BKE_key_from_object_p(Object *ob) { - if (ob == NULL) return NULL; - + if (ob == NULL) + return NULL; + if (ob->type == OB_MESH) { Mesh *me = ob->data; - return me->key; + return &me->key; } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - return cu->key; + return &cu->key; } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; - return lt->key; + return <->key; } return NULL; } +Key *BKE_key_from_object(Object *ob) +{ + Key **key_p; + key_p = BKE_key_from_object_p(ob); + if (key_p) { + return *key_p; + } + + return NULL; +} + KeyBlock *BKE_keyblock_add(Key *key, const char *name) { KeyBlock *kb; @@ -2019,6 +2527,72 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me) } } +/************************* Strands ************************/ +void BKE_keyblock_update_from_strands(Strands *strands, KeyBlock *kb, bool use_motion) +{ + float (*fp)[3]; + int a, tot; + + BLI_assert(strands->totverts == kb->totelem); + + tot = strands->totverts; + if (tot == 0) return; + + fp = kb->data; + /* use vertex locations as fallback, so we always get a valid shape */ + if (use_motion && strands->state) { + StrandsMotionState *state = strands->state; + for (a = 0; a < tot; a++, fp++, state++) { + copy_v3_v3(*fp, state->co); + } + } + else { + StrandsVertex *vert = strands->verts; + for (a = 0; a < tot; a++, fp++, vert++) { + copy_v3_v3(*fp, vert->co); + } + } +} + +void BKE_keyblock_convert_from_strands(Strands *strands, Key *key, KeyBlock *kb, bool use_motion) +{ + int tot = strands->totverts; + + if (strands->totverts == 0) return; + + MEM_SAFE_FREE(kb->data); + + kb->data = MEM_mallocN(key->elemsize * tot, __func__); + kb->totelem = tot; + + BKE_keyblock_update_from_strands(strands, kb, use_motion); +} + +void BKE_keyblock_convert_to_strands(KeyBlock *kb, Strands *strands, bool use_motion) +{ + const float (*fp)[3]; + int a, tot; + + fp = kb->data; + + tot = min_ii(kb->totelem, strands->totverts); + + if (use_motion) { + if (strands->state) { + StrandsMotionState *state = strands->state; + for (a = 0; a < tot; a++, fp++, state++) { + copy_v3_v3(state->co, *fp); + } + } + } + else { + StrandsVertex *vert = strands->verts; + for (a = 0; a < tot; a++, fp++, vert++) { + copy_v3_v3(vert->co, *fp); + } + } +} + /************************* raw coords ************************/ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3]) { @@ -2256,11 +2830,10 @@ void BKE_keyblock_convert_from_hair_keys(struct Object *UNUSED(ob), struct Parti * \param org_index if < 0, current object's active shape will be used as skey to move. * \return true if something was done, else false. */ -bool BKE_keyblock_move(Object *ob, int org_index, int new_index) +bool BKE_keyblock_move_ex(Key *key, int *shapenr, int org_index, int new_index) { - Key *key = BKE_key_from_object(ob); KeyBlock *kb; - const int act_index = ob->shapenr - 1; + const int act_index = *shapenr - 1; const int totkey = key->totkey; int i; bool rev, in_range = false; @@ -2320,13 +2893,13 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index) /* Need to update active shape number if it's affected, same principle as for relative indices above. */ if (org_index == act_index) { - ob->shapenr = new_index + 1; + *shapenr = new_index + 1; } else if (act_index < org_index && act_index >= new_index) { - ob->shapenr++; + (*shapenr)++; } else if (act_index > org_index && act_index <= new_index) { - ob->shapenr--; + (*shapenr)--; } /* First key is always refkey, matches interface and BKE_key_sort */ @@ -2335,6 +2908,14 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index) return true; } +bool BKE_keyblock_move(Object *ob, int org_index, int new_index) +{ + int shapenr; + bool result = BKE_keyblock_move_ex(BKE_key_from_object(ob), &shapenr, org_index, new_index); + ob->shapenr = shapenr; + return result; +} + /** * Check if given keyblock (as index) is used as basis by others in given key. */ diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 93b9c22566d..44e35c645de 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -221,7 +221,7 @@ void BKE_lamp_free(Lamp *la) if (mtex) MEM_freeN(mtex); } - BKE_free_animdata((ID *)la); + BKE_animdata_free((ID *)la); curvemapping_free(la->curfalloff); @@ -232,7 +232,7 @@ void BKE_lamp_free(Lamp *la) } BKE_previewimg_free(&la->preview); - BKE_icon_delete(&la->id); + BKE_icon_id_delete(&la->id); la->id.icon_id = 0; } diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 13f6e1b87b2..582c164a776 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -53,6 +53,7 @@ #include "BKE_anim.h" #include "BKE_cdderivedmesh.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_key.h" @@ -307,7 +308,7 @@ void BKE_lattice_free(Lattice *lt) /* free animation data */ if (lt->adt) { - BKE_free_animdata(<->id); + BKE_animdata_free(<->id); lt->adt = NULL; } } @@ -725,8 +726,9 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], return false; } -void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], - int numVerts, const char *vgroup, short defaxis) +void curve_deform_verts( + Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], + int numVerts, const char *vgroup, short defaxis) { Curve *cu; int a; @@ -1068,7 +1070,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob) } for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -1205,3 +1207,10 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys) } } +/* **** Depsgraph evaluation **** */ + +void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Lattice *UNUSED(latt)) +{ +} + diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index fa4f9c6ed52..c850216f5ef 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -45,6 +45,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_brush_types.h" +#include "DNA_cache_library_types.h" #include "DNA_camera_types.h" #include "DNA_group_types.h" #include "DNA_gpencil_types.h" @@ -79,6 +80,7 @@ #include "BKE_armature.h" #include "BKE_bpath.h" #include "BKE_brush.h" +#include "BKE_cache_library.h" #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_curve.h" @@ -107,6 +109,7 @@ #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" +#include "BKE_pointcache.h" #include "BKE_speaker.h" #include "BKE_sound.h" #include "BKE_screen.h" @@ -115,6 +118,8 @@ #include "BKE_texture.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #ifdef WITH_PYTHON @@ -291,7 +296,7 @@ bool id_make_local(ID *id, bool test) /** * Invokes the appropriate copy method for the block and returns the result in - * newid, unless test. Returns true iff the block can be copied. + * newid, unless test. Returns true if the block can be copied. */ bool id_copy(ID *id, ID **newid, bool test) { @@ -384,7 +389,7 @@ bool id_copy(ID *id, ID **newid, bool test) if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id); return true; case ID_LS: - if (!test) *newid = (ID *)BKE_linestyle_copy((FreestyleLineStyle *)id); + if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id); return true; } @@ -409,6 +414,10 @@ bool id_unlink(ID *id, int test) if (test) return true; BKE_object_unlink((Object *)id); break; + case ID_CL: + if (test) return true; + BKE_cache_library_unlink((CacheLibrary *)id); + break; } if (id->us == 0) { @@ -432,7 +441,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) if (RNA_property_editable(ptr, prop)) { if (id_copy(id, &newid, false) && newid) { /* copy animation actions too */ - BKE_copy_animdata_id_action(id); + BKE_animdata_copy_id_action(id); /* us is 1 by convention, but RNA_property_pointer_set * will also increment it, so set it to zero */ newid->us = 0; @@ -521,6 +530,8 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->palettes); case ID_PC: return &(mainlib->paintcurves); + case ID_CL: + return &(mainlib->cache_library); } return NULL; } @@ -610,13 +621,14 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++] = &(main->speaker); lb[a++] = &(main->world); + lb[a++] = &(main->movieclip); lb[a++] = &(main->screen); lb[a++] = &(main->object); lb[a++] = &(main->linestyle); /* referenced by scenes */ lb[a++] = &(main->scene); lb[a++] = &(main->library); + lb[a++] = &(main->cache_library); lb[a++] = &(main->wm); - lb[a++] = &(main->movieclip); lb[a++] = &(main->mask); lb[a] = NULL; @@ -747,6 +759,9 @@ static ID *alloc_libblock_notest(short type) case ID_PC: id = MEM_callocN(sizeof(PaintCurve), "Paint Curve"); break; + case ID_CL: + id = MEM_callocN(sizeof(CacheLibrary), "Cache Library"); + break; } return id; } @@ -785,7 +800,7 @@ static void id_copy_animdata(ID *id, const bool do_action) if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id; - iat->adt = BKE_copy_animdata(iat->adt, do_action); /* could be set to false, need to investigate */ + iat->adt = BKE_animdata_copy(iat->adt, do_action); /* could be set to false, need to investigate */ } } @@ -865,18 +880,24 @@ static void BKE_library_free(Library *lib) static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL; -void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) ) +void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) ) { free_windowmanager_cb = func; } static void (*free_notifier_reference_cb)(const void *) = NULL; -void set_free_notifier_reference_cb(void (*func)(const void *) ) +void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) ) { free_notifier_reference_cb = func; } +static void (*free_editor_id_reference_cb)(const ID *) = NULL; + +void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *)) +{ + free_editor_id_reference_cb = func; +} static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) { @@ -1029,13 +1050,21 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) case ID_PC: BKE_paint_curve_free((PaintCurve *)id); break; + case ID_CL: + BKE_cache_library_free((CacheLibrary *)id); + break; } /* avoid notifying on removed data */ BKE_main_lock(bmain); - if (free_notifier_reference_cb) + if (free_notifier_reference_cb) { free_notifier_reference_cb(id); + } + + if (free_editor_id_reference_cb) { + free_editor_id_reference_cb(id); + } BLI_remlink(lb, id); @@ -1070,8 +1099,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ Main *BKE_main_new(void) { Main *bmain = MEM_callocN(sizeof(Main), "new main"); - bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext), - "EvaluationContext"); + bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT); bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock"); BLI_spin_init((SpinLock *)bmain->lock); return bmain; @@ -1138,7 +1166,7 @@ void BKE_main_free(Main *mainvar) BLI_spin_end((SpinLock *)mainvar->lock); MEM_freeN(mainvar->lock); - MEM_freeN(mainvar->eval_ctx); + DEG_evaluation_context_free(mainvar->eval_ctx); MEM_freeN(mainvar); } @@ -1404,16 +1432,11 @@ void id_clear_lib_data(Main *bmain, ID *id) /* internal bNodeTree blocks inside ID types below * also stores id->lib, make sure this stays in sync. */ - switch (GS(id->name)) { - case ID_SCE: ntree = ((Scene *)id)->nodetree; break; - case ID_MA: ntree = ((Material *)id)->nodetree; break; - case ID_LA: ntree = ((Lamp *)id)->nodetree; break; - case ID_WO: ntree = ((World *)id)->nodetree; break; - case ID_TE: ntree = ((Tex *)id)->nodetree; break; - case ID_LS: ntree = ((FreestyleLineStyle *)id)->nodetree; break; - } - if (ntree) + ntree = ntreeFromID(id); + + if (ntree) { ntree->id.lib = NULL; + } } /* next to indirect usage in read/writefile also in editobject.c scene.c */ @@ -1603,7 +1626,7 @@ void rename_id(ID *id, const char *name) void name_uiprefix_id(char *name, const ID *id) { name[0] = id->lib ? 'L' : ' '; - name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' '; + name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); name[2] = ' '; strcpy(name + 3, id->name + 2); diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index b97bf0ed9b0..40db411ef4c 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -107,14 +107,11 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle) linestyle->caps = LS_CAPS_BUTT; } -FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main) +FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) { FreestyleLineStyle *linestyle; - if (!main) - main = G.main; - - linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(main, ID_LS, name); + linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name); default_linestyle_settings(linestyle); @@ -138,7 +135,7 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle) MEM_freeN(linestyle->nodetree); } - BKE_free_animdata(&linestyle->id); + BKE_animdata_free(&linestyle->id); while ((m = (LineStyleModifier *)linestyle->color_modifiers.first)) BKE_linestyle_color_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first)) @@ -149,13 +146,13 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle) BKE_linestyle_geometry_modifier_remove(linestyle, m); } -FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle) +FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle) { FreestyleLineStyle *new_linestyle; LineStyleModifier *m; int a; - new_linestyle = BKE_linestyle_new(linestyle->id.name + 2, NULL); + new_linestyle = BKE_linestyle_new(bmain, linestyle->id.name + 2); BKE_linestyle_free(new_linestyle); for (a = 0; a < MAX_MTEX; a++) { diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 387d093051e..13ec970c65c 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -1360,6 +1360,9 @@ float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float x case PROP_SHARP: value_layer = value_layer * value_layer; break; + case PROP_INVSQUARE: + value_layer = value_layer * (2.0f - value_layer); + break; case PROP_LIN: default: /* nothing */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 9b682f101ad..283c7a6fc88 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -53,6 +53,7 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_array_utils.h" #include "BKE_animsys.h" #include "BKE_displist.h" @@ -66,6 +67,8 @@ #include "BKE_scene.h" #include "BKE_node.h" #include "BKE_curve.h" +#include "BKE_editmesh.h" +#include "BKE_font.h" #include "GPU_material.h" @@ -99,11 +102,11 @@ void BKE_material_free_ex(Material *ma, bool do_id_user) if (ma->ramp_col) MEM_freeN(ma->ramp_col); if (ma->ramp_spec) MEM_freeN(ma->ramp_spec); - BKE_free_animdata((ID *)ma); + BKE_animdata_free((ID *)ma); if (ma->preview) BKE_previewimg_free(&ma->preview); - BKE_icon_delete((struct ID *)ma); + BKE_icon_id_delete((struct ID *)ma); ma->id.icon_id = 0; /* is no lib link block, but material extension */ @@ -806,9 +809,13 @@ void assign_material_id(ID *id, Material *ma, short act) if (act > MAXMAT) return; if (act < 1) act = 1; + /* this is needed for Python overrides, + * we just have to take care that the UI can't do this */ +#if 0 /* prevent crashing when using accidentally */ BLI_assert(id->lib == NULL); if (id->lib) return; +#endif /* test arraylens */ @@ -918,6 +925,35 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) test_object_materials(G.main, ob->data); } + +void BKE_material_remap_object(Object *ob, const unsigned int *remap) +{ + Material ***matar = give_matarar(ob); + const short *totcol_p = give_totcolp(ob); + + BLI_array_permute(ob->mat, ob->totcol, remap); + + if (ob->matbits) { + BLI_array_permute(ob->matbits, ob->totcol, remap); + } + + if (matar) { + BLI_array_permute(*matar, *totcol_p, remap); + } + + if (ob->type == OB_MESH) { + BKE_mesh_material_remap(ob->data, remap, ob->totcol); + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + BKE_curve_material_remap(ob->data, remap, ob->totcol); + } + else { + /* add support for this object data! */ + BLI_assert(matar == NULL); + } +} + + /* XXX - this calls many more update calls per object then are needed, could be optimized */ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol) { diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index ce20636233a..c09cd1aabdc 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -39,6 +39,7 @@ #include <stdlib.h> #include <ctype.h> #include <float.h> + #include "MEM_guardedalloc.h" #include "DNA_material_types.h" @@ -46,7 +47,6 @@ #include "DNA_meta_types.h" #include "DNA_scene_types.h" - #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -54,7 +54,6 @@ #include "BKE_global.h" #include "BKE_main.h" -/* #include "BKE_object.h" */ #include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" @@ -65,119 +64,6 @@ #include "BKE_object.h" #include "BKE_material.h" -/* Data types */ - -typedef struct vertex { /* surface vertex */ - float co[3]; /* position and surface normal */ - float no[3]; -} VERTEX; - -typedef struct vertices { /* list of vertices in polygonization */ - int count, max; /* # vertices, max # allowed */ - VERTEX *ptr; /* dynamically allocated */ -} VERTICES; - -typedef struct corner { /* corner of a cube */ - int i, j, k; /* (i, j, k) is index within lattice */ - float co[3], value; /* location and function value */ - struct corner *next; -} CORNER; - -typedef struct cube { /* partitioning cell (cube) */ - int i, j, k; /* lattice location of cube */ - CORNER *corners[8]; /* eight corners */ -} CUBE; - -typedef struct cubes { /* linked list of cubes acting as stack */ - CUBE cube; /* a single cube */ - struct cubes *next; /* remaining elements */ -} CUBES; - -typedef struct centerlist { /* list of cube locations */ - int i, j, k; /* cube location */ - struct centerlist *next; /* remaining elements */ -} CENTERLIST; - -typedef struct edgelist { /* list of edges */ - int i1, j1, k1, i2, j2, k2; /* edge corner ids */ - int vid; /* vertex id */ - struct edgelist *next; /* remaining elements */ -} EDGELIST; - -typedef struct intlist { /* list of integers */ - int i; /* an integer */ - struct intlist *next; /* remaining elements */ -} INTLIST; - -typedef struct intlists { /* list of list of integers */ - INTLIST *list; /* a list of integers */ - struct intlists *next; /* remaining elements */ -} INTLISTS; - -/* dividing scene using octal tree makes polygonisation faster */ -typedef struct ml_pointer { - struct ml_pointer *next, *prev; - struct MetaElem *ml; -} ml_pointer; - -typedef struct octal_node { - struct octal_node *nodes[8];/* children of current node */ - struct octal_node *parent; /* parent of current node */ - struct ListBase elems; /* ListBase of MetaElem pointers (ml_pointer) */ - float x_min, y_min, z_min; /* 1st border point */ - float x_max, y_max, z_max; /* 7th border point */ - float x, y, z; /* center of node */ - int pos, neg; /* number of positive and negative MetaElements in the node */ - int count; /* number of MetaElems, which belongs to the node */ -} octal_node; - -typedef struct octal_tree { - struct octal_node *first; /* first node */ - int pos, neg; /* number of positive and negative MetaElements in the scene */ - short depth; /* number of scene subdivision */ -} octal_tree; - -struct pgn_elements { - struct pgn_elements *next, *prev; - char *data; -}; - -typedef struct process { /* parameters, function, storage */ - /* ** old G_mb contents ** */ - float thresh; - int totelem; - MetaElem **mainb; - octal_tree *metaball_tree; - - /* ** old process contents ** */ - - /* what happens here? floats, I think. */ - /* float (*function)(void); */ /* implicit surface function */ - float (*function)(struct process *, float, float, float); - float size, delta; /* cube size, normal delta */ - int bounds; /* cube range within lattice */ - CUBES *cubes; /* active cubes */ - VERTICES vertices; /* surface vertices */ - CENTERLIST **centers; /* cube center hash table */ - CORNER **corners; /* corner value hash table */ - EDGELIST **edges; /* edge and vertex id hash table */ - - /* Runtime things */ - int *indices; - int totindex, curindex; - - int pgn_offset; - struct pgn_elements *pgn_current; - ListBase pgn_list; -} PROCESS; - -/* Forward declarations */ -static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, MetaBall *mb); -static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k); -static CORNER *setcorner(PROCESS *process, int i, int j, int k); -static void converge(PROCESS *process, const float p1[3], const float p2[3], float v1, float v2, - float p[3], MetaBall *mb, int f); - /* Functions */ void BKE_mball_unlink(MetaBall *mb) @@ -197,7 +83,7 @@ void BKE_mball_free(MetaBall *mb) BKE_mball_unlink(mb); if (mb->adt) { - BKE_free_animdata((ID *)mb); + BKE_animdata_free((ID *)mb); mb->adt = NULL; } if (mb->mat) MEM_freeN(mb->mat); @@ -558,1817 +444,6 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis) return basis; } - -/* ******************** ARITH ************************* */ - -/* BASED AT CODE (but mostly rewritten) : - * C code from the article - * "An Implicit Surface Polygonizer" - * by Jules Bloomenthal, jbloom@beauty.gmu.edu - * in "Graphics Gems IV", Academic Press, 1994 - * - * Authored by Jules Bloomenthal, Xerox PARC. - * Copyright (c) Xerox Corporation, 1991. All rights reserved. - * Permission is granted to reproduce, use and distribute this code for - * any and all purposes, provided that this notice appears in all copies. */ - -#define RES 12 /* # converge iterations */ - -#define L 0 /* left direction: -x, -i */ -#define R 1 /* right direction: +x, +i */ -#define B 2 /* bottom direction: -y, -j */ -#define T 3 /* top direction: +y, +j */ -#define N 4 /* near direction: -z, -k */ -#define F 5 /* far direction: +z, +k */ -#define LBN 0 /* left bottom near corner */ -#define LBF 1 /* left bottom far corner */ -#define LTN 2 /* left top near corner */ -#define LTF 3 /* left top far corner */ -#define RBN 4 /* right bottom near corner */ -#define RBF 5 /* right bottom far corner */ -#define RTN 6 /* right top near corner */ -#define RTF 7 /* right top far corner */ - -/* the LBN corner of cube (i, j, k), corresponds with location - * (i-0.5)*size, (j-0.5)*size, (k-0.5)*size) */ - -#define HASHBIT (5) -#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */ - -#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) ) - -#define MB_BIT(i, bit) (((i) >> (bit)) & 1) -#define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */ - - -/* **************** POLYGONIZATION ************************ */ - -static void calc_mballco(MetaElem *ml, float vec[3]) -{ - if (ml->mat) { - mul_m4_v3((float (*)[4])ml->mat, vec); - } -} - -static float densfunc(MetaElem *ball, float x, float y, float z) -{ - float dist2; - float dvec[3] = {x, y, z}; - - mul_m4_v3((float (*)[4])ball->imat, dvec); - - switch (ball->type) { - case MB_BALL: - /* do nothing */ - break; - case MB_TUBE: - if (dvec[0] > ball->expx) dvec[0] -= ball->expx; - else if (dvec[0] < -ball->expx) dvec[0] += ball->expx; - else dvec[0] = 0.0; - break; - case MB_PLANE: - if (dvec[0] > ball->expx) dvec[0] -= ball->expx; - else if (dvec[0] < -ball->expx) dvec[0] += ball->expx; - else dvec[0] = 0.0; - if (dvec[1] > ball->expy) dvec[1] -= ball->expy; - else if (dvec[1] < -ball->expy) dvec[1] += ball->expy; - else dvec[1] = 0.0; - break; - case MB_ELIPSOID: - dvec[0] /= ball->expx; - dvec[1] /= ball->expy; - dvec[2] /= ball->expz; - break; - case MB_CUBE: - if (dvec[0] > ball->expx) dvec[0] -= ball->expx; - else if (dvec[0] < -ball->expx) dvec[0] += ball->expx; - else dvec[0] = 0.0; - - if (dvec[1] > ball->expy) dvec[1] -= ball->expy; - else if (dvec[1] < -ball->expy) dvec[1] += ball->expy; - else dvec[1] = 0.0; - - if (dvec[2] > ball->expz) dvec[2] -= ball->expz; - else if (dvec[2] < -ball->expz) dvec[2] += ball->expz; - else dvec[2] = 0.0; - break; - - /* *** deprecated, could be removed?, do-versioned at least *** */ - case MB_TUBEX: - if (dvec[0] > ball->len) dvec[0] -= ball->len; - else if (dvec[0] < -ball->len) dvec[0] += ball->len; - else dvec[0] = 0.0; - break; - case MB_TUBEY: - if (dvec[1] > ball->len) dvec[1] -= ball->len; - else if (dvec[1] < -ball->len) dvec[1] += ball->len; - else dvec[1] = 0.0; - break; - case MB_TUBEZ: - if (dvec[2] > ball->len) dvec[2] -= ball->len; - else if (dvec[2] < -ball->len) dvec[2] += ball->len; - else dvec[2] = 0.0; - break; - /* *** end deprecated *** */ - } - - dist2 = 1.0f - (len_squared_v3(dvec) / ball->rad2); - - if ((ball->flag & MB_NEGATIVE) == 0) { - return (dist2 < 0.0f) ? -0.5f : (ball->s * dist2 * dist2 * dist2) - 0.5f; - } - else { - return (dist2 < 0.0f) ? 0.5f : 0.5f - (ball->s * dist2 * dist2 * dist2); - } -} - -static octal_node *find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth) -{ - if (!depth) return node; - - if (z < node->z) { - if (y < node->y) { - if (x < node->x) { - if (node->nodes[0]) - return find_metaball_octal_node(node->nodes[0], x, y, z, depth--); - else - return node; - } - else { - if (node->nodes[1]) - return find_metaball_octal_node(node->nodes[1], x, y, z, depth--); - else - return node; - } - } - else { - if (x < node->x) { - if (node->nodes[3]) - return find_metaball_octal_node(node->nodes[3], x, y, z, depth--); - else - return node; - } - else { - if (node->nodes[2]) - return find_metaball_octal_node(node->nodes[2], x, y, z, depth--); - else - return node; - } - } - } - else { - if (y < node->y) { - if (x < node->x) { - if (node->nodes[4]) - return find_metaball_octal_node(node->nodes[4], x, y, z, depth--); - else - return node; - } - else { - if (node->nodes[5]) - return find_metaball_octal_node(node->nodes[5], x, y, z, depth--); - else - return node; - } - } - else { - if (x < node->x) { - if (node->nodes[7]) - return find_metaball_octal_node(node->nodes[7], x, y, z, depth--); - else - return node; - } - else { - if (node->nodes[6]) - return find_metaball_octal_node(node->nodes[6], x, y, z, depth--); - else - return node; - } - } - } - - /* all cases accounted for */ - BLI_assert(0); -} - -static float metaball(PROCESS *process, float x, float y, float z) -/* float x, y, z; */ -{ - octal_tree *metaball_tree = process->metaball_tree; - struct octal_node *node; - struct ml_pointer *ml_p; - float dens = 0; - int a; - - if (process->totelem > 1) { - node = find_metaball_octal_node(metaball_tree->first, x, y, z, metaball_tree->depth); - if (node) { - for (ml_p = node->elems.first; ml_p; ml_p = ml_p->next) { - dens += densfunc(ml_p->ml, x, y, z); - } - - dens += -0.5f * (metaball_tree->pos - node->pos); - dens += 0.5f * (metaball_tree->neg - node->neg); - } - else { - for (a = 0; a < process->totelem; a++) { - dens += densfunc(process->mainb[a], x, y, z); - } - } - } - else { - dens += densfunc(process->mainb[0], x, y, z); - } - - return process->thresh - dens; -} - -/* ******************************************** */ - -static void accum_mballfaces(PROCESS *process, int i1, int i2, int i3, int i4) -{ - int *newi, *cur; - /* static int i = 0; I would like to delete altogether, but I don't dare to, yet */ - - if (process->totindex == process->curindex) { - process->totindex += 256; - newi = MEM_mallocN(4 * sizeof(int) * process->totindex, "vertindex"); - - if (process->indices) { - memcpy(newi, process->indices, 4 * sizeof(int) * (process->totindex - 256)); - MEM_freeN(process->indices); - } - process->indices = newi; - } - - cur = process->indices + 4 * process->curindex; - - /* displists now support array drawing, we treat tri's as fake quad */ - - cur[0] = i1; - cur[1] = i2; - cur[2] = i3; - if (i4 == 0) - cur[3] = i3; - else - cur[3] = i4; - - process->curindex++; - -} - -/* ******************* MEMORY MANAGEMENT *********************** */ -static void *new_pgn_element(PROCESS *process, int size) -{ - /* during polygonize 1000s of elements are allocated - * and never freed in between. Freeing only done at the end. - */ - int blocksize = 16384; - void *adr; - - if (size > 10000 || size == 0) { - printf("incorrect use of new_pgn_element\n"); - } - else if (size == -1) { - struct pgn_elements *cur = process->pgn_list.first; - while (cur) { - MEM_freeN(cur->data); - cur = cur->next; - } - BLI_freelistN(&process->pgn_list); - - return NULL; - } - - size = 4 * ( (size + 3) / 4); - - if (process->pgn_current) { - if (size + process->pgn_offset < blocksize) { - adr = (void *) (process->pgn_current->data + process->pgn_offset); - process->pgn_offset += size; - return adr; - } - } - - process->pgn_current = MEM_callocN(sizeof(struct pgn_elements), "newpgn"); - process->pgn_current->data = MEM_callocN(blocksize, "newpgn"); - BLI_addtail(&process->pgn_list, process->pgn_current); - - process->pgn_offset = size; - return process->pgn_current->data; -} - -static void freepolygonize(PROCESS *process) -{ - MEM_freeN(process->corners); - MEM_freeN(process->edges); - MEM_freeN(process->centers); - - new_pgn_element(process, -1); - - if (process->vertices.ptr) { - MEM_freeN(process->vertices.ptr); - } -} - -/**** Cubical Polygonization (optional) ****/ - -#define LB 0 /* left bottom edge */ -#define LT 1 /* left top edge */ -#define LN 2 /* left near edge */ -#define LF 3 /* left far edge */ -#define RB 4 /* right bottom edge */ -#define RT 5 /* right top edge */ -#define RN 6 /* right near edge */ -#define RF 7 /* right far edge */ -#define BN 8 /* bottom near edge */ -#define BF 9 /* bottom far edge */ -#define TN 10 /* top near edge */ -#define TF 11 /* top far edge */ - -static INTLISTS *cubetable[256]; - -/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */ -static int corner1[12] = { - LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF -}; -static int corner2[12] = { - LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF -}; -static int leftface[12] = { - B, L, L, F, R, T, N, R, N, B, T, F -}; -/* face on left when going corner1 to corner2 */ -static int rightface[12] = { - L, T, N, L, B, R, R, F, B, F, N, T -}; -/* face on right when going corner1 to corner2 */ - - -/* docube: triangulate the cube directly, without decomposition */ - -static void docube(PROCESS *process, CUBE *cube, MetaBall *mb) -{ - INTLISTS *polys; - CORNER *c1, *c2; - int i, index = 0, count, indexar[8]; - - for (i = 0; i < 8; i++) { - if (cube->corners[i]->value > 0.0f) { - index += (1 << i); - } - } - - for (polys = cubetable[index]; polys; polys = polys->next) { - INTLIST *edges; - - count = 0; - - for (edges = polys->list; edges; edges = edges->next) { - c1 = cube->corners[corner1[edges->i]]; - c2 = cube->corners[corner2[edges->i]]; - - indexar[count] = vertid(process, c1, c2, mb); - count++; - } - if (count > 2) { - switch (count) { - case 3: - accum_mballfaces(process, indexar[2], indexar[1], indexar[0], 0); - break; - case 4: - if (indexar[0] == 0) accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]); - else accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]); - break; - case 5: - if (indexar[0] == 0) accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]); - else accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]); - - accum_mballfaces(process, indexar[4], indexar[3], indexar[0], 0); - break; - case 6: - if (indexar[0] == 0) { - accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]); - accum_mballfaces(process, indexar[0], indexar[5], indexar[4], indexar[3]); - } - else { - accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]); - accum_mballfaces(process, indexar[5], indexar[4], indexar[3], indexar[0]); - } - break; - case 7: - if (indexar[0] == 0) { - accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]); - accum_mballfaces(process, indexar[0], indexar[5], indexar[4], indexar[3]); - } - else { - accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]); - accum_mballfaces(process, indexar[5], indexar[4], indexar[3], indexar[0]); - } - - accum_mballfaces(process, indexar[6], indexar[5], indexar[0], 0); - - break; - } - } - } -} - - -/* testface: given cube at lattice (i, j, k), and four corners of face, - * if surface crosses face, compute other four corners of adjacent cube - * and add new cube to cube stack */ - -static void testface(PROCESS *process, int i, int j, int k, CUBE *old, int bit, int c1, int c2, int c3, int c4) -{ - CUBE newc; - CUBES *oldcubes = process->cubes; - CORNER *corn1, *corn2, *corn3, *corn4; - int n, pos; - - corn1 = old->corners[c1]; - corn2 = old->corners[c2]; - corn3 = old->corners[c3]; - corn4 = old->corners[c4]; - - pos = corn1->value > 0.0f ? 1 : 0; - - /* test if no surface crossing */ - if ( (corn2->value > 0) == pos && (corn3->value > 0) == pos && (corn4->value > 0) == pos) return; - /* test if cube out of bounds */ - /*if ( abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;*/ - /* test if already visited (always as last) */ - if (setcenter(process, process->centers, i, j, k)) { - return; - } - - /* create new cube and add cube to top of stack: */ - process->cubes = (CUBES *) new_pgn_element(process, sizeof(CUBES)); - process->cubes->next = oldcubes; - - newc.i = i; - newc.j = j; - newc.k = k; - for (n = 0; n < 8; n++) newc.corners[n] = NULL; - - newc.corners[FLIP(c1, bit)] = corn1; - newc.corners[FLIP(c2, bit)] = corn2; - newc.corners[FLIP(c3, bit)] = corn3; - newc.corners[FLIP(c4, bit)] = corn4; - - if (newc.corners[0] == NULL) newc.corners[0] = setcorner(process, i, j, k); - if (newc.corners[1] == NULL) newc.corners[1] = setcorner(process, i, j, k + 1); - if (newc.corners[2] == NULL) newc.corners[2] = setcorner(process, i, j + 1, k); - if (newc.corners[3] == NULL) newc.corners[3] = setcorner(process, i, j + 1, k + 1); - if (newc.corners[4] == NULL) newc.corners[4] = setcorner(process, i + 1, j, k); - if (newc.corners[5] == NULL) newc.corners[5] = setcorner(process, i + 1, j, k + 1); - if (newc.corners[6] == NULL) newc.corners[6] = setcorner(process, i + 1, j + 1, k); - if (newc.corners[7] == NULL) newc.corners[7] = setcorner(process, i + 1, j + 1, k + 1); - - process->cubes->cube = newc; -} - -/* setcorner: return corner with the given lattice location - * set (and cache) its function value */ - -static CORNER *setcorner(PROCESS *process, int i, int j, int k) -{ - /* for speed, do corner value caching here */ - CORNER *c; - int index; - - /* does corner exist? */ - index = HASH(i, j, k); - c = process->corners[index]; - - for (; c != NULL; c = c->next) { - if (c->i == i && c->j == j && c->k == k) { - return c; - } - } - - c = (CORNER *) new_pgn_element(process, sizeof(CORNER)); - - c->i = i; - c->co[0] = ((float)i - 0.5f) * process->size; - c->j = j; - c->co[1] = ((float)j - 0.5f) * process->size; - c->k = k; - c->co[2] = ((float)k - 0.5f) * process->size; - c->value = process->function(process, c->co[0], c->co[1], c->co[2]); - - c->next = process->corners[index]; - process->corners[index] = c; - - return c; -} - - -/* nextcwedge: return next clockwise edge from given edge around given face */ - -static int nextcwedge(int edge, int face) -{ - switch (edge) { - case LB: - return (face == L) ? LF : BN; - case LT: - return (face == L) ? LN : TF; - case LN: - return (face == L) ? LB : TN; - case LF: - return (face == L) ? LT : BF; - case RB: - return (face == R) ? RN : BF; - case RT: - return (face == R) ? RF : TN; - case RN: - return (face == R) ? RT : BN; - case RF: - return (face == R) ? RB : TF; - case BN: - return (face == B) ? RB : LN; - case BF: - return (face == B) ? LB : RF; - case TN: - return (face == T) ? LT : RN; - case TF: - return (face == T) ? RT : LF; - } - return 0; -} - - -/* otherface: return face adjoining edge that is not the given face */ - -static int otherface(int edge, int face) -{ - int other = leftface[edge]; - return face == other ? rightface[edge] : other; -} - - -/* makecubetable: create the 256 entry table for cubical polygonization */ - -static void makecubetable(void) -{ - static bool is_done = false; - int i, e, c, done[12], pos[8]; - - if (is_done) return; - is_done = true; - - for (i = 0; i < 256; i++) { - for (e = 0; e < 12; e++) done[e] = 0; - for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c); - for (e = 0; e < 12; e++) - if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) { - INTLIST *ints = NULL; - INTLISTS *lists = (INTLISTS *) MEM_callocN(sizeof(INTLISTS), "mball_intlist"); - int start = e, edge = e; - - /* get face that is to right of edge from pos to neg corner: */ - int face = pos[corner1[e]] ? rightface[e] : leftface[e]; - - while (1) { - edge = nextcwedge(edge, face); - done[edge] = 1; - if (pos[corner1[edge]] != pos[corner2[edge]]) { - INTLIST *tmp = ints; - - ints = (INTLIST *) MEM_callocN(sizeof(INTLIST), "mball_intlist"); - ints->i = edge; - ints->next = tmp; /* add edge to head of list */ - - if (edge == start) break; - face = otherface(edge, face); - } - } - lists->list = ints; /* add ints to head of table entry */ - lists->next = cubetable[i]; - cubetable[i] = lists; - } - } -} - -void BKE_mball_cubeTable_free(void) -{ - int i; - INTLISTS *lists, *nlists; - INTLIST *ints, *nints; - - for (i = 0; i < 256; i++) { - lists = cubetable[i]; - while (lists) { - nlists = lists->next; - - ints = lists->list; - while (ints) { - nints = ints->next; - MEM_freeN(ints); - ints = nints; - } - - MEM_freeN(lists); - lists = nlists; - } - cubetable[i] = NULL; - } -} - -/**** Storage ****/ - -/* setcenter: set (i, j, k) entry of table[] - * return 1 if already set; otherwise, set and return 0 */ - -static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k) -{ - int index; - CENTERLIST *newc, *l, *q; - - index = HASH(i, j, k); - q = table[index]; - - for (l = q; l != NULL; l = l->next) { - if (l->i == i && l->j == j && l->k == k) return 1; - } - - newc = (CENTERLIST *) new_pgn_element(process, sizeof(CENTERLIST)); - newc->i = i; - newc->j = j; - newc->k = k; - newc->next = q; - table[index] = newc; - - return 0; -} - - -/* setedge: set vertex id for edge */ - -static void setedge(PROCESS *process, - EDGELIST *table[], - int i1, int j1, - int k1, int i2, - int j2, int k2, - int vid) -{ - unsigned int index; - EDGELIST *newe; - - if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) { - int t = i1; - i1 = i2; - i2 = t; - t = j1; - j1 = j2; - j2 = t; - t = k1; - k1 = k2; - k2 = t; - } - index = HASH(i1, j1, k1) + HASH(i2, j2, k2); - newe = (EDGELIST *) new_pgn_element(process, sizeof(EDGELIST)); - newe->i1 = i1; - newe->j1 = j1; - newe->k1 = k1; - newe->i2 = i2; - newe->j2 = j2; - newe->k2 = k2; - newe->vid = vid; - newe->next = table[index]; - table[index] = newe; -} - - -/* getedge: return vertex id for edge; return -1 if not set */ - -static int getedge(EDGELIST *table[], - int i1, int j1, int k1, - int i2, int j2, int k2) -{ - EDGELIST *q; - - if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) { - int t = i1; - i1 = i2; - i2 = t; - t = j1; - j1 = j2; - j2 = t; - t = k1; - k1 = k2; - k2 = t; - } - q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)]; - for (; q != NULL; q = q->next) { - if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 && - q->i2 == i2 && q->j2 == j2 && q->k2 == k2) - { - return q->vid; - } - } - return -1; -} - - -/**** Vertices ****/ - -#undef R - - - -/* vertid: return index for vertex on edge: - * c1->value and c2->value are presumed of different sign - * return saved index if any; else compute vertex and save */ - -/* addtovertices: add v to sequence of vertices */ - -static void addtovertices(VERTICES *vertices, VERTEX v) -{ - if (vertices->count == vertices->max) { - int i; - VERTEX *newv; - vertices->max = vertices->count == 0 ? 10 : 2 * vertices->count; - newv = (VERTEX *) MEM_callocN(vertices->max * sizeof(VERTEX), "addtovertices"); - - for (i = 0; i < vertices->count; i++) newv[i] = vertices->ptr[i]; - - if (vertices->ptr != NULL) MEM_freeN(vertices->ptr); - vertices->ptr = newv; - } - vertices->ptr[vertices->count++] = v; -} - -/* vnormal: compute unit length surface normal at point */ - -static void vnormal(PROCESS *process, const float point[3], float r_no[3]) -{ - const float delta = 0.2f * process->delta; - const float f = process->function(process, point[0], point[1], point[2]); - - r_no[0] = process->function(process, point[0] + delta, point[1], point[2]) - f; - r_no[1] = process->function(process, point[0], point[1] + delta, point[2]) - f; - r_no[2] = process->function(process, point[0], point[1], point[2] + delta) - f; - -#if 1 - normalize_v3(r_no); -#else - f = normalize_v3(r_no); - - if (0) { - float tvec[3]; - - delta *= 2.0f; - - f = process->function(process, point[0], point[1], point[2]); - - tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f; - tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f; - tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f; - - if (normalize_v3(tvec) != 0.0f) { - add_v3_v3(r_no, tvec); - normalize_v3(r_no); - } - } -#endif -} - - -static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, MetaBall *mb) -{ - VERTEX v; - int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); - - if (vid != -1) { - return vid; /* previously computed */ - } - - converge(process, c1->co, c2->co, c1->value, c2->value, v.co, mb, 1); /* position */ - vnormal(process, v.co, v.no); - - addtovertices(&process->vertices, v); /* save vertex */ - vid = process->vertices.count - 1; - setedge(process, process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); - - return vid; -} - - -/* converge: from two points of differing sign, converge to zero crossing */ -/* watch it: p1 and p2 are used to calculate */ -static void converge(PROCESS *process, const float p1[3], const float p2[3], float v1, float v2, - float p[3], MetaBall *mb, int f) -{ - int i = 0; - float pos[3], neg[3]; - float positive = 0.0f, negative = 0.0f; - float dvec[3]; - - if (v1 < 0) { - copy_v3_v3(pos, p2); - copy_v3_v3(neg, p1); - positive = v2; - negative = v1; - } - else { - copy_v3_v3(pos, p1); - copy_v3_v3(neg, p2); - positive = v1; - negative = v2; - } - - sub_v3_v3v3(dvec, pos, neg); - -/* Approximation by linear interpolation is faster then binary subdivision, - * but it results sometimes (mb->thresh < 0.2) into the strange results */ - if ((mb->thresh > 0.2f) && (f == 1)) { - if ((dvec[1] == 0.0f) && (dvec[2] == 0.0f)) { - p[0] = neg[0] - negative * dvec[0] / (positive - negative); - p[1] = neg[1]; - p[2] = neg[2]; - return; - } - if ((dvec[0] == 0.0f) && (dvec[2] == 0.0f)) { - p[0] = neg[0]; - p[1] = neg[1] - negative * dvec[1] / (positive - negative); - p[2] = neg[2]; - return; - } - if ((dvec[0] == 0.0f) && (dvec[1] == 0.0f)) { - p[0] = neg[0]; - p[1] = neg[1]; - p[2] = neg[2] - negative * dvec[2] / (positive - negative); - return; - } - } - - if ((dvec[1] == 0.0f) && (dvec[2] == 0.0f)) { - p[1] = neg[1]; - p[2] = neg[2]; - while (1) { - if (i++ == RES) return; - p[0] = 0.5f * (pos[0] + neg[0]); - if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[0] = p[0]; - else neg[0] = p[0]; - } - } - - if ((dvec[0] == 0.0f) && (dvec[2] == 0.0f)) { - p[0] = neg[0]; - p[2] = neg[2]; - while (1) { - if (i++ == RES) return; - p[1] = 0.5f * (pos[1] + neg[1]); - if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[1] = p[1]; - else neg[1] = p[1]; - } - } - - if ((dvec[0] == 0.0f) && (dvec[1] == 0.0f)) { - p[0] = neg[0]; - p[1] = neg[1]; - while (1) { - if (i++ == RES) return; - p[2] = 0.5f * (pos[2] + neg[2]); - if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[2] = p[2]; - else neg[2] = p[2]; - } - } - - /* This is necessary to find start point */ - while (1) { - mid_v3_v3v3(&p[0], pos, neg); - - if (i++ == RES) { - return; - } - - if ((process->function(process, p[0], p[1], p[2])) > 0.0f) { - copy_v3_v3(pos, &p[0]); - } - else { - copy_v3_v3(neg, &p[0]); - } - } -} - -/* ************************************** */ -static void add_cube(PROCESS *process, int i, int j, int k, int count) -{ - CUBES *ncube; - int n; - int a, b, c; - - /* hmmm, not only one, but eight cube will be added on the stack - * ... */ - for (a = i - 1; a < i + count; a++) - for (b = j - 1; b < j + count; b++) - for (c = k - 1; c < k + count; c++) { - /* test if cube has been found before */ - if (setcenter(process, process->centers, a, b, c) == 0) { - /* push cube on stack: */ - ncube = (CUBES *) new_pgn_element(process, sizeof(CUBES)); - ncube->next = process->cubes; - process->cubes = ncube; - - ncube->cube.i = a; - ncube->cube.j = b; - ncube->cube.k = c; - - /* set corners of initial cube: */ - for (n = 0; n < 8; n++) - ncube->cube.corners[n] = setcorner(process, a + MB_BIT(n, 2), b + MB_BIT(n, 1), c + MB_BIT(n, 0)); - } - } -} - - -static void find_first_points(PROCESS *process, MetaBall *mb, int a) -{ - MetaElem *ml; - float f; - - ml = process->mainb[a]; - f = 1.0f - (mb->thresh / ml->s); - - /* Skip, when Stiffness of MetaElement is too small ... MetaElement can't be - * visible alone ... but still can influence others MetaElements :-) */ - if (f > 0.0f) { - float IN[3] = {0.0f}, OUT[3] = {0.0f}, in[3] = {0.0f}, out[3]; - int i, j, k, c_i, c_j, c_k; - int index[3] = {1, 0, -1}; - float in_v /*, out_v*/; - float workp[3]; - float dvec[3]; - float tmp_v, workp_v, max_len_sq, nx, ny, nz, max_dim; - - calc_mballco(ml, in); - in_v = process->function(process, in[0], in[1], in[2]); - - for (i = 0; i < 3; i++) { - switch (ml->type) { - case MB_BALL: - OUT[0] = out[0] = IN[0] + index[i] * ml->rad; - break; - case MB_TUBE: - case MB_PLANE: - case MB_ELIPSOID: - case MB_CUBE: - OUT[0] = out[0] = IN[0] + index[i] * (ml->expx + ml->rad); - break; - } - - for (j = 0; j < 3; j++) { - switch (ml->type) { - case MB_BALL: - OUT[1] = out[1] = IN[1] + index[j] * ml->rad; - break; - case MB_TUBE: - case MB_PLANE: - case MB_ELIPSOID: - case MB_CUBE: - OUT[1] = out[1] = IN[1] + index[j] * (ml->expy + ml->rad); - break; - } - - for (k = 0; k < 3; k++) { - out[0] = OUT[0]; - out[1] = OUT[1]; - switch (ml->type) { - case MB_BALL: - case MB_TUBE: - case MB_PLANE: - out[2] = IN[2] + index[k] * ml->rad; - break; - case MB_ELIPSOID: - case MB_CUBE: - out[2] = IN[2] + index[k] * (ml->expz + ml->rad); - break; - } - - calc_mballco(ml, out); - - /*out_v = process->function(out[0], out[1], out[2]);*/ /*UNUSED*/ - - /* find "first points" on Implicit Surface of MetaElemnt ml */ - copy_v3_v3(workp, in); - workp_v = in_v; - max_len_sq = len_squared_v3v3(out, in); - - nx = fabsf((out[0] - in[0]) / process->size); - ny = fabsf((out[1] - in[1]) / process->size); - nz = fabsf((out[2] - in[2]) / process->size); - - max_dim = max_fff(nx, ny, nz); - if (max_dim != 0.0f) { - float len_sq = 0.0f; - - dvec[0] = (out[0] - in[0]) / max_dim; - dvec[1] = (out[1] - in[1]) / max_dim; - dvec[2] = (out[2] - in[2]) / max_dim; - - while (len_sq <= max_len_sq) { - add_v3_v3(workp, dvec); - - /* compute value of implicite function */ - tmp_v = process->function(process, workp[0], workp[1], workp[2]); - /* add cube to the stack, when value of implicite function crosses zero value */ - if ((tmp_v < 0.0f && workp_v >= 0.0f) || (tmp_v > 0.0f && workp_v <= 0.0f)) { - - /* indexes of CUBE, which includes "first point" */ - c_i = (int)floor(workp[0] / process->size); - c_j = (int)floor(workp[1] / process->size); - c_k = (int)floor(workp[2] / process->size); - - /* add CUBE (with indexes c_i, c_j, c_k) to the stack, - * this cube includes found point of Implicit Surface */ - if ((ml->flag & MB_NEGATIVE) == 0) { - add_cube(process, c_i, c_j, c_k, 1); - } - else { - add_cube(process, c_i, c_j, c_k, 2); - } - } - len_sq = len_squared_v3v3(workp, in); - workp_v = tmp_v; - - } - } - } - } - } - } -} - -static void polygonize(PROCESS *process, MetaBall *mb) -{ - CUBE c; - int a; - - process->vertices.count = process->vertices.max = 0; - process->vertices.ptr = NULL; - - /* allocate hash tables and build cube polygon table: */ - process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers"); - process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners"); - process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges"); - makecubetable(); - - for (a = 0; a < process->totelem; a++) { - - /* try to find 8 points on the surface for each MetaElem */ - find_first_points(process, mb, a); - } - - /* polygonize all MetaElems of current MetaBall */ - while (process->cubes != NULL) { /* process active cubes till none left */ - c = process->cubes->cube; - - /* polygonize the cube directly: */ - docube(process, &c, mb); - - /* pop current cube from stack */ - process->cubes = process->cubes->next; - - /* test six face directions, maybe add to stack: */ - testface(process, c.i - 1, c.j, c.k, &c, 2, LBN, LBF, LTN, LTF); - testface(process, c.i + 1, c.j, c.k, &c, 2, RBN, RBF, RTN, RTF); - testface(process, c.i, c.j - 1, c.k, &c, 1, LBN, LBF, RBN, RBF); - testface(process, c.i, c.j + 1, c.k, &c, 1, LTN, LTF, RTN, RTF); - testface(process, c.i, c.j, c.k - 1, &c, 0, LBN, LTN, RBN, RTN); - testface(process, c.i, c.j, c.k + 1, &c, 0, LBF, LTF, RBF, RTF); - } -} - -static float init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) /* return totsize */ -{ - Scene *sce_iter = scene; - Base *base; - Object *bob; - MetaBall *mb; - MetaElem *ml; - float size, totsize, obinv[4][4], obmat[4][4], vec[3]; - //float max = 0.0f; - int a, obnr, zero_size = 0; - char obname[MAX_ID_NAME]; - SceneBaseIter iter; - - copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ - invert_m4_m4(obinv, ob->obmat); - a = 0; - - BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - - /* make main array */ - BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) { - - if (bob->type == OB_MBALL) { - zero_size = 0; - ml = NULL; - - if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { - mb = ob->data; - - if (mb->editelems) ml = mb->editelems->first; - else ml = mb->elems.first; - } - else { - char name[MAX_ID_NAME]; - int nr; - - BLI_split_name_num(name, &nr, bob->id.name + 2, '.'); - if (STREQ(obname, name)) { - mb = bob->data; - - if (mb->editelems) ml = mb->editelems->first; - else ml = mb->elems.first; - } - } - - /* when metaball object has zero scale, then MetaElem to this MetaBall - * will not be put to mainb array */ - if (has_zero_axis_m4(bob->obmat)) { - zero_size = 1; - } - else if (bob->parent) { - struct Object *pob = bob->parent; - while (pob) { - if (has_zero_axis_m4(pob->obmat)) { - zero_size = 1; - break; - } - pob = pob->parent; - } - } - - if (zero_size) { - unsigned int ml_count = 0; - while (ml) { - ml_count++; - ml = ml->next; - } - process->totelem -= ml_count; - } - else { - while (ml) { - if (!(ml->flag & MB_HIDE)) { - int i; - float temp1[4][4], temp2[4][4], temp3[4][4]; - float (*mat)[4] = NULL, (*imat)[4] = NULL; - float max_x, max_y, max_z, min_x, min_y, min_z; - float expx, expy, expz; - - max_x = max_y = max_z = -3.4e38; - min_x = min_y = min_z = 3.4e38; - - /* too big stiffness seems only ugly due to linear interpolation - * no need to have possibility for too big stiffness */ - if (ml->s > 10.0f) ml->s = 10.0f; - - /* Rotation of MetaElem is stored in quat */ - quat_to_mat4(temp3, ml->quat); - - /* Translation of MetaElem */ - unit_m4(temp2); - temp2[3][0] = ml->x; - temp2[3][1] = ml->y; - temp2[3][2] = ml->z; - - mul_m4_m4m4(temp1, temp2, temp3); - - /* make a copy because of duplicates */ - process->mainb[a] = new_pgn_element(process, sizeof(MetaElem)); - *(process->mainb[a]) = *ml; - process->mainb[a]->bb = new_pgn_element(process, sizeof(BoundBox)); - - mat = new_pgn_element(process, 4 * 4 * sizeof(float)); - imat = new_pgn_element(process, 4 * 4 * sizeof(float)); - - /* mat is the matrix to transform from mball into the basis-mball */ - invert_m4_m4(obinv, obmat); - mul_m4_m4m4(temp2, obinv, bob->obmat); - /* MetaBall transformation */ - mul_m4_m4m4(mat, temp2, temp1); - - invert_m4_m4(imat, mat); - - process->mainb[a]->rad2 = ml->rad * ml->rad; - - process->mainb[a]->mat = (float *) mat; - process->mainb[a]->imat = (float *) imat; - - if (!MB_TYPE_SIZE_SQUARED(ml->type)) { - expx = ml->expx; - expy = ml->expy; - expz = ml->expz; - } - else { - expx = ml->expx * ml->expx; - expy = ml->expy * ml->expy; - expz = ml->expz * ml->expz; - } - - /* untransformed Bounding Box of MetaElem */ - /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */ - copy_v3_fl3(process->mainb[a]->bb->vec[0], -expx, -expy, -expz); /* 0 */ - copy_v3_fl3(process->mainb[a]->bb->vec[1], +expx, -expy, -expz); /* 1 */ - copy_v3_fl3(process->mainb[a]->bb->vec[2], +expx, +expy, -expz); /* 2 */ - copy_v3_fl3(process->mainb[a]->bb->vec[3], -expx, +expy, -expz); /* 3 */ - copy_v3_fl3(process->mainb[a]->bb->vec[4], -expx, -expy, +expz); /* 4 */ - copy_v3_fl3(process->mainb[a]->bb->vec[5], +expx, -expy, +expz); /* 5 */ - copy_v3_fl3(process->mainb[a]->bb->vec[6], +expx, +expy, +expz); /* 6 */ - copy_v3_fl3(process->mainb[a]->bb->vec[7], -expx, +expy, +expz); /* 7 */ - - /* transformation of Metalem bb */ - for (i = 0; i < 8; i++) - mul_m4_v3((float (*)[4])mat, process->mainb[a]->bb->vec[i]); - - /* find max and min of transformed bb */ - for (i = 0; i < 8; i++) { - /* find maximums */ - if (process->mainb[a]->bb->vec[i][0] > max_x) max_x = process->mainb[a]->bb->vec[i][0]; - if (process->mainb[a]->bb->vec[i][1] > max_y) max_y = process->mainb[a]->bb->vec[i][1]; - if (process->mainb[a]->bb->vec[i][2] > max_z) max_z = process->mainb[a]->bb->vec[i][2]; - /* find minimums */ - if (process->mainb[a]->bb->vec[i][0] < min_x) min_x = process->mainb[a]->bb->vec[i][0]; - if (process->mainb[a]->bb->vec[i][1] < min_y) min_y = process->mainb[a]->bb->vec[i][1]; - if (process->mainb[a]->bb->vec[i][2] < min_z) min_z = process->mainb[a]->bb->vec[i][2]; - } - - /* create "new" bb, only point 0 and 6, which are - * necessary for octal tree filling */ - process->mainb[a]->bb->vec[0][0] = min_x - ml->rad; - process->mainb[a]->bb->vec[0][1] = min_y - ml->rad; - process->mainb[a]->bb->vec[0][2] = min_z - ml->rad; - - process->mainb[a]->bb->vec[6][0] = max_x + ml->rad; - process->mainb[a]->bb->vec[6][1] = max_y + ml->rad; - process->mainb[a]->bb->vec[6][2] = max_z + ml->rad; - - a++; - } - ml = ml->next; - } - } - } - } - - - /* totsize (= 'manhattan' radius) */ - totsize = 0.0; - for (a = 0; a < process->totelem; a++) { - - vec[0] = process->mainb[a]->x + process->mainb[a]->rad + process->mainb[a]->expx; - vec[1] = process->mainb[a]->y + process->mainb[a]->rad + process->mainb[a]->expy; - vec[2] = process->mainb[a]->z + process->mainb[a]->rad + process->mainb[a]->expz; - - calc_mballco(process->mainb[a], vec); - - size = fabsf(vec[0]); - if (size > totsize) totsize = size; - size = fabsf(vec[1]); - if (size > totsize) totsize = size; - size = fabsf(vec[2]); - if (size > totsize) totsize = size; - - vec[0] = process->mainb[a]->x - process->mainb[a]->rad; - vec[1] = process->mainb[a]->y - process->mainb[a]->rad; - vec[2] = process->mainb[a]->z - process->mainb[a]->rad; - - calc_mballco(process->mainb[a], vec); - - size = fabsf(vec[0]); - if (size > totsize) totsize = size; - size = fabsf(vec[1]); - if (size > totsize) totsize = size; - size = fabsf(vec[2]); - if (size > totsize) totsize = size; - } - - for (a = 0; a < process->totelem; a++) { - process->thresh += densfunc(process->mainb[a], 2.0f * totsize, 2.0f * totsize, 2.0f * totsize); - } - - return totsize; -} - -/* if MetaElem lies in node, then node includes MetaElem pointer (ml_p) - * pointing at MetaElem (ml) - */ -static void fill_metaball_octal_node(octal_node *node, MetaElem *ml, short i) -{ - ml_pointer *ml_p; - - ml_p = MEM_mallocN(sizeof(ml_pointer), "ml_pointer"); - ml_p->ml = ml; - BLI_addtail(&(node->nodes[i]->elems), ml_p); - node->count++; - - if ((ml->flag & MB_NEGATIVE) == 0) { - node->nodes[i]->pos++; - } - else { - node->nodes[i]->neg++; - } -} - -/* Node is subdivided as is illustrated on the following figure: - * - * +------+------+ - * / / /| - * +------+------+ | - * / / /| + - * +------+------+ |/| - * | | | + | - * | | |/| + - * +------+------+ |/ - * | | | + - * | | |/ - * +------+------+ - * - */ -static void subdivide_metaball_octal_node(octal_node *node, float size_x, float size_y, float size_z, short depth) -{ - MetaElem *ml; - ml_pointer *ml_p; - float x, y, z; - int a, i; - - /* create new nodes */ - for (a = 0; a < 8; a++) { - node->nodes[a] = MEM_mallocN(sizeof(octal_node), "octal_node"); - for (i = 0; i < 8; i++) - node->nodes[a]->nodes[i] = NULL; - node->nodes[a]->parent = node; - BLI_listbase_clear(&node->nodes[a]->elems); - node->nodes[a]->count = 0; - node->nodes[a]->neg = 0; - node->nodes[a]->pos = 0; - } - - size_x /= 2; - size_y /= 2; - size_z /= 2; - - /* center of node */ - node->x = x = node->x_min + size_x; - node->y = y = node->y_min + size_y; - node->z = z = node->z_min + size_z; - - /* setting up of border points of new nodes */ - node->nodes[0]->x_min = node->x_min; - node->nodes[0]->y_min = node->y_min; - node->nodes[0]->z_min = node->z_min; - node->nodes[0]->x = node->nodes[0]->x_min + size_x / 2; - node->nodes[0]->y = node->nodes[0]->y_min + size_y / 2; - node->nodes[0]->z = node->nodes[0]->z_min + size_z / 2; - - node->nodes[1]->x_min = x; - node->nodes[1]->y_min = node->y_min; - node->nodes[1]->z_min = node->z_min; - node->nodes[1]->x = node->nodes[1]->x_min + size_x / 2; - node->nodes[1]->y = node->nodes[1]->y_min + size_y / 2; - node->nodes[1]->z = node->nodes[1]->z_min + size_z / 2; - - node->nodes[2]->x_min = x; - node->nodes[2]->y_min = y; - node->nodes[2]->z_min = node->z_min; - node->nodes[2]->x = node->nodes[2]->x_min + size_x / 2; - node->nodes[2]->y = node->nodes[2]->y_min + size_y / 2; - node->nodes[2]->z = node->nodes[2]->z_min + size_z / 2; - - node->nodes[3]->x_min = node->x_min; - node->nodes[3]->y_min = y; - node->nodes[3]->z_min = node->z_min; - node->nodes[3]->x = node->nodes[3]->x_min + size_x / 2; - node->nodes[3]->y = node->nodes[3]->y_min + size_y / 2; - node->nodes[3]->z = node->nodes[3]->z_min + size_z / 2; - - node->nodes[4]->x_min = node->x_min; - node->nodes[4]->y_min = node->y_min; - node->nodes[4]->z_min = z; - node->nodes[4]->x = node->nodes[4]->x_min + size_x / 2; - node->nodes[4]->y = node->nodes[4]->y_min + size_y / 2; - node->nodes[4]->z = node->nodes[4]->z_min + size_z / 2; - - node->nodes[5]->x_min = x; - node->nodes[5]->y_min = node->y_min; - node->nodes[5]->z_min = z; - node->nodes[5]->x = node->nodes[5]->x_min + size_x / 2; - node->nodes[5]->y = node->nodes[5]->y_min + size_y / 2; - node->nodes[5]->z = node->nodes[5]->z_min + size_z / 2; - - node->nodes[6]->x_min = x; - node->nodes[6]->y_min = y; - node->nodes[6]->z_min = z; - node->nodes[6]->x = node->nodes[6]->x_min + size_x / 2; - node->nodes[6]->y = node->nodes[6]->y_min + size_y / 2; - node->nodes[6]->z = node->nodes[6]->z_min + size_z / 2; - - node->nodes[7]->x_min = node->x_min; - node->nodes[7]->y_min = y; - node->nodes[7]->z_min = z; - node->nodes[7]->x = node->nodes[7]->x_min + size_x / 2; - node->nodes[7]->y = node->nodes[7]->y_min + size_y / 2; - node->nodes[7]->z = node->nodes[7]->z_min + size_z / 2; - - ml_p = node->elems.first; - - /* setting up references of MetaElems for new nodes */ - while (ml_p) { - ml = ml_p->ml; - if (ml->bb->vec[0][2] < z) { - if (ml->bb->vec[0][1] < y) { - /* vec[0][0] lies in first octant */ - if (ml->bb->vec[0][0] < x) { - /* ml belongs to the (0)1st node */ - fill_metaball_octal_node(node, ml, 0); - - /* ml belongs to the (3)4th node */ - if (ml->bb->vec[6][1] >= y) { - fill_metaball_octal_node(node, ml, 3); - - /* ml belongs to the (7)8th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 7); - } - } - - /* ml belongs to the (1)2nd node */ - if (ml->bb->vec[6][0] >= x) { - fill_metaball_octal_node(node, ml, 1); - - /* ml belongs to the (5)6th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 5); - } - } - - /* ml belongs to the (2)3th node */ - if ((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)) { - fill_metaball_octal_node(node, ml, 2); - - /* ml belong to the (6)7th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 6); - } - - } - - /* ml belongs to the (4)5th node too */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 4); - } - - - - } - /* vec[0][0] is in the (1)second octant */ - else { - /* ml belong to the (1)2nd node */ - fill_metaball_octal_node(node, ml, 1); - - /* ml belongs to the (2)3th node */ - if (ml->bb->vec[6][1] >= y) { - fill_metaball_octal_node(node, ml, 2); - - /* ml belongs to the (6)7th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 6); - } - - } - - /* ml belongs to the (5)6th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 5); - } - } - } - else { - /* vec[0][0] is in the (3)4th octant */ - if (ml->bb->vec[0][0] < x) { - /* ml belongs to the (3)4nd node */ - fill_metaball_octal_node(node, ml, 3); - - /* ml belongs to the (7)8th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 7); - } - - - /* ml belongs to the (2)3th node */ - if (ml->bb->vec[6][0] >= x) { - fill_metaball_octal_node(node, ml, 2); - - /* ml belongs to the (6)7th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 6); - } - } - } - - } - - /* vec[0][0] is in the (2)3th octant */ - if ((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)) { - /* ml belongs to the (2)3th node */ - fill_metaball_octal_node(node, ml, 2); - - /* ml belongs to the (6)7th node */ - if (ml->bb->vec[6][2] >= z) { - fill_metaball_octal_node(node, ml, 6); - } - } - } - else { - if (ml->bb->vec[0][1] < y) { - /* vec[0][0] lies in (4)5th octant */ - if (ml->bb->vec[0][0] < x) { - /* ml belongs to the (4)5th node */ - fill_metaball_octal_node(node, ml, 4); - - if (ml->bb->vec[6][0] >= x) { - fill_metaball_octal_node(node, ml, 5); - } - - if (ml->bb->vec[6][1] >= y) { - fill_metaball_octal_node(node, ml, 7); - } - - if ((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)) { - fill_metaball_octal_node(node, ml, 6); - } - } - /* vec[0][0] lies in (5)6th octant */ - else { - fill_metaball_octal_node(node, ml, 5); - - if (ml->bb->vec[6][1] >= y) { - fill_metaball_octal_node(node, ml, 6); - } - } - } - else { - /* vec[0][0] lies in (7)8th octant */ - if (ml->bb->vec[0][0] < x) { - fill_metaball_octal_node(node, ml, 7); - - if (ml->bb->vec[6][0] >= x) { - fill_metaball_octal_node(node, ml, 6); - } - } - - } - - /* vec[0][0] lies in (6)7th octant */ - if ((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)) { - fill_metaball_octal_node(node, ml, 6); - } - } - ml_p = ml_p->next; - } - - /* free references of MetaElems for curent node (it is not needed anymore) */ - BLI_freelistN(&node->elems); - - depth--; - - if (depth > 0) { - for (a = 0; a < 8; a++) { - if (node->nodes[a]->count > 0) /* if node is not empty, then it is subdivided */ - subdivide_metaball_octal_node(node->nodes[a], size_x, size_y, size_z, depth); - } - } -} - -/* free all octal nodes recursively */ -static void free_metaball_octal_node(octal_node *node) -{ - int a; - for (a = 0; a < 8; a++) { - if (node->nodes[a] != NULL) free_metaball_octal_node(node->nodes[a]); - } - BLI_freelistN(&node->elems); - MEM_freeN(node); -} - -/* If scene include more than one MetaElem, then octree is used */ -static void init_metaball_octal_tree(PROCESS *process, int depth) -{ - struct octal_node *node; - ml_pointer *ml_p; - float size[3]; - int a; - - process->metaball_tree = MEM_mallocN(sizeof(octal_tree), "metaball_octal_tree"); - process->metaball_tree->first = node = MEM_mallocN(sizeof(octal_node), "metaball_octal_node"); - /* maximal depth of octree */ - process->metaball_tree->depth = depth; - - process->metaball_tree->neg = node->neg = 0; - process->metaball_tree->pos = node->pos = 0; - - BLI_listbase_clear(&node->elems); - node->count = 0; - - for (a = 0; a < 8; a++) - node->nodes[a] = NULL; - - node->x_min = node->y_min = node->z_min = FLT_MAX; - node->x_max = node->y_max = node->z_max = -FLT_MAX; - - /* size of octal tree scene */ - for (a = 0; a < process->totelem; a++) { - if (process->mainb[a]->bb->vec[0][0] < node->x_min) node->x_min = process->mainb[a]->bb->vec[0][0]; - if (process->mainb[a]->bb->vec[0][1] < node->y_min) node->y_min = process->mainb[a]->bb->vec[0][1]; - if (process->mainb[a]->bb->vec[0][2] < node->z_min) node->z_min = process->mainb[a]->bb->vec[0][2]; - - if (process->mainb[a]->bb->vec[6][0] > node->x_max) node->x_max = process->mainb[a]->bb->vec[6][0]; - if (process->mainb[a]->bb->vec[6][1] > node->y_max) node->y_max = process->mainb[a]->bb->vec[6][1]; - if (process->mainb[a]->bb->vec[6][2] > node->z_max) node->z_max = process->mainb[a]->bb->vec[6][2]; - - ml_p = MEM_mallocN(sizeof(ml_pointer), "ml_pointer"); - ml_p->ml = process->mainb[a]; - BLI_addtail(&node->elems, ml_p); - - if ((process->mainb[a]->flag & MB_NEGATIVE) == 0) { - /* number of positive MetaElem in scene */ - process->metaball_tree->pos++; - } - else { - /* number of negative MetaElem in scene */ - process->metaball_tree->neg++; - } - } - - /* size of first node */ - size[0] = node->x_max - node->x_min; - size[1] = node->y_max - node->y_min; - size[2] = node->z_max - node->z_min; - - /* first node is subdivided recursively */ - subdivide_metaball_octal_node(node, size[0], size[1], size[2], process->metaball_tree->depth); -} - -static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *basis) -{ - Scene *sce_iter = scene; - Base *base; - Object *ob, *bob = basis; - MetaElem *ml = NULL; - int basisnr, obnr; - char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; - SceneBaseIter iter; - - BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - process->totelem = 0; - - BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if (ob->type == OB_MBALL) { - if (ob == bob) { - MetaBall *mb = ob->data; - - /* if bob object is in edit mode, then dynamic list of all MetaElems - * is stored in editelems */ - if (mb->editelems) ml = mb->editelems->first; - /* if bob object is in object mode */ - else ml = mb->elems.first; - } - else { - BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - - /* object ob has to be in same "group" ... it means, that it has to have - * same base of its name */ - if (STREQ(obname, basisname)) { - MetaBall *mb = ob->data; - - /* if object is in edit mode, then dynamic list of all MetaElems - * is stored in editelems */ - if (mb->editelems) ml = mb->editelems->first; - /* if bob object is in object mode */ - else ml = mb->elems.first; - } - } - - for ( ; ml; ml = ml->next) { - if (!(ml->flag & MB_HIDE)) { - process->totelem++; - } - } - } - } -} - -void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase) -{ - MetaBall *mb; - DispList *dl; - int a, nr_cubes; - float *co, *no, totsize, width; - PROCESS process = {0}; - - mb = ob->data; - - mball_count(eval_ctx, &process, scene, ob); - - if (process.totelem == 0) return; - if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return; - if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return; - - process.thresh = mb->thresh; - - /* total number of MetaElems (totelem) is precomputed in find_basis_mball() function */ - process.mainb = MEM_mallocN(sizeof(void *) * process.totelem, "mainb"); - - /* initialize all mainb (MetaElems) */ - totsize = init_meta(eval_ctx, &process, scene, ob); - - /* if scene includes more than one MetaElem, then octal tree optimization is used */ - if ((process.totelem > 1) && (process.totelem <= 64)) init_metaball_octal_tree(&process, 1); - if ((process.totelem > 64) && (process.totelem <= 128)) init_metaball_octal_tree(&process, 2); - if ((process.totelem > 128) && (process.totelem <= 512)) init_metaball_octal_tree(&process, 3); - if ((process.totelem > 512) && (process.totelem <= 1024)) init_metaball_octal_tree(&process, 4); - if (process.totelem > 1024) init_metaball_octal_tree(&process, 5); - - /* don't polygonize metaballs with too high resolution (base mball to small) - * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ - if (process.metaball_tree) { - if (ob->size[0] <= 0.00001f * (process.metaball_tree->first->x_max - process.metaball_tree->first->x_min) || - ob->size[1] <= 0.00001f * (process.metaball_tree->first->y_max - process.metaball_tree->first->y_min) || - ob->size[2] <= 0.00001f * (process.metaball_tree->first->z_max - process.metaball_tree->first->z_min)) - { - new_pgn_element(&process, -1); /* free values created by init_meta */ - - MEM_freeN(process.mainb); - - /* free tree */ - free_metaball_octal_node(process.metaball_tree->first); - MEM_freeN(process.metaball_tree); - - return; - } - } - - /* width is size per polygonize cube */ - if (eval_ctx->mode == DAG_EVAL_RENDER) { - width = mb->rendersize; - } - else { - width = mb->wiresize; - if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) { - width *= 2; - } - } - /* nr_cubes is just for safety, minimum is totsize */ - nr_cubes = (int)(0.5f + totsize / width); - - /* init process */ - process.function = metaball; - process.size = width; - process.bounds = nr_cubes; - process.cubes = NULL; - process.delta = width / (float)(RES * RES); - - polygonize(&process, mb); - - MEM_freeN(process.mainb); - - /* free octal tree */ - if (process.totelem > 1) { - free_metaball_octal_node(process.metaball_tree->first); - MEM_freeN(process.metaball_tree); - process.metaball_tree = NULL; - } - - if (process.curindex) { - VERTEX *ptr = process.vertices.ptr; - - dl = MEM_callocN(sizeof(DispList), "mbaldisp"); - BLI_addtail(dispbase, dl); - dl->type = DL_INDEX4; - dl->nr = process.vertices.count; - dl->parts = process.curindex; - - dl->index = process.indices; - process.indices = NULL; - - a = process.vertices.count; - dl->verts = co = MEM_mallocN(sizeof(float[3]) * a, "mballverts"); - dl->nors = no = MEM_mallocN(sizeof(float[3]) * a, "mballnors"); - - for (a = 0; a < process.vertices.count; ptr++, a++, no += 3, co += 3) { - copy_v3_v3(co, ptr->co); - copy_v3_v3(no, ptr->no); - } - } - - freepolygonize(&process); -} - bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3], float obmat[4][4], const short flag) { @@ -2511,3 +586,9 @@ void BKE_mball_select_swap(struct MetaBall *mb) } } +/* **** Depsgraph evaluation **** */ + +void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + MetaBall *UNUSED(mball)) +{ +} diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c new file mode 100644 index 00000000000..e8418e876bb --- /dev/null +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -0,0 +1,1325 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Jiri Hnidek <jiri.hnidek@vslib.cz>. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mball_tessellate.c + * \ingroup bke + */ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> +#include <ctype.h> +#include <float.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" +#include "DNA_meta_types.h" +#include "DNA_scene_types.h" + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_memarena.h" + +#include "BKE_global.h" + +#include "BKE_depsgraph.h" +#include "BKE_scene.h" +#include "BKE_displist.h" +#include "BKE_mball_tessellate.h" /* own include */ + +#include "BLI_strict_flags.h" + +/* experimental (faster) normal calculation */ +// #define USE_ACCUM_NORMAL + +/* Data types */ + +typedef struct corner { /* corner of a cube */ + int i, j, k; /* (i, j, k) is index within lattice */ + float co[3], value; /* location and function value */ + struct corner *next; +} CORNER; + +typedef struct cube { /* partitioning cell (cube) */ + int i, j, k; /* lattice location of cube */ + CORNER *corners[8]; /* eight corners */ +} CUBE; + +typedef struct cubes { /* linked list of cubes acting as stack */ + CUBE cube; /* a single cube */ + struct cubes *next; /* remaining elements */ +} CUBES; + +typedef struct centerlist { /* list of cube locations */ + int i, j, k; /* cube location */ + struct centerlist *next; /* remaining elements */ +} CENTERLIST; + +typedef struct edgelist { /* list of edges */ + int i1, j1, k1, i2, j2, k2; /* edge corner ids */ + int vid; /* vertex id */ + struct edgelist *next; /* remaining elements */ +} EDGELIST; + +typedef struct intlist { /* list of integers */ + int i; /* an integer */ + struct intlist *next; /* remaining elements */ +} INTLIST; + +typedef struct intlists { /* list of list of integers */ + INTLIST *list; /* a list of integers */ + struct intlists *next; /* remaining elements */ +} INTLISTS; + +typedef struct Box { /* an AABB with pointer to metalelem */ + float min[3], max[3]; + const MetaElem *ml; +} Box; + +typedef struct MetaballBVHNode { /* BVH node */ + Box bb[2]; /* AABB of children */ + struct MetaballBVHNode *child[2]; +} MetaballBVHNode; + +typedef struct process { /* parameters, storage */ + float thresh, size; /* mball threshold, single cube size */ + float delta; /* small delta for calculating normals */ + unsigned int converge_res; /* converge procedure resolution (more = slower) */ + + MetaElem **mainb; /* array of all metaelems */ + unsigned int totelem, mem; /* number of metaelems */ + + MetaballBVHNode metaball_bvh; /* The simplest bvh */ + Box allbb; /* Bounding box of all metaelems */ + + MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */ + unsigned int bvh_queue_size; + + CUBES *cubes; /* stack of cubes waiting for polygonization */ + CENTERLIST **centers; /* cube center hash table */ + CORNER **corners; /* corner value hash table */ + EDGELIST **edges; /* edge and vertex id hash table */ + + int (*indices)[4]; /* output indices */ + unsigned int totindex; /* size of memory allocated for indices */ + unsigned int curindex; /* number of currently added indices */ + + float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */ + unsigned int totvertex; /* memory size */ + unsigned int curvertex; /* currently added vertices */ + + /* memory allocation from common pool */ + MemArena *pgn_elements; +} PROCESS; + +/* Forward declarations */ +static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2); +static void add_cube(PROCESS *process, int i, int j, int k); +static void make_face(PROCESS *process, int i1, int i2, int i3, int i4); +static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]); + +/* ******************* SIMPLE BVH ********************* */ + +static void make_box_union(const BoundBox *a, const Box *b, Box *r_out) +{ + r_out->min[0] = min_ff(a->vec[0][0], b->min[0]); + r_out->min[1] = min_ff(a->vec[0][1], b->min[1]); + r_out->min[2] = min_ff(a->vec[0][2], b->min[2]); + + r_out->max[0] = max_ff(a->vec[6][0], b->max[0]); + r_out->max[1] = max_ff(a->vec[6][1], b->max[1]); + r_out->max[2] = max_ff(a->vec[6][2], b->max[2]); +} + +static void make_box_from_metaelem(Box *r, const MetaElem *ml) +{ + copy_v3_v3(r->max, ml->bb->vec[6]); + copy_v3_v3(r->min, ml->bb->vec[0]); + r->ml = ml; +} + +/** + * Partitions part of mainb array [start, end) along axis s. Returns i, + * where centroids of elements in the [start, i) segment lie "on the right side" of div, + * and elements in the [i, end) segment lie "on the left" + */ +static unsigned int partition_mainb(MetaElem **mainb, unsigned int start, unsigned int end, unsigned int s, float div) +{ + unsigned int i = start, j = end - 1; + div *= 2.0f; + + while (1) { + while (i < j && div > (mainb[i]->bb->vec[6][s] + mainb[i]->bb->vec[0][s])) i++; + while (j > i && div < (mainb[j]->bb->vec[6][s] + mainb[j]->bb->vec[0][s])) j--; + + if (i >= j) + break; + + SWAP(MetaElem *, mainb[i], mainb[j]); + i++; + j--; + } + + if (i == start) { + i++; + } + + return i; +} + +/** + * Recursively builds a BVH, dividing elements along the middle of the longest axis of allbox. + */ +static void build_bvh_spatial( + PROCESS *process, MetaballBVHNode *node, + unsigned int start, unsigned int end, const Box *allbox) +{ + unsigned int part, j, s; + float dim[3], div; + + /* Maximum bvh queue size is number of nodes which are made, equals calls to this function. */ + process->bvh_queue_size++; + + dim[0] = allbox->max[0] - allbox->min[0]; + dim[1] = allbox->max[1] - allbox->min[1]; + dim[2] = allbox->max[2] - allbox->min[2]; + + s = 0; + if (dim[1] > dim[0] && dim[1] > dim[2]) s = 1; + else if (dim[2] > dim[1] && dim[2] > dim[0]) s = 2; + + div = allbox->min[s] + (dim[s] / 2.0f); + + part = partition_mainb(process->mainb, start, end, s, div); + + make_box_from_metaelem(&node->bb[0], process->mainb[start]); + node->child[0] = NULL; + + if (part > start + 1) { + for (j = start; j < part; j++) { + make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]); + } + + node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode)); + build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]); + } + + node->child[1] = NULL; + if (part < end) { + make_box_from_metaelem(&node->bb[1], process->mainb[part]); + + if (part < end - 1) { + for (j = part; j < end; j++) { + make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]); + } + + node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode)); + build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]); + } + } + else { + INIT_MINMAX(node->bb[1].min, node->bb[1].max); + } +} + +/* ******************** ARITH ************************* */ + +/** + * BASED AT CODE (but mostly rewritten) : + * C code from the article + * "An Implicit Surface Polygonizer" + * by Jules Bloomenthal, jbloom@beauty.gmu.edu + * in "Graphics Gems IV", Academic Press, 1994 + * + * Authored by Jules Bloomenthal, Xerox PARC. + * Copyright (c) Xerox Corporation, 1991. All rights reserved. + * Permission is granted to reproduce, use and distribute this code for + * any and all purposes, provided that this notice appears in all copies. + */ + +#define L 0 /* left direction: -x, -i */ +#define R 1 /* right direction: +x, +i */ +#define B 2 /* bottom direction: -y, -j */ +#define T 3 /* top direction: +y, +j */ +#define N 4 /* near direction: -z, -k */ +#define F 5 /* far direction: +z, +k */ +#define LBN 0 /* left bottom near corner */ +#define LBF 1 /* left bottom far corner */ +#define LTN 2 /* left top near corner */ +#define LTF 3 /* left top far corner */ +#define RBN 4 /* right bottom near corner */ +#define RBF 5 /* right bottom far corner */ +#define RTN 6 /* right top near corner */ +#define RTF 7 /* right top far corner */ + +/** + * the LBN corner of cube (i, j, k), corresponds with location + * (i-0.5)*size, (j-0.5)*size, (k-0.5)*size) + */ + +#define HASHBIT (5) +#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */ + +#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) ) + +#define MB_BIT(i, bit) (((i) >> (bit)) & 1) +// #define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */ + +/* ******************** DENSITY COPMPUTATION ********************* */ + +/** + * Computes density from given metaball at given position. + * Metaball equation is: ``(1 - r^2 / R^2)^3 * s`` + * + * r = distance from center + * R = metaball radius + * s - metaball stiffness + */ +static float densfunc(const MetaElem *ball, float x, float y, float z) +{ + float dist2; + float dvec[3] = {x, y, z}; + + mul_m4_v3((float (*)[4])ball->imat, dvec); + + switch (ball->type) { + case MB_BALL: + /* do nothing */ + break; + case MB_CUBE: + if (dvec[2] > ball->expz) dvec[2] -= ball->expz; + else if (dvec[2] < -ball->expz) dvec[2] += ball->expz; + else dvec[2] = 0.0; + /* fall through */ + case MB_PLANE: + if (dvec[1] > ball->expy) dvec[1] -= ball->expy; + else if (dvec[1] < -ball->expy) dvec[1] += ball->expy; + else dvec[1] = 0.0; + /* fall through */ + case MB_TUBE: + if (dvec[0] > ball->expx) dvec[0] -= ball->expx; + else if (dvec[0] < -ball->expx) dvec[0] += ball->expx; + else dvec[0] = 0.0; + break; + case MB_ELIPSOID: + dvec[0] /= ball->expx; + dvec[1] /= ball->expy; + dvec[2] /= ball->expz; + break; + + /* *** deprecated, could be removed?, do-versioned at least *** */ + case MB_TUBEX: + if (dvec[0] > ball->len) dvec[0] -= ball->len; + else if (dvec[0] < -ball->len) dvec[0] += ball->len; + else dvec[0] = 0.0; + break; + case MB_TUBEY: + if (dvec[1] > ball->len) dvec[1] -= ball->len; + else if (dvec[1] < -ball->len) dvec[1] += ball->len; + else dvec[1] = 0.0; + break; + case MB_TUBEZ: + if (dvec[2] > ball->len) dvec[2] -= ball->len; + else if (dvec[2] < -ball->len) dvec[2] += ball->len; + else dvec[2] = 0.0; + break; + /* *** end deprecated *** */ + } + + /* ball->rad2 is inverse of squared rad */ + dist2 = 1.0f - (len_squared_v3(dvec) * ball->rad2); + + /* ball->s is negative if metaball is negative */ + return (dist2 < 0.0f) ? 0.0f : (ball->s * dist2 * dist2 * dist2); +} + +/** + * Computes density at given position form all metaballs which contain this point in their box. + * Traverses BVH using a queue. + */ +static float metaball(PROCESS *process, float x, float y, float z) +{ + int i; + float dens = 0.0f; + unsigned int front = 0, back = 0; + MetaballBVHNode *node; + + process->bvh_queue[front++] = &process->metaball_bvh; + + while (front != back) { + node = process->bvh_queue[back++]; + + for (i = 0; i < 2; i++) { + if ((node->bb[i].min[0] <= x) && (node->bb[i].max[0] >= x) && + (node->bb[i].min[1] <= y) && (node->bb[i].max[1] >= y) && + (node->bb[i].min[2] <= z) && (node->bb[i].max[2] >= z)) + { + if (node->child[i]) process->bvh_queue[front++] = node->child[i]; + else dens += densfunc(node->bb[i].ml, x, y, z); + } + } + } + + return process->thresh - dens; +} + +/** + * Adds face to indices, expands memory if needed. + */ +static void make_face(PROCESS *process, int i1, int i2, int i3, int i4) +{ + int *cur; + +#ifdef USE_ACCUM_NORMAL + float n[3]; +#endif + + if (UNLIKELY(process->totindex == process->curindex)) { + process->totindex += 4096; + process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex); + } + + cur = process->indices[process->curindex++]; + + /* displists now support array drawing, we treat tri's as fake quad */ + + cur[0] = i1; + cur[1] = i2; + cur[2] = i3; + + if (i4 == 0) { + cur[3] = i3; + } + else { + cur[3] = i4; + } + +#ifdef USE_ACCUM_NORMAL + if (i4 == 0) { + normal_tri_v3(n, process->co[i1], process->co[i2], process->co[i3]); + accumulate_vertex_normals( + process->no[i1], process->no[i2], process->no[i3], NULL, n, + process->co[i1], process->co[i2], process->co[i3], NULL); + } + else { + normal_quad_v3(n, process->co[i1], process->co[i2], process->co[i3], process->co[i4]); + accumulate_vertex_normals( + process->no[i1], process->no[i2], process->no[i3], process->no[i4], n, + process->co[i1], process->co[i2], process->co[i3], process->co[i4]); + } +#endif + +} + +/* Frees allocated memory */ +static void freepolygonize(PROCESS *process) +{ + if (process->corners) MEM_freeN(process->corners); + if (process->edges) MEM_freeN(process->edges); + if (process->centers) MEM_freeN(process->centers); + if (process->mainb) MEM_freeN(process->mainb); + if (process->bvh_queue) MEM_freeN(process->bvh_queue); + if (process->pgn_elements) BLI_memarena_free(process->pgn_elements); +} + +/* **************** POLYGONIZATION ************************ */ + +/**** Cubical Polygonization (optional) ****/ + +#define LB 0 /* left bottom edge */ +#define LT 1 /* left top edge */ +#define LN 2 /* left near edge */ +#define LF 3 /* left far edge */ +#define RB 4 /* right bottom edge */ +#define RT 5 /* right top edge */ +#define RN 6 /* right near edge */ +#define RF 7 /* right far edge */ +#define BN 8 /* bottom near edge */ +#define BF 9 /* bottom far edge */ +#define TN 10 /* top near edge */ +#define TF 11 /* top far edge */ + +static INTLISTS *cubetable[256]; +static char faces[256]; + +/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */ +static int corner1[12] = { + LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF +}; +static int corner2[12] = { + LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF +}; +static int leftface[12] = { + B, L, L, F, R, T, N, R, N, B, T, F +}; +/* face on left when going corner1 to corner2 */ +static int rightface[12] = { + L, T, N, L, B, R, R, F, B, F, N, T +}; +/* face on right when going corner1 to corner2 */ + +/** + * triangulate the cube directly, without decomposition + */ +static void docube(PROCESS *process, CUBE *cube) +{ + INTLISTS *polys; + CORNER *c1, *c2; + int i, index = 0, count, indexar[8]; + + /* Determine which case cube falls into. */ + for (i = 0; i < 8; i++) { + if (cube->corners[i]->value > 0.0f) { + index += (1 << i); + } + } + + /* Using faces[] table, adds neighbouring cube if surface intersects face in this direction. */ + if (MB_BIT(faces[index], 0)) add_cube(process, cube->i - 1, cube->j, cube->k); + if (MB_BIT(faces[index], 1)) add_cube(process, cube->i + 1, cube->j, cube->k); + if (MB_BIT(faces[index], 2)) add_cube(process, cube->i, cube->j - 1, cube->k); + if (MB_BIT(faces[index], 3)) add_cube(process, cube->i, cube->j + 1, cube->k); + if (MB_BIT(faces[index], 4)) add_cube(process, cube->i, cube->j, cube->k - 1); + if (MB_BIT(faces[index], 5)) add_cube(process, cube->i, cube->j, cube->k + 1); + + /* Using cubetable[], determines polygons for output. */ + for (polys = cubetable[index]; polys; polys = polys->next) { + INTLIST *edges; + + count = 0; + /* Sets needed vertex id's lying on the edges. */ + for (edges = polys->list; edges; edges = edges->next) { + c1 = cube->corners[corner1[edges->i]]; + c2 = cube->corners[corner2[edges->i]]; + + indexar[count] = vertid(process, c1, c2); + count++; + } + + /* Adds faces to output. */ + if (count > 2) { + switch (count) { + case 3: + make_face(process, indexar[2], indexar[1], indexar[0], 0); + break; + case 4: + if (indexar[0] == 0) make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]); + else make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]); + break; + case 5: + if (indexar[0] == 0) make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]); + else make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]); + + make_face(process, indexar[4], indexar[3], indexar[0], 0); + break; + case 6: + if (indexar[0] == 0) { + make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]); + make_face(process, indexar[0], indexar[5], indexar[4], indexar[3]); + } + else { + make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]); + make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]); + } + break; + case 7: + if (indexar[0] == 0) { + make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]); + make_face(process, indexar[0], indexar[5], indexar[4], indexar[3]); + } + else { + make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]); + make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]); + } + + make_face(process, indexar[6], indexar[5], indexar[0], 0); + + break; + } + } + } +} + +/** + * return corner with the given lattice location + * set (and cache) its function value + */ +static CORNER *setcorner(PROCESS *process, int i, int j, int k) +{ + /* for speed, do corner value caching here */ + CORNER *c; + int index; + + /* does corner exist? */ + index = HASH(i, j, k); + c = process->corners[index]; + + for (; c != NULL; c = c->next) { + if (c->i == i && c->j == j && c->k == k) { + return c; + } + } + + c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER)); + + c->i = i; + c->co[0] = ((float)i - 0.5f) * process->size; + c->j = j; + c->co[1] = ((float)j - 0.5f) * process->size; + c->k = k; + c->co[2] = ((float)k - 0.5f) * process->size; + + c->value = metaball(process, c->co[0], c->co[1], c->co[2]); + + c->next = process->corners[index]; + process->corners[index] = c; + + return c; +} + +/** + * return next clockwise edge from given edge around given face + */ +static int nextcwedge(int edge, int face) +{ + switch (edge) { + case LB: + return (face == L) ? LF : BN; + case LT: + return (face == L) ? LN : TF; + case LN: + return (face == L) ? LB : TN; + case LF: + return (face == L) ? LT : BF; + case RB: + return (face == R) ? RN : BF; + case RT: + return (face == R) ? RF : TN; + case RN: + return (face == R) ? RT : BN; + case RF: + return (face == R) ? RB : TF; + case BN: + return (face == B) ? RB : LN; + case BF: + return (face == B) ? LB : RF; + case TN: + return (face == T) ? LT : RN; + case TF: + return (face == T) ? RT : LF; + } + return 0; +} + +/** + * \return the face adjoining edge that is not the given face + */ +static int otherface(int edge, int face) +{ + int other = leftface[edge]; + return face == other ? rightface[edge] : other; +} + +/** + * create the 256 entry table for cubical polygonization + */ +static void makecubetable(void) +{ + static bool is_done = false; + int i, e, c, done[12], pos[8]; + + if (is_done) return; + is_done = true; + + for (i = 0; i < 256; i++) { + for (e = 0; e < 12; e++) done[e] = 0; + for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c); + for (e = 0; e < 12; e++) + if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) { + INTLIST *ints = NULL; + INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist"); + int start = e, edge = e; + + /* get face that is to right of edge from pos to neg corner: */ + int face = pos[corner1[e]] ? rightface[e] : leftface[e]; + + while (1) { + edge = nextcwedge(edge, face); + done[edge] = 1; + if (pos[corner1[edge]] != pos[corner2[edge]]) { + INTLIST *tmp = ints; + + ints = MEM_callocN(sizeof(INTLIST), "mball_intlist"); + ints->i = edge; + ints->next = tmp; /* add edge to head of list */ + + if (edge == start) break; + face = otherface(edge, face); + } + } + lists->list = ints; /* add ints to head of table entry */ + lists->next = cubetable[i]; + cubetable[i] = lists; + } + } + + for (i = 0; i < 256; i++) { + INTLISTS *polys; + faces[i] = 0; + for (polys = cubetable[i]; polys; polys = polys->next) { + INTLIST *edges; + + for (edges = polys->list; edges; edges = edges->next) { + if (edges->i == LB || edges->i == LT || edges->i == LN || edges->i == LF) faces[i] |= 1 << L; + if (edges->i == RB || edges->i == RT || edges->i == RN || edges->i == RF) faces[i] |= 1 << R; + if (edges->i == LB || edges->i == RB || edges->i == BN || edges->i == BF) faces[i] |= 1 << B; + if (edges->i == LT || edges->i == RT || edges->i == TN || edges->i == TF) faces[i] |= 1 << T; + if (edges->i == LN || edges->i == RN || edges->i == BN || edges->i == TN) faces[i] |= 1 << N; + if (edges->i == LF || edges->i == RF || edges->i == BF || edges->i == TF) faces[i] |= 1 << F; + } + } + } +} + +void BKE_mball_cubeTable_free(void) +{ + int i; + INTLISTS *lists, *nlists; + INTLIST *ints, *nints; + + for (i = 0; i < 256; i++) { + lists = cubetable[i]; + while (lists) { + nlists = lists->next; + + ints = lists->list; + while (ints) { + nints = ints->next; + MEM_freeN(ints); + ints = nints; + } + + MEM_freeN(lists); + lists = nlists; + } + cubetable[i] = NULL; + } +} + +/**** Storage ****/ + +/** + * Inserts cube at lattice i, j, k into hash table, marking it as "done" + */ +static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k) +{ + int index; + CENTERLIST *newc, *l, *q; + + index = HASH(i, j, k); + q = table[index]; + + for (l = q; l != NULL; l = l->next) { + if (l->i == i && l->j == j && l->k == k) return 1; + } + + newc = BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST)); + newc->i = i; + newc->j = j; + newc->k = k; + newc->next = q; + table[index] = newc; + + return 0; +} + +/** + * Sets vid of vertex lying on given edge. + */ +static void setedge( + PROCESS *process, + int i1, int j1, int k1, + int i2, int j2, int k2, + int vid) +{ + int index; + EDGELIST *newe; + + if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) { + int t = i1; + i1 = i2; + i2 = t; + t = j1; + j1 = j2; + j2 = t; + t = k1; + k1 = k2; + k2 = t; + } + index = HASH(i1, j1, k1) + HASH(i2, j2, k2); + newe = BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST)); + + newe->i1 = i1; + newe->j1 = j1; + newe->k1 = k1; + newe->i2 = i2; + newe->j2 = j2; + newe->k2 = k2; + newe->vid = vid; + newe->next = process->edges[index]; + process->edges[index] = newe; +} + +/** + * \return vertex id for edge; return -1 if not set + */ +static int getedge(EDGELIST *table[], + int i1, int j1, int k1, + int i2, int j2, int k2) +{ + EDGELIST *q; + + if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) { + int t = i1; + i1 = i2; + i2 = t; + t = j1; + j1 = j2; + j2 = t; + t = k1; + k1 = k2; + k2 = t; + } + q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)]; + for (; q != NULL; q = q->next) { + if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 && + q->i2 == i2 && q->j2 == j2 && q->k2 == k2) + { + return q->vid; + } + } + return -1; +} + +/** + * Adds a vertex, expands memory if needed. + */ +static void addtovertices(PROCESS *process, const float v[3], const float no[3]) +{ + if (process->curvertex == process->totvertex) { + process->totvertex += 4096; + process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3])); + process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3])); + } + + copy_v3_v3(process->co[process->curvertex], v); + copy_v3_v3(process->no[process->curvertex], no); + + process->curvertex++; +} + +#ifndef USE_ACCUM_NORMAL +/** + * Computes normal from density field at given point. + * + * \note Doesn't do normalization! + */ +static void vnormal(PROCESS *process, const float point[3], float r_no[3]) +{ + const float delta = process->delta; + const float f = metaball(process, point[0], point[1], point[2]); + + r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f; + r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f; + r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f; + +#if 0 + f = normalize_v3(r_no); + + if (0) { + float tvec[3]; + + delta *= 2.0f; + + f = process->function(process, point[0], point[1], point[2]); + + tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f; + tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f; + tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f; + + if (normalize_v3(tvec) != 0.0f) { + add_v3_v3(r_no, tvec); + normalize_v3(r_no); + } + } +#endif +} +#endif /* USE_ACCUM_NORMAL */ + +/** + * \return the id of vertex between two corners. + * + * If it wasn't previously computed, does #converge() and adds vertex to process. + */ +static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2) +{ + float v[3], no[3]; + int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); + + if (vid != -1) return vid; /* previously computed */ + + converge(process, c1, c2, v); /* position */ + +#ifdef USE_ACCUM_NORMAL + zero_v3(no); +#else + vnormal(process, v, no); +#endif + + addtovertices(process, v, no); /* save vertex */ + vid = (int)process->curvertex - 1; + setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); + + return vid; +} + +/** + * Given two corners, computes approximation of surface intersection point between them. + * In case of small threshold, do bisection. + */ +static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]) +{ + float tmp, dens; + unsigned int i; + float c1_value, c1_co[3]; + float c2_value, c2_co[3]; + + if (c1->value < c2->value) { + c1_value = c2->value; + copy_v3_v3(c1_co, c2->co); + c2_value = c1->value; + copy_v3_v3(c2_co, c1->co); + } + else { + c1_value = c1->value; + copy_v3_v3(c1_co, c1->co); + c2_value = c2->value; + copy_v3_v3(c2_co, c2->co); + } + + + for (i = 0; i < process->converge_res; i++) { + interp_v3_v3v3(r_p, c1_co, c2_co, 0.5f); + dens = metaball(process, r_p[0], r_p[1], r_p[2]); + + if (dens > 0.0f) { + c1_value = dens; + copy_v3_v3(c1_co, r_p); + } + else { + c2_value = dens; + copy_v3_v3(c2_co, r_p); + } + } + + tmp = -c1_value / (c2_value - c1_value); + interp_v3_v3v3(r_p, c1_co, c2_co, tmp); +} + +/** + * Adds cube at given lattice position to cube stack of process. + */ +static void add_cube(PROCESS *process, int i, int j, int k) +{ + CUBES *ncube; + int n; + + /* test if cube has been found before */ + if (setcenter(process, process->centers, i, j, k) == 0) { + /* push cube on stack: */ + ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES)); + ncube->next = process->cubes; + process->cubes = ncube; + + ncube->cube.i = i; + ncube->cube.j = j; + ncube->cube.k = k; + + /* set corners of initial cube: */ + for (n = 0; n < 8; n++) + ncube->cube.corners[n] = setcorner(process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0)); + } +} + +static void next_lattice(int r[3], const float pos[3], const float size) +{ + r[0] = (int)ceil((pos[0] / size) + 0.5f); + r[1] = (int)ceil((pos[1] / size) + 0.5f); + r[2] = (int)ceil((pos[2] / size) + 0.5f); +} +static void prev_lattice(int r[3], const float pos[3], const float size) +{ + next_lattice(r, pos, size); + r[0]--; r[1]--; r[2]--; +} +static void closest_latice(int r[3], const float pos[3], const float size) +{ + r[0] = (int)floorf(pos[0] / size + 1.0f); + r[1] = (int)floorf(pos[1] / size + 1.0f); + r[2] = (int)floorf(pos[2] / size + 1.0f); +} + +/** + * Find at most 26 cubes to start polygonization from. + */ +static void find_first_points(PROCESS *process, const unsigned int em) +{ + const MetaElem *ml; + int center[3], lbn[3], rtf[3], it[3], dir[3], add[3]; + float tmp[3], a, b; + + ml = process->mainb[em]; + + mid_v3_v3v3(tmp, ml->bb->vec[0], ml->bb->vec[6]); + closest_latice(center, tmp, process->size); + prev_lattice(lbn, ml->bb->vec[0], process->size); + next_lattice(rtf, ml->bb->vec[6], process->size); + + for (dir[0] = -1; dir[0] <= 1; dir[0]++) { + for (dir[1] = -1; dir[1] <= 1; dir[1]++) { + for (dir[2] = -1; dir[2] <= 1; dir[2]++) { + if (dir[0] == 0 && dir[1] == 0 && dir[2] == 0) { + continue; + } + + copy_v3_v3_int(it, center); + + b = setcorner(process, it[0], it[1], it[2])->value; + do { + it[0] += dir[0]; + it[1] += dir[1]; + it[2] += dir[2]; + a = b; + b = setcorner(process, it[0], it[1], it[2])->value; + + if (a * b < 0.0f) { + add[0] = it[0] - dir[0]; + add[1] = it[1] - dir[1]; + add[2] = it[2] - dir[2]; + DO_MIN(it, add); + add_cube(process, add[0], add[1], add[2]); + break; + } + } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) && + (it[0] < rtf[0]) && (it[1] < rtf[1]) && (it[2] < rtf[2])); + } + } + } +} + +/** + * The main polygonization proc. + * Allocates memory, makes cubetable, + * finds starting surface points + * and processes cubes on the stack until none left. + */ +static void polygonize(PROCESS *process) +{ + CUBE c; + unsigned int i; + + process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers"); + process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners"); + process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges"); + process->bvh_queue = MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size, "Metaball BVH Queue"); + + makecubetable(); + + for (i = 0; i < process->totelem; i++) { + find_first_points(process, i); + } + + while (process->cubes != NULL) { + c = process->cubes->cube; + process->cubes = process->cubes->next; + + docube(process, &c); + } +} + +/** + * Iterates over ALL objects in the scene and all of its sets, including + * making all duplis(not only metas). Copies metas to mainb array. + * Computes bounding boxes for building BVH. */ +static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) +{ + Scene *sce_iter = scene; + Base *base; + Object *bob; + MetaBall *mb; + const MetaElem *ml; + float obinv[4][4], obmat[4][4]; + unsigned int i; + int obnr, zero_size = 0; + char obname[MAX_ID_NAME]; + SceneBaseIter iter; + + copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ + invert_m4_m4(obinv, ob->obmat); + + BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); + + /* make main array */ + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); + while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) { + if (bob->type == OB_MBALL) { + zero_size = 0; + ml = NULL; + + if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { + mb = ob->data; + + if (mb->editelems) ml = mb->editelems->first; + else ml = mb->elems.first; + } + else { + char name[MAX_ID_NAME]; + int nr; + + BLI_split_name_num(name, &nr, bob->id.name + 2, '.'); + if (STREQ(obname, name)) { + mb = bob->data; + + if (mb->editelems) ml = mb->editelems->first; + else ml = mb->elems.first; + } + } + + /* when metaball object has zero scale, then MetaElem to this MetaBall + * will not be put to mainb array */ + if (has_zero_axis_m4(bob->obmat)) { + zero_size = 1; + } + else if (bob->parent) { + struct Object *pob = bob->parent; + while (pob) { + if (has_zero_axis_m4(pob->obmat)) { + zero_size = 1; + break; + } + pob = pob->parent; + } + } + + if (zero_size) { + while (ml) { + ml = ml->next; + } + } + else { + while (ml) { + if (!(ml->flag & MB_HIDE)) { + float pos[4][4], rot[4][4]; + float expx, expy, expz; + float tempmin[3], tempmax[3]; + + MetaElem *new_ml; + + /* make a copy because of duplicates */ + new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem)); + *(new_ml) = *ml; + new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)); + new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); + new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); + + /* too big stiffness seems only ugly due to linear interpolation + * no need to have possibility for too big stiffness */ + if (ml->s > 10.0f) new_ml->s = 10.0f; + else new_ml->s = ml->s; + + /* if metaball is negative, set stiffness negative */ + if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s; + + /* Translation of MetaElem */ + unit_m4(pos); + pos[3][0] = ml->x; + pos[3][1] = ml->y; + pos[3][2] = ml->z; + + /* Rotation of MetaElem is stored in quat */ + quat_to_mat4(rot, ml->quat); + + /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */ + mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot); + /* ml local space -> basis object space */ + invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); + + /* rad2 is inverse of squared radius */ + new_ml->rad2 = 1 / (ml->rad * ml->rad); + + /* initial dimensions = radius */ + expx = ml->rad; + expy = ml->rad; + expz = ml->rad; + + switch (ml->type) { + case MB_BALL: + break; + case MB_CUBE: /* cube is "expanded" by expz, expy and expx */ + expz += ml->expz; + /* fall through */ + case MB_PLANE: /* plane is "expanded" by expy and expx */ + expy += ml->expy; + /* fall through */ + case MB_TUBE: /* tube is "expanded" by expx */ + expx += ml->expx; + break; + case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */ + expx *= ml->expx; + expy *= ml->expy; + expz *= ml->expz; + break; + } + + /* untransformed Bounding Box of MetaElem */ + /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */ + copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */ + copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */ + copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */ + copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */ + copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */ + copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */ + copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */ + copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */ + + /* transformation of Metalem bb */ + for (i = 0; i < 8; i++) + mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]); + + /* find max and min of transformed bb */ + INIT_MINMAX(tempmin, tempmax); + for (i = 0; i < 8; i++) { + DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax); + } + + /* set only point 0 and 6 - AABB of Metaelem */ + copy_v3_v3(new_ml->bb->vec[0], tempmin); + copy_v3_v3(new_ml->bb->vec[6], tempmax); + + /* add new_ml to mainb[] */ + if (UNLIKELY(process->totelem == process->mem)) { + process->mem = process->mem * 2 + 10; + process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); + } + process->mainb[process->totelem++] = new_ml; + } + ml = ml->next; + } + } + } + } + + /* compute AABB of all Metaelems */ + if (process->totelem > 0) { + copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]); + copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]); + for (i = 1; i < process->totelem; i++) + make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb); + } +} + +void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase) +{ + MetaBall *mb; + DispList *dl; + unsigned int a; + PROCESS process = {0}; + + mb = ob->data; + + process.thresh = mb->thresh; + + if (process.thresh < 0.001f) process.converge_res = 16; + else if (process.thresh < 0.01f) process.converge_res = 8; + else if (process.thresh < 0.1f) process.converge_res = 4; + else process.converge_res = 2; + + if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return; + if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return; + + if (eval_ctx->mode == DAG_EVAL_RENDER) { + process.size = mb->rendersize; + } + else { + process.size = mb->wiresize; + if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) { + process.size *= 2.0f; + } + } + + process.delta = process.size * 0.001f; + + process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena"); + + /* initialize all mainb (MetaElems) */ + init_meta(eval_ctx, &process, scene, ob); + + if (process.totelem > 0) { + build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); + + /* don't polygonize metaballs with too high resolution (base mball to small) + * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ + if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || + ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || + ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) + { + polygonize(&process); + + /* add resulting surface to displist */ + if (process.curindex) { + dl = MEM_callocN(sizeof(DispList), "mballdisp"); + BLI_addtail(dispbase, dl); + dl->type = DL_INDEX4; + dl->nr = (int)process.curvertex; + dl->parts = (int)process.curindex; + + dl->index = (int *)process.indices; + + for (a = 0; a < process.curvertex; a++) { + normalize_v3(process.no[a]); + } + + dl->verts = (float *)process.co; + dl->nors = (float *)process.no; + } + } + } + + freepolygonize(&process); +} diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 419f907d786..c8223657a05 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -61,6 +61,7 @@ #include "BKE_object.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" enum { MESHCMP_DVERT_WEIGHTMISMATCH = 1, @@ -463,7 +464,7 @@ void BKE_mesh_free(Mesh *me, int unlink) CustomData_free(&me->pdata, me->totpoly); if (me->adt) { - BKE_free_animdata(&me->id); + BKE_animdata_free(&me->id); me->adt = NULL; } @@ -1265,7 +1266,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, dl = dispbase->first; while (dl) { - int smooth = dl->rt & CU_SMOOTH ? 1 : 0; + const bool is_smooth = (dl->rt & CU_SMOOTH) != 0; if (dl->type == DL_SEGM) { startvert = vertcount; @@ -1344,7 +1345,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, } } - if (smooth) mpoly->flag |= ME_SMOOTH; + if (is_smooth) mpoly->flag |= ME_SMOOTH; mpoly++; mloop += 3; index += 3; @@ -1423,7 +1424,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, } } - if (smooth) mpoly->flag |= ME_SMOOTH; + if (is_smooth) mpoly->flag |= ME_SMOOTH; mpoly++; mloop += 4; @@ -1773,6 +1774,36 @@ void BKE_mesh_material_index_clear(Mesh *me) } } +void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len) +{ + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMFace *efa; + + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + MAT_NR_REMAP(efa->mat_nr); + } + } + else { + int i; + for (i = 0; i < me->totpoly; i++) { + MAT_NR_REMAP(me->mpoly[i].mat_nr); + } + } + +#undef MAT_NR_REMAP + +} + void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) { Mesh *me = meshOb->data; @@ -1805,7 +1836,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) * Return a newly MEM_malloc'd array of all the mesh vertex locations * \note \a r_numVerts may be NULL */ -float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3] +float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3] { int i, numVerts = me->totvert; float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1"); @@ -1821,8 +1852,9 @@ float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3] * Find the index of the loop in 'poly' which references vertex, * returns -1 if not found */ -int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, - unsigned vert) +int poly_find_loop_from_vert( + const MPoly *poly, const MLoop *loopstart, + unsigned vert) { int j; for (j = 0; j < poly->totloop; j++, loopstart++) { @@ -1838,20 +1870,22 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, * vertex. Returns the index of the loop matching vertex, or -1 if the * vertex is not in \a poly */ -int poly_get_adj_loops_from_vert(unsigned r_adj[3], const MPoly *poly, - const MLoop *mloop, unsigned vert) +int poly_get_adj_loops_from_vert( + unsigned r_adj[2], const MPoly *poly, + const MLoop *mloop, unsigned vert) { int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert); if (corner != -1) { +#if 0 /* unused - this loop */ const MLoop *ml = &mloop[poly->loopstart + corner]; +#endif /* vertex was found */ r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v; - r_adj[1] = ml->v; - r_adj[2] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v; + r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v; } return corner; @@ -1887,6 +1921,7 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) { int i; MVert *mvert = me->mvert; + float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL); for (i = 0; i < me->totvert; i++, mvert++) mul_m4_v3(mat, mvert->co); @@ -1901,7 +1936,17 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) } } - /* don't update normals, caller can do this explicitly */ + /* don't update normals, caller can do this explicitly. + * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */ + if (lnors) { + float m3[3][3]; + + copy_m3_m4(m3, mat); + normalize_m3(m3); + for (i = 0; i < me->totloop; i++, lnors++) { + mul_m3_v3(m3, *lnors); + } + } } void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) @@ -2124,6 +2169,146 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) (me->mselect[me->totselect - 1].type == type)); } +void BKE_mesh_calc_normals_split(Mesh *mesh) +{ + float (*r_loopnors)[3]; + float (*polynors)[3]; + short (*clnors)[2] = NULL; + bool free_polynors = false; + + if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { + r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); + } + else { + r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + } + + /* may be NULL */ + clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); + + if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { + /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */ + polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + free_polynors = false; + } + else { + polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); + BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, + polynors, false); + free_polynors = true; + } + + BKE_mesh_normals_loop_split( + mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, + mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, + (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL); + + if (free_polynors) { + MEM_freeN(polynors); + } +} + +/* Spli faces based on the edge angle. + * Matches behavior of face splitting in render engines. + */ +void BKE_mesh_split_faces(Mesh *mesh) +{ + const int num_verts = mesh->totvert; + const int num_edges = mesh->totedge; + const int num_polys = mesh->totpoly; + MVert *mvert = mesh->mvert; + MEdge *medge = mesh->medge; + MLoop *mloop = mesh->mloop; + MPoly *mpoly = mesh->mpoly; + float (*lnors)[3]; + int poly, num_new_verts = 0; + if ((mesh->flag & ME_AUTOSMOOTH) == 0) { + return; + } + BKE_mesh_tessface_clear(mesh); + /* Compute loop normals if needed. */ + if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { + BKE_mesh_calc_normals_split(mesh); + } + lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + /* Count. */ + for (poly = 0; poly < num_polys; poly++) { + MPoly *mp = &mpoly[poly]; + int loop; + for (loop = 0; loop < mp->totloop; loop++) { + MLoop *ml = &mloop[mp->loopstart + loop]; + MVert *mv = &mvert[ml->v]; + float vn[3]; + normal_short_to_float_v3(vn, mv->no); + if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) { + num_new_verts++; + } + } + } + if (num_new_verts == 0) { + /* No new vertices are to be added, can do early exit. */ + return; + } + /* Actual split. */ + mesh->totvert += num_new_verts; + mesh->totedge += 2 * num_new_verts; + mvert = mesh->mvert = MEM_reallocN(mesh->mvert, + sizeof(MVert) * mesh->totvert); + medge = mesh->medge = MEM_reallocN(mesh->medge, + sizeof(MEdge) * mesh->totedge); + CustomData_set_layer(&mesh->vdata, CD_MVERT, mesh->mvert); + CustomData_set_layer(&mesh->edata, CD_MEDGE, mesh->medge); + num_new_verts = 0; + for (poly = 0; poly < num_polys; poly++) { + MPoly *mp = &mpoly[poly]; + int loop; + for (loop = 0; loop < mp->totloop; loop++) { + int poly_loop = mp->loopstart + loop; + MLoop *ml = &mloop[poly_loop]; + MVert *mv = &mvert[ml->v]; + float vn[3]; + normal_short_to_float_v3(vn, mv->no); + if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) { + int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop; + MLoop *ml_prev = &mloop[poly_loop_prev]; + int new_edge_prev, new_edge; + /* Cretae new vertex. */ + int new_vert = num_verts + num_new_verts; + CustomData_copy_data(&mesh->vdata, &mesh->vdata, + ml->v, new_vert, 1); + normal_float_to_short_v3(mvert[new_vert].no, + lnors[poly_loop]); + /* Create new edges. */ + new_edge_prev = num_edges + 2 * num_new_verts; + new_edge = num_edges + 2 * num_new_verts + 1; + CustomData_copy_data(&mesh->edata, &mesh->edata, + ml_prev->e, new_edge_prev, 1); + CustomData_copy_data(&mesh->edata, &mesh->edata, + ml->e, new_edge, 1); + if (medge[new_edge_prev].v1 == ml->v) { + medge[new_edge_prev].v1 = new_vert; + } + else { + medge[new_edge_prev].v2 = new_vert; + } + if (medge[new_edge].v1 == ml->v) { + medge[new_edge].v1 = new_vert; + } + else { + medge[new_edge].v2 = new_vert; + } + + ml->v = new_vert; + ml_prev->e = new_edge_prev; + ml->e = new_edge; + num_new_verts++; + } + } + } +} + /* settings: 1 - preview, 2 - render */ Mesh *BKE_mesh_new_from_object( Main *bmain, Scene *sce, Object *ob, @@ -2213,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object( * only contains for_render flag. As soon as CoW is * implemented, this is to be rethinked. */ - EvaluationContext eval_ctx = {0}; - eval_ctx.mode = DAG_EVAL_RENDER; + EvaluationContext eval_ctx; + DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER); BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); @@ -2339,3 +2524,75 @@ Mesh *BKE_mesh_new_from_object( return tmpmesh; } +/* settings: 1 - preview, 2 - render */ +Mesh *BKE_mesh_new_from_dupli_data( + Main *bmain, DupliObjectData *data, + bool calc_tessface, bool calc_undeformed) +{ + Object *ob = data->ob; + DerivedMesh *dm = data->dm; + CustomDataMask mask; + + Mesh *tmpmesh; + + if (!ob || !dm) + return NULL; + + mask = CD_MASK_MESH; /* this seems more suitable, exporter, + * for example, needs CD_MASK_MDEFORMVERT */ + if (calc_undeformed) + mask |= CD_MASK_ORCO; + + tmpmesh = BKE_mesh_add(bmain, "Mesh"); + DM_to_mesh(dm, tmpmesh, ob, mask, true); + + /* BKE_mesh_add/copy gives us a user count we don't need */ + tmpmesh->id.us--; + + /* Copy materials to new mesh */ + switch (ob->type) { + case OB_MESH: { + Mesh *origmesh = ob->data; + int i; + + tmpmesh->flag = origmesh->flag; + tmpmesh->mat = MEM_dupallocN(origmesh->mat); + tmpmesh->totcol = origmesh->totcol; + tmpmesh->smoothresh = origmesh->smoothresh; + if (origmesh->mat) { + for (i = origmesh->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i]; + + if (tmpmesh->mat[i]) { + tmpmesh->mat[i]->id.us++; + } + } + } + break; + } + } /* end copy materials */ + + if (calc_tessface) { + /* cycles and exporters rely on this still */ + BKE_mesh_tessface_ensure(tmpmesh); + } + + /* make sure materials get updated in objects */ + test_object_materials(bmain, &tmpmesh->id); + + return tmpmesh; +} + +/* **** Depsgraph evaluation **** */ + +void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Mesh *mesh) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, mesh->id.name); + } + if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) { + BKE_mesh_texspace_calc(mesh); + } +} diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 40a09eba658..d17ca751c5e 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -226,7 +226,7 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly MPoly *mp; if (only_face_normals) { - BLI_assert(pnors != NULL); + BLI_assert((pnors != NULL) || (numPolys == 0)); #pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT) for (i = 0; i < numPolys; i++) { @@ -252,12 +252,12 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly } } - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ for (i = 0; i < numVerts; i++) { MVert *mv = &mverts[i]; float *no = tnorms[i]; if (UNLIKELY(normalize_v3(no) == 0.0f)) { + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ normalize_v3_v3(no, mv->co); } @@ -372,6 +372,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, * tag it as invalid and abort. */ lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; + + if (edge_vectors) { + BLI_stack_clear(edge_vectors); + } return; } @@ -387,7 +391,9 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], BLI_stack_discard(edge_vectors); nbr++; } - BLI_assert(nbr > 2); /* This piece of code shall only be called for more than one loop... */ + /* Note: In theory, this could be 'nbr > 2', but there is one case where we only have two edges for + * two loops: a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */ + BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */ lnor_space->ref_alpha = alpha / (float)nbr; } else { @@ -1347,6 +1353,10 @@ static void mesh_normals_loop_custom_set( const int nidx = lidx; float *nor = custom_loopnors[nidx]; + if (is_zero_v3(nor)) { + nor = lnors[nidx]; + } + if (!org_nor) { org_nor = nor; } @@ -1406,6 +1416,10 @@ static void mesh_normals_loop_custom_set( const int nidx = use_vertices ? (int)mloops[lidx].v : lidx; float *nor = custom_loopnors[nidx]; + if (is_zero_v3(nor)) { + nor = lnors[nidx]; + } + nbr_nors++; add_v3_v3(avg_nor, nor); BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]); @@ -2243,12 +2257,15 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData /** * Recreate tessellation. * - * \param do_face_nor_copy controls whether the normals from the poly are copied to the tessellated faces. + * \param do_face_nor_copy: Controls whether the normals from the poly are copied to the tessellated faces. * * \return number of tessellation faces. */ -int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata, - MVert *mvert, int totface, int totloop, int totpoly, const bool do_face_nor_cpy) +int BKE_mesh_recalc_tessellation( + CustomData *fdata, CustomData *ldata, CustomData *pdata, + MVert *mvert, + int totface, int totloop, int totpoly, + const bool do_face_nor_copy) { /* use this to avoid locking pthread for _every_ polygon * and calling the fill function */ @@ -2458,7 +2475,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); - if (do_face_nor_cpy) { + if (do_face_nor_copy) { /* If polys have a normals layer, copying that to faces can help * avoid the need to recalculate normals later */ if (CustomData_has_layer(pdata, CD_NORMAL)) { diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index 8d9fbe46f19..8b41aded3d9 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -30,7 +30,9 @@ #include "MEM_guardedalloc.h" #include "DNA_meshdata_types.h" +#include "DNA_vec_types.h" +#include "BLI_buffer.h" #include "BLI_utildefines.h" #include "BLI_bitmap.h" #include "BLI_math.h" @@ -52,8 +54,10 @@ /* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could * but for now this replaces it because its unused. */ -UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, - unsigned int totpoly, unsigned int totvert, int selected, float *limit) +UvVertMap *BKE_mesh_uv_vert_map_create( + struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, + unsigned int totpoly, unsigned int totvert, + const float limit[2], const bool selected, const bool use_winding) { UvVertMap *vmap; UvMapVert *buf; @@ -61,6 +65,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, unsigned int a; int i, totuv, nverts; + bool *winding; + BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32); + totuv = 0; /* generate UvMapVert array */ @@ -72,7 +79,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, if (totuv == 0) return NULL; + winding = MEM_callocN(sizeof(*winding) * totpoly, "winding"); vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap"); + if (!vmap) return NULL; @@ -87,6 +96,8 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, mp = mpoly; for (a = 0; a < totpoly; a++, mp++) { if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, mp->totloop); + nverts = mp->totloop; for (i = 0; i < nverts; i++) { @@ -95,8 +106,15 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, buf->separate = 0; buf->next = vmap->vert[mloop[mp->loopstart + i].v]; vmap->vert[mloop[mp->loopstart + i].v] = buf; + + copy_v2_v2(tf_uv[i], mloopuv[mpoly[a].loopstart + i].uv); buf++; } + + if (use_winding) + winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0; + else + winding[a] = 0; } } @@ -123,7 +141,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, sub_v2_v2v2(uvdiff, uv2, uv); - if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1]) { + if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1] && + winding[iterv->f] == winding[v->f]) + { if (lastv) lastv->next = next; else vlist = next; iterv->next = newvlist; @@ -141,6 +161,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, vmap->vert[a] = newvlist; } + MEM_freeN(winding); + BLI_buffer_free(&tf_uv_buf); + return vmap; } @@ -159,8 +182,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap) } /** - - * Generates a map where the key is the vertex and the value is a list * of polys or loops that use that vertex as a corner. The lists are allocated * from one memory pool. @@ -233,9 +254,10 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem, mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true); } -/* Generates a map where the key is the vertex and the value is a list - * of edges that use that vertex as an endpoint. The lists are allocated - * from one memory pool. */ +/** + * Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint. + * The lists are allocated from one memory pool. + */ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge) { @@ -275,6 +297,10 @@ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, *r_mem = indices; } +/** + * Generates a map where the key is the edge and the value is a list of polygons that use that edge. + * The lists are allocated from one memory pool. + */ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, const MEdge *UNUSED(medge), const int totedge, const MPoly *mpoly, const int totpoly, @@ -382,7 +408,8 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem, * Used currently for UVs and 'smooth groups'. * \{ */ -/** Callback deciding whether the given poly/loop/edge define an island boundary or not. +/** + * Callback deciding whether the given poly/loop/edge define an island boundary or not. */ typedef bool (*MeshRemap_CheckIslandBoundary)( const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, @@ -565,8 +592,7 @@ static void poly_edge_loop_islands_calc( } static bool poly_is_island_boundary_smooth_cb( - const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, - const int nbr_egde_users) + const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users) { /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */ return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2)); @@ -663,7 +689,6 @@ void BKE_mesh_loop_islands_add( const size_t curr_num_islands = (size_t)island_store->islands_num; int i = item_num; - island_store->items_to_islands_num = item_num; while (i--) { island_store->items_to_islands[items_indices[i]] = curr_island_idx; } @@ -698,17 +723,21 @@ void BKE_mesh_loop_islands_add( * not sure we want that at all! */ static bool mesh_check_island_boundary_uv( - const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, - const int UNUSED(nbr_egde_users)) + const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users)) { /* Edge is UV boundary if tagged as seam. */ return (me->flag & ME_SEAM) != 0; } /** - * \note all this could be optimized... - * Not sure it would be worth the more complex code, though, those loops - * are supposed to be really quick to do... + * Calculate UV islands. + * + * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity, + * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams + * will not be handled correctly... + * + * \note All this could be optimized... + * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do... */ bool BKE_mesh_calc_islands_loop_poly_uv( MVert *UNUSED(verts), const int UNUSED(totvert), diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index aca72614094..0ed10687fae 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -707,7 +707,7 @@ void BKE_mesh_remap_calc_edges_from_dm( BLI_space_transform_apply_normal(space_transform, v2_no); } - fill_vn_fl(weights, (int)numedges_src, 0.0f); + copy_vn_fl(weights, (int)numedges_src, 0.0f); /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), * with lower/upper bounds. */ @@ -977,6 +977,8 @@ void BKE_mesh_remap_calc_loops_from_dm( float (*poly_nors_dst)[3] = NULL; float (*loop_nors_dst)[3] = NULL; + float (*poly_cents_src)[3] = NULL; + MeshElemMap *vert_to_loop_map_src = NULL; int *vert_to_loop_map_src_buff = NULL; MeshElemMap *vert_to_poly_map_src = NULL; @@ -1012,6 +1014,8 @@ void BKE_mesh_remap_calc_loops_from_dm( int *indices_interp = NULL; float *weights_interp = NULL; + MLoop *ml_src, *ml_dst; + MPoly *mp_src, *mp_dst; int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src; IslandResult **islands_res; @@ -1089,11 +1093,13 @@ void BKE_mesh_remap_calc_loops_from_dm( edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src); if (use_from_vert) { loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__); - for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) { - MPoly *mp = &polys_src[pidx_src]; - for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) { + poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__); + for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) { + ml_src = &loops_src[mp_src->loopstart]; + for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) { loop_to_poly_map_src[lidx_src] = pidx_src; } + BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]); } } @@ -1155,10 +1161,13 @@ void BKE_mesh_remap_calc_loops_from_dm( int num_verts_active = 0; BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src); for (i = 0; i < isld->count; i++) { - MPoly *mp_src = &polys_src[isld->indices[i]]; + mp_src = &polys_src[isld->indices[i]]; for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) { - BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); - num_verts_active++; + const unsigned int vidx_src = loops_src[lidx_src].v; + if (!BLI_BITMAP_TEST(verts_active, vidx_src)) { + BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); + num_verts_active++; + } } } /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ @@ -1199,13 +1208,13 @@ void BKE_mesh_remap_calc_loops_from_dm( int num_faces_active = 0; BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src); for (i = 0; i < num_faces_src; i++) { - MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]]; + mp_src = &polys_src[tessface_to_poly_map_src[i]]; if (island_store.items_to_islands[mp_src->loopstart] == tindex) { BLI_BITMAP_ENABLE(faces_active, i); num_faces_active++; } } - /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ + /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */ bvhtree_from_mesh_faces_ex( &treedata[tindex], verts_src, verts_allocated_src, faces_src, num_faces_src, faces_allocated_src, @@ -1233,10 +1242,14 @@ void BKE_mesh_remap_calc_loops_from_dm( islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__); } - for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) { - MPoly *mp_dst = &polys_dst[pidx_dst]; + for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) { float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst]; + /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which + * corner to use from normals only. */ + float pcent_dst[3]; + bool pcent_dst_valid = false; + if ((size_t)mp_dst->totloop > islands_res_buff_size) { islands_res_buff_size = (size_t)mp_dst->totloop; for (tindex = 0; tindex < num_trees; tindex++) { @@ -1246,8 +1259,8 @@ void BKE_mesh_remap_calc_loops_from_dm( for (tindex = 0; tindex < num_trees; tindex++) { BVHTreeFromMesh *tdata = &treedata[tindex]; - MLoop *ml_dst = &loops_dst[mp_dst->loopstart]; + ml_dst = &loops_dst[mp_dst->loopstart]; for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { if (use_from_vert) { float tmp_co[3]; @@ -1263,6 +1276,7 @@ void BKE_mesh_remap_calc_loops_from_dm( float (*nor_dst)[3]; float (*nors_src)[3]; float best_nor_dot = -2.0f; + float best_sqdist_fallback = FLT_MAX; int best_index_src = -1; if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { @@ -1279,16 +1293,50 @@ void BKE_mesh_remap_calc_loops_from_dm( for (i = vert_to_refelem_map_src[nearest.index].count; i--;) { const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; const float dot = dot_v3v3(nors_src[index_src], *nor_dst); - if (dot > best_nor_dot) { - best_nor_dot = dot; - best_index_src = index_src; + + pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + loop_to_poly_map_src[index_src] : index_src; + /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it + * to check we stay on current island (all loops from a given poly are + * on same island!). */ + lidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + index_src : polys_src[pidx_src].loopstart; + + /* A same vert may be at the boundary of several islands! Hence, we have to ensure + * poly/loop we are currently considering *belongs* to current island! */ + if (use_islands && island_store.items_to_islands[lidx_src] != tindex) { + continue; + } + + if (dot > best_nor_dot - 1e-6f) { + /* We need something as fallback decision in case dest normal matches several + * source normals (see T44522), using distance between polys' centers here. */ + float *pcent_src; + float sqdist; + + mp_src = &polys_src[pidx_src]; + ml_src = &loops_src[mp_src->loopstart]; + + if (!pcent_dst_valid) { + BKE_mesh_calc_poly_center( + mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst); + pcent_dst_valid = true; + } + pcent_src = poly_cents_src[pidx_src]; + sqdist = len_squared_v3v3(pcent_dst, pcent_src); + + if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) { + best_nor_dot = dot; + best_sqdist_fallback = sqdist; + best_index_src = index_src; + } } } if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { /* Our best_index_src is a poly one for now! * Have to find its loop matching our closest vertex. */ - MPoly *mp_src = &polys_src[best_index_src]; - MLoop *ml_src = &loops_src[mp_src->loopstart]; + mp_src = &polys_src[best_index_src]; + ml_src = &loops_src[mp_src->loopstart]; for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) { if ((int)ml_src->v == nearest.index) { best_index_src = plidx_src + mp_src->loopstart; @@ -1296,7 +1344,8 @@ void BKE_mesh_remap_calc_loops_from_dm( } } } - islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f; + best_nor_dot = (best_nor_dot + 1.0f) * 0.5f; + islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist * best_nor_dot) : 1e18f; islands_res[tindex][plidx_dst].hit_dist = hit_dist; islands_res[tindex][plidx_dst].index_src = best_index_src; } @@ -1488,12 +1537,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (last_valid_pidx_isld_src != -1) { /* Find a new valid loop in that new poly (nearest one for now). * Note we could be much more subtle here, again that's for later... */ - MPoly *mp_src; - MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst]; int j; float best_dist_sq = FLT_MAX; float tmp_co[3]; + ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); /* We do our transform here, since we may do several raycast/nearest queries. */ @@ -1532,10 +1580,10 @@ void BKE_mesh_remap_calc_loops_from_dm( /* Else, we use source poly, indices stored in islands_res are those of polygons. */ pidx_src = isld_res->index_src; if (pidx_src >= 0) { - MPoly *mp_src = &polys_src[pidx_src]; float *hit_co = isld_res->hit_point; int best_loop_index_src; + mp_src = &polys_src[pidx_src]; /* If prev and curr poly are the same, no need to do anything more!!! */ if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { int pidx_isld_src, pidx_isld_src_prev; @@ -1575,11 +1623,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (last_valid_pidx_isld_src != -1) { /* Find a new valid loop in that new poly (nearest point on poly for now). * Note we could be much more subtle here, again that's for later... */ - MLoop *ml_dst = &loops_dst[lidx_dst]; float best_dist_sq = FLT_MAX; float tmp_co[3]; int j; + ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); /* We do our transform here, since we may do several raycast/nearest queries. */ @@ -1710,6 +1758,9 @@ void BKE_mesh_remap_calc_loops_from_dm( if (loop_to_poly_map_src) { MEM_freeN(loop_to_poly_map_src); } + if (poly_cents_src) { + MEM_freeN(poly_cents_src); + } if (vcos_interp) { MEM_freeN(vcos_interp); } @@ -1865,7 +1916,7 @@ void BKE_mesh_remap_calc_polys_from_dm( BLI_space_transform_apply_normal(space_transform, tmp_no); } - fill_vn_fl(weights, (int)numpolys_src, 0.0f); + copy_vn_fl(weights, (int)numpolys_src, 0.0f); if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) { tmp_poly_size = (size_t)mp->totloop; diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c new file mode 100644 index 00000000000..b1a89ec64fc --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_sample.c @@ -0,0 +1,381 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_sample.c + * \ingroup bke + * + * Sample a mesh surface or volume and evaluate samples on deformed meshes. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_rand.h" + +#include "BKE_bvhutils.h" +#include "BKE_mesh_sample.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" + +#include "BLI_strict_flags.h" + +/* ==== Evaluate ==== */ + +bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3], float tang[3]) +{ + MVert *mverts = dm->getVertArray(dm); + unsigned int totverts = (unsigned int)dm->getNumVerts(dm); + MVert *v1, *v2, *v3; + + zero_v3(loc); + zero_v3(nor); + zero_v3(tang); + + if (sample->orig_verts[0] >= totverts || + sample->orig_verts[1] >= totverts || + sample->orig_verts[2] >= totverts) + return false; + + v1 = &mverts[sample->orig_verts[0]]; + v2 = &mverts[sample->orig_verts[1]]; + v3 = &mverts[sample->orig_verts[2]]; + + { /* location */ + madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]); + madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]); + madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]); + } + + { /* normal */ + float vnor[3]; + + normal_short_to_float_v3(vnor, v1->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[0]); + normal_short_to_float_v3(vnor, v2->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[1]); + normal_short_to_float_v3(vnor, v3->no); + madd_v3_v3fl(nor, vnor, sample->orig_weights[2]); + + normalize_v3(nor); + } + + { /* tangent */ + float edge[3]; + + /* XXX simply using the v1-v2 edge as a tangent vector for now ... + * Eventually mikktspace generated tangents (CD_TANGENT tessface layer) + * should be used for consistency, but requires well-defined tessface + * indices for the mesh surface samples. + */ + + sub_v3_v3v3(edge, v2->co, v1->co); + /* make edge orthogonal to nor */ + madd_v3_v3fl(edge, nor, -dot_v3v3(edge, nor)); + normalize_v3_v3(tang, edge); + } + + return true; +} + +bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *sample, float loc[3]) +{ + float *v1, *v2, *v3; + + (void)key; /* Unused in release builds. */ + + BLI_assert(key->elemsize == 3 * sizeof(float)); + BLI_assert(sample->orig_verts[0] < (unsigned int)kb->totelem); + BLI_assert(sample->orig_verts[1] < (unsigned int)kb->totelem); + BLI_assert(sample->orig_verts[2] < (unsigned int)kb->totelem); + + v1 = (float *)kb->data + sample->orig_verts[0] * 3; + v2 = (float *)kb->data + sample->orig_verts[1] * 3; + v3 = (float *)kb->data + sample->orig_verts[2] * 3; + + zero_v3(loc); + madd_v3_v3fl(loc, v1, sample->orig_weights[0]); + madd_v3_v3fl(loc, v2, sample->orig_weights[1]); + madd_v3_v3fl(loc, v3, sample->orig_weights[2]); + + /* TODO use optional vgroup weights to determine if a shapeky actually affects the sample */ + return true; +} + + +/* ==== Sampling Utilities ==== */ + +BLI_INLINE void mesh_sample_weights_from_loc(MSurfaceSample *sample, DerivedMesh *dm, int face_index, const float loc[3]) +{ + MFace *face = &dm->getTessFaceArray(dm)[face_index]; + unsigned int index[4] = { face->v1, face->v2, face->v3, face->v4 }; + MVert *mverts = dm->getVertArray(dm); + + float *v1 = mverts[face->v1].co; + float *v2 = mverts[face->v2].co; + float *v3 = mverts[face->v3].co; + float *v4 = face->v4 ? mverts[face->v4].co : NULL; + float w[4]; + int tri[3]; + + interp_weights_face_v3_index(tri, w, v1, v2, v3, v4, loc); + + sample->orig_verts[0] = index[tri[0]]; + sample->orig_verts[1] = index[tri[1]]; + sample->orig_verts[2] = index[tri[2]]; + sample->orig_weights[0] = w[tri[0]]; + sample->orig_weights[1] = w[tri[1]]; + sample->orig_weights[2] = w[tri[2]]; +} + +/* ==== Sampling ==== */ + +static bool mesh_sample_store_array_sample(void *vdata, int capacity, int index, const MSurfaceSample *sample) +{ + MSurfaceSample *data = vdata; + if (index >= capacity) + return false; + + data[index] = *sample; + return true; +} + +void BKE_mesh_sample_storage_single(MSurfaceSampleStorage *storage, MSurfaceSample *sample) +{ + /* handled as just a special array case with capacity = 1 */ + storage->store_sample = mesh_sample_store_array_sample; + storage->capacity = 1; + storage->data = sample; + storage->free_data = false; +} + +void BKE_mesh_sample_storage_array(MSurfaceSampleStorage *storage, MSurfaceSample *samples, int capacity) +{ + storage->store_sample = mesh_sample_store_array_sample; + storage->capacity = capacity; + storage->data = samples; + storage->free_data = false; +} + +void BKE_mesh_sample_storage_release(MSurfaceSampleStorage *storage) +{ + if (storage->free_data) + MEM_freeN(storage->data); +} + + +int BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm, unsigned int seed, int totsample) +{ + MFace *mfaces; + int totfaces; + RNG *rng; + MFace *mface; + float a, b; + int i, stored = 0; + + rng = BLI_rng_new(seed); + + DM_ensure_tessface(dm); + mfaces = dm->getTessFaceArray(dm); + totfaces = dm->getNumTessFaces(dm); + + for (i = 0; i < totsample; ++i) { + MSurfaceSample sample = {{0}}; + + mface = &mfaces[BLI_rng_get_int(rng) % totfaces]; + + if (mface->v4 && BLI_rng_get_int(rng) % 2 == 0) { + sample.orig_verts[0] = mface->v3; + sample.orig_verts[1] = mface->v4; + sample.orig_verts[2] = mface->v1; + } + else { + sample.orig_verts[0] = mface->v1; + sample.orig_verts[1] = mface->v2; + sample.orig_verts[2] = mface->v3; + } + + a = BLI_rng_get_float(rng); + b = BLI_rng_get_float(rng); + if (a + b > 1.0f) { + a = 1.0f - a; + b = 1.0f - b; + } + sample.orig_weights[0] = 1.0f - (a + b); + sample.orig_weights[1] = a; + sample.orig_weights[2] = b; + + if (dst->store_sample(dst->data, dst->capacity, i, &sample)) + ++stored; + else + break; + } + + BLI_rng_free(rng); + + return stored; +} + + +static bool sample_bvh_raycast(MSurfaceSample *sample, DerivedMesh *dm, BVHTreeFromMesh *bvhdata, const float ray_start[3], const float ray_end[3]) +{ + BVHTreeRayHit hit; + float ray_normal[3], dist; + + sub_v3_v3v3(ray_normal, ray_end, ray_start); + dist = normalize_v3(ray_normal); + + hit.index = -1; + hit.dist = dist; + + if (BLI_bvhtree_ray_cast(bvhdata->tree, ray_start, ray_normal, 0.0f, + &hit, bvhdata->raycast_callback, bvhdata) >= 0) { + + mesh_sample_weights_from_loc(sample, dm, hit.index, hit.co); + + return true; + } + else + return false; +} + +int BKE_mesh_sample_generate_raycast(MSurfaceSampleStorage *dst, DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata, int totsample) +{ + BVHTreeFromMesh bvhdata; + float ray_start[3], ray_end[3]; + int i, stored = 0; + + DM_ensure_tessface(dm); + + memset(&bvhdata, 0, sizeof(BVHTreeFromMesh)); + bvhtree_from_mesh_faces(&bvhdata, dm, 0.0f, 4, 6); + + if (bvhdata.tree) { + for (i = 0; i < totsample; ++i) { + if (ray_cb(userdata, ray_start, ray_end)) { + MSurfaceSample sample; + if (sample_bvh_raycast(&sample, dm, &bvhdata, ray_start, ray_end)) { + if (dst->store_sample(dst->data, dst->capacity, i, &sample)) + ++stored; + else + break; + } + } + } + } + + free_bvhtree_from_mesh(&bvhdata); + + return stored; +} + +/* ==== Utilities ==== */ + +#include "DNA_particle_types.h" + +#include "BKE_bvhutils.h" +#include "BKE_particle.h" + +bool BKE_mesh_sample_from_particle(MSurfaceSample *sample, ParticleSystem *psys, DerivedMesh *dm, ParticleData *pa) +{ + MVert *mverts; + MFace *mface; + float mapfw[4]; + int mapindex; + float *co1 = NULL, *co2 = NULL, *co3 = NULL, *co4 = NULL; + float vec[3]; + float w[4]; + + if (!psys_get_index_on_dm(psys, dm, pa, &mapindex, mapfw)) + return false; + + mface = dm->getTessFaceData(dm, mapindex, CD_MFACE); + mverts = dm->getVertDataArray(dm, CD_MVERT); + + co1 = mverts[mface->v1].co; + co2 = mverts[mface->v2].co; + co3 = mverts[mface->v3].co; + + if (mface->v4) { + co4 = mverts[mface->v4].co; + + interp_v3_v3v3v3v3(vec, co1, co2, co3, co4, mapfw); + } + else { + interp_v3_v3v3v3(vec, co1, co2, co3, mapfw); + } + + /* test both triangles of the face */ + interp_weights_face_v3(w, co1, co2, co3, NULL, vec); + if (w[0] <= 1.0f && w[1] <= 1.0f && w[2] <= 1.0f) { + sample->orig_verts[0] = mface->v1; + sample->orig_verts[1] = mface->v2; + sample->orig_verts[2] = mface->v3; + + copy_v3_v3(sample->orig_weights, w); + return true; + } + else if (mface->v4) { + interp_weights_face_v3(w, co3, co4, co1, NULL, vec); + sample->orig_verts[0] = mface->v3; + sample->orig_verts[1] = mface->v4; + sample->orig_verts[2] = mface->v1; + + copy_v3_v3(sample->orig_weights, w); + return true; + } + else + return false; +} + +bool BKE_mesh_sample_to_particle(MSurfaceSample *sample, ParticleSystem *UNUSED(psys), DerivedMesh *dm, BVHTreeFromMesh *bvhtree, ParticleData *pa) +{ + BVHTreeNearest nearest; + float vec[3], nor[3], tang[3]; + + BKE_mesh_sample_eval(dm, sample, vec, nor, tang); + + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + BLI_bvhtree_find_nearest(bvhtree->tree, vec, &nearest, bvhtree->nearest_callback, bvhtree); + if (nearest.index >= 0) { + MFace *mface = dm->getTessFaceData(dm, nearest.index, CD_MFACE); + MVert *mverts = dm->getVertDataArray(dm, CD_MVERT); + + float *co1 = mverts[mface->v1].co; + float *co2 = mverts[mface->v2].co; + float *co3 = mverts[mface->v3].co; + float *co4 = mface->v4 ? mverts[mface->v4].co : NULL; + + pa->num = nearest.index; + pa->num_dmcache = DMCACHE_NOTFOUND; + + interp_weights_face_v3(pa->fuv, co1, co2, co3, co4, vec); + pa->foffset = 0.0f; /* XXX any sensible way to reconstruct this? */ + + return true; + } + else + return false; +} diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 7de993e1099..f758bcdf2f5 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -1475,8 +1475,9 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) int j, v_prev = (l + (mp->totloop - 1))->v; for (j = 0; j < mp->totloop; j++, l++) { if (v_prev != l->v) { - if (!BLI_edgehash_haskey(eh, v_prev, l->v)) { - BLI_edgehash_insert(eh, v_prev, l->v, NULL); + void **val_p; + if (!BLI_edgehash_ensure_p(eh, v_prev, l->v, &val_p)) { + *val_p = NULL; } } v_prev = l->v; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 42247d866e4..4d007e12ef5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -57,6 +57,7 @@ #include "BLF_translation.h" #include "BKE_appdir.h" +#include "BKE_cache_library.h" #include "BKE_key.h" #include "BKE_multires.h" #include "BKE_DerivedMesh.h" @@ -68,7 +69,7 @@ #include "MOD_modifiertypes.h" -static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL}; +static ModifierTypeInfo *cache_modifier_types[NUM_MODIFIER_TYPES] = {NULL}; static VirtualModifierData virtualModifierCommonData; void BKE_modifier_init(void) @@ -76,7 +77,7 @@ void BKE_modifier_init(void) ModifierData *md; /* Initialize modifier types */ - modifier_type_init(modifier_types); /* MOD_utils.c */ + modifier_type_init(cache_modifier_types); /* MOD_utils.c */ /* Initialize global cmmon storage used for virtual modifier list */ md = modifier_new(eModifierType_Armature); @@ -99,13 +100,15 @@ void BKE_modifier_init(void) virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual; virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual; virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual; + + BKE_cache_modifier_init(); } -ModifierTypeInfo *modifierType_getInfo(ModifierType type) +const ModifierTypeInfo *modifierType_getInfo(ModifierType type) { /* type unsigned, no need to check < 0 */ - if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') { - return modifier_types[type]; + if (type < NUM_MODIFIER_TYPES && cache_modifier_types[type]->name[0] != '\0') { + return cache_modifier_types[type]; } else { return NULL; @@ -116,7 +119,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) ModifierData *modifier_new(int type) { - ModifierTypeInfo *mti = modifierType_getInfo(type); + const ModifierTypeInfo *mti = modifierType_getInfo(type); ModifierData *md = MEM_callocN(mti->structSize, mti->structName); /* note, this name must be made unique later */ @@ -135,7 +138,7 @@ ModifierData *modifier_new(int type) void modifier_free(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (mti->freeData) mti->freeData(md); if (md->error) MEM_freeN(md->error); @@ -146,7 +149,7 @@ void modifier_free(ModifierData *md) bool modifier_unique_name(ListBase *modifiers, ModifierData *md) { if (modifiers && md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name)); } @@ -155,14 +158,14 @@ bool modifier_unique_name(ListBase *modifiers, ModifierData *md) bool modifier_dependsOnTime(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); return mti->dependsOnTime && mti->dependsOnTime(md); } bool modifier_supportsMapping(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); return (mti->type == eModifierTypeType_OnlyDeform || (mti->flags & eModifierTypeFlag_SupportsMapping)); @@ -170,7 +173,7 @@ bool modifier_supportsMapping(ModifierData *md) bool modifier_isPreview(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */ if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) { @@ -221,7 +224,7 @@ void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, ModifierData *md = ob->modifiers.first; for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (mti->foreachObjectLink) mti->foreachObjectLink(md, ob, walk, userData); @@ -233,7 +236,7 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData) ModifierData *md = ob->modifiers.first; for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData); else if (mti->foreachObjectLink) { @@ -249,7 +252,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData) ModifierData *md = ob->modifiers.first; for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (mti->foreachTexLink) mti->foreachTexLink(md, ob, walk, userData); @@ -261,7 +264,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData) */ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst) { - ModifierTypeInfo *mti = modifierType_getInfo(md_src->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type); const size_t data_size = sizeof(ModifierData); const char *md_src_data = ((const char *)md_src) + data_size; char *md_dst_data = ((char *)md_dst) + data_size; @@ -271,7 +274,7 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst) void modifier_copyData(ModifierData *md, ModifierData *target) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); target->mode = md->mode; @@ -282,7 +285,7 @@ void modifier_copyData(ModifierData *md, ModifierData *target) bool modifier_supportsCage(struct Scene *scene, ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -293,7 +296,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md) bool modifier_couldBeCage(struct Scene *scene, ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -305,13 +308,13 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md) bool modifier_isSameTopology(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical); } bool modifier_isNonGeometrical(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); return (mti->type == eModifierTypeType_NonGeometrical); } @@ -353,7 +356,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC /* Find the last modifier acting on the cage. */ for (i = 0; md; i++, md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); bool supports_mapping; md->scene = scene; @@ -411,7 +414,7 @@ bool modifiers_isParticleEnabled(Object *ob) bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; @@ -432,7 +435,7 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierDat /* build a list of modifier data requirements in reverse order */ for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink"); @@ -626,7 +629,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm) bool modifier_isCorrectableDeformed(ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); return (mti->deformMatricesEM != NULL); } @@ -736,7 +739,7 @@ struct DerivedMesh *modwrap_applyModifier( struct DerivedMesh *dm, ModifierApplyFlag flag) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); if (mti->dependsOnNormals && mti->dependsOnNormals(md)) { @@ -751,7 +754,7 @@ struct DerivedMesh *modwrap_applyModifierEM( DerivedMesh *dm, ModifierApplyFlag flag) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); if (mti->dependsOnNormals && mti->dependsOnNormals(md)) { @@ -766,7 +769,7 @@ void modwrap_deformVerts( float (*vertexCos)[3], int numVerts, ModifierApplyFlag flag) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) { @@ -780,7 +783,7 @@ void modwrap_deformVertsEM( struct BMEditMesh *em, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) { diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 645567eea67..18f3db6bd15 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -37,8 +37,9 @@ #include "BKE_editmesh.h" /* Static function for alloc */ -static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml, - BMesh *bm, BMVert **vtable, BMEdge **etable) +static BMFace *bm_face_create_from_mpoly( + MPoly *mp, MLoop *ml, + BMesh *bm, BMVert **vtable, BMEdge **etable) { BMVert **verts = BLI_array_alloca(verts, mp->totloop); BMEdge **edges = BLI_array_alloca(edges, mp->totloop); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 73f75f4f96d..f063933f3f9 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1129,15 +1129,15 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy) } /* get segments of cached frames. useful for debugging cache policies */ -void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *totseg_r, int **points_r) +void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *r_totseg, int **r_points) { - *totseg_r = 0; - *points_r = NULL; + *r_totseg = 0; + *r_points = NULL; if (clip->cache) { int proxy = rendersize_to_proxy(user, clip->flag); - IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, totseg_r, points_r); + IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points); } } @@ -1168,7 +1168,7 @@ static void free_buffers(MovieClip *clip) clip->anim = NULL; } - BKE_free_animdata((ID *) clip); + BKE_animdata_free((ID *) clip); } void BKE_movieclip_clear_cache(MovieClip *clip) diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 220d0f7c604..0c984c38b8e 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -280,7 +280,7 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob) { ModifierData *md = (ModifierData *)mmd; - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); DerivedMesh *dm; @@ -340,13 +340,13 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd, bool render, bool ignore_simplify) { if (render) - return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl) : mmd->renderlvl; + return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl; else if (ob->mode == OB_MODE_SCULPT) return mmd->sculptlvl; else if (ignore_simplify) return mmd->lvl; else - return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl) : mmd->lvl; + return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl; } void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) @@ -429,7 +429,7 @@ int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *ds int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd, Object *ob, ModifierData *md) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); DerivedMesh *dm, *ndm; int numVerts, result; float (*deformedVerts)[3]; @@ -882,18 +882,20 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl { Mesh *me = ob->data; MDisps *mdisps; - int lvl = mmd->totlvl; + const int lvl = mmd->totlvl; if ((totlvl > multires_max_levels) || (me->totpoly == 0)) return; + BLI_assert(totlvl > lvl); + multires_force_update(ob); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); if (!mdisps) mdisps = multires_mdisps_initialize_hidden(me, totlvl); - if (mdisps->disps && !updateblock && totlvl > 1) { + if (mdisps->disps && !updateblock && lvl != 0) { /* upsample */ DerivedMesh *lowdm, *cddm, *highdm; CCGElem **highGridData, **lowGridData, **subGridData; @@ -910,6 +912,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl /* create multires DM from original mesh at low level */ lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask); + BLI_assert(lowdm != cddm); cddm->release(cddm); /* copy subsurf grids and replace them with low displaced grids */ @@ -2137,27 +2140,38 @@ void multires_load_old(Object *ob, Mesh *me) me->mr = NULL; } -/* If 'ob' and 'to_ob' both have multires modifiers, synchronize them - * such that 'ob' has the same total number of levels as 'to_ob'. */ -static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob) +/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them + * such that 'ob_dst' has the same total number of levels as 'ob_src'. */ +void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) { - MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1); - MultiresModifierData *to_mmd = get_multires_modifier(scene, to_ob, 1); + if (mmd_src->totlvl == mmd_dst->totlvl) { + return; + } + + if (mmd_src->totlvl > mmd_dst->totlvl) { + multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); + } + else { + multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); + } +} - if (!mmd) { +static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) +{ + MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true); + MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true); + + if (!mmd_src) { /* object could have MDISP even when there is no multires modifier * this could lead to troubles due to i've got no idea how mdisp could be * upsampled correct without modifier data. * just remove mdisps if no multires present (nazgul) */ - multires_customdata_delete(ob->data); + multires_customdata_delete(ob_src->data); } - if (mmd && to_mmd) { - if (mmd->totlvl > to_mmd->totlvl) - multires_del_higher(mmd, ob, to_mmd->totlvl); - else - multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple); + if (mmd_src && mmd_dst) { + multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst); } } @@ -2276,7 +2290,7 @@ void multiresModifier_scale_disp(Scene *scene, Object *ob) void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob) { float smat[3][3], tmat[3][3], mat[3][3]; - multires_sync_levels(scene, ob, to_ob); + multires_sync_levels(scene, to_ob, ob); /* construct scale matrix for displacement */ BKE_object_scale_to_mat3(to_ob, tmat); diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 9a04312aaab..1ad6446eb05 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -535,9 +535,14 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode) /* if the active-strip info has been stored already, access this, otherwise look this up * and store for (very probable) future usage */ + if (adt->act_track == NULL) { + if (adt->actstrip) + adt->act_track = BKE_nlatrack_find_tweaked(adt); + else + adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks); + } if (adt->actstrip == NULL) { - NlaTrack *nlt = BKE_nlatrack_find_active(&adt->nla_tracks); - adt->actstrip = BKE_nlastrip_find_active(nlt); + adt->actstrip = BKE_nlastrip_find_active(adt->act_track); } strip = adt->actstrip; @@ -926,6 +931,39 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks) return NULL; } +/* Get the NLA Track that the active action/action strip comes from, + * since this info is not stored in AnimData. It also isn't as simple + * as just using the active track, since multiple tracks may have been + * entered at the same time. + */ +NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt) +{ + NlaTrack *nlt; + + /* sanity check */ + if (adt == NULL) + return NULL; + + /* Since the track itself gets disabled, we want the first disabled... */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) { + /* For good measure, make sure that strip actually exists there */ + if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) { + return nlt; + } + else if (G.debug & G_DEBUG) { + printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n", + __func__, + adt->actstrip, (adt->actstrip) ? adt->actstrip->name : "<None>", + nlt, nlt->name); + } + } + } + + /* Not found! */ + return NULL; +} + /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one * that has this status in its AnimData block. */ @@ -1584,6 +1622,12 @@ bool BKE_nla_action_stash(AnimData *adt) nlt = add_nlatrack(adt, prev_track); BLI_assert(nlt != NULL); + /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */ + if (prev_track == NULL) { + BLI_remlink(&adt->nla_tracks, nlt); + BLI_addhead(&adt->nla_tracks, nlt); + } + BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name)); BLI_uniquename(&adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name)); @@ -1605,6 +1649,12 @@ bool BKE_nla_action_stash(AnimData *adt) nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED); strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE); + /* also mark the strip for auto syncing the length, so that the strips accurately + * reflect the length of the action + * XXX: we could do with some extra flags here to prevent repeats/scaling options from working! + */ + strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH; + /* succeeded */ return true; } @@ -1756,6 +1806,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) */ adt->tmpact = adt->action; adt->action = activeStrip->act; + adt->act_track = activeTrack; adt->actstrip = activeStrip; id_us_plus(&activeStrip->act->id); adt->flag |= ADT_NLA_EDIT_ON; @@ -1815,6 +1866,7 @@ void BKE_nla_tweakmode_exit(AnimData *adt) if (adt->action) adt->action->id.us--; adt->action = adt->tmpact; adt->tmpact = NULL; + adt->act_track = NULL; adt->actstrip = NULL; adt->flag &= ~ADT_NLA_EDIT_ON; } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index c7010e42aac..9e159fa5852 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -303,7 +303,7 @@ bNodeTreeType *ntreeTypeFind(const char *idname) void ntreeTypeAdd(bNodeTreeType *nt) { - BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt); + BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ update_typeinfo(G.main, NULL, nt, NULL, NULL, false); } @@ -317,7 +317,7 @@ static void ntree_free_type(void *treetype_v) MEM_freeN(treetype); } -void ntreeTypeFreeLink(bNodeTreeType *nt) +void ntreeTypeFreeLink(const bNodeTreeType *nt) { BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type); } @@ -378,7 +378,7 @@ void nodeRegisterType(bNodeType *nt) BLI_assert(nt->idname[0] != '\0'); BLI_assert(nt->poll != NULL); - BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt); + BLI_ghash_insert(nodetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ update_typeinfo(G.main, NULL, NULL, nt, NULL, false); } @@ -1109,7 +1109,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) * copying for internal use (threads for eg), where you wont want it to modify the * scene data. */ -static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_id_user, bool do_make_extern, bool copy_previews) +static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews) { bNodeTree *newtree; bNode *node /*, *nnode */ /* UNUSED */, *last; @@ -1119,7 +1119,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_ if (ntree == NULL) return NULL; /* is ntree part of library? */ - if (bmain && BLI_findindex(&bmain->nodetree, ntree) >= 0) { + if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { newtree = BKE_libblock_copy(&ntree->id); } else { @@ -1211,7 +1211,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_ bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user) { - return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true); + return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); } bNodeTree *ntreeCopyTree(bNodeTree *ntree) { @@ -1418,7 +1418,7 @@ static void node_preview_sync(bNodePreview *to, bNodePreview *from) if (to->rect && from->rect) { int xsize = to->xsize; int ysize = to->ysize; - memcpy(to->rect, from->rect, 4 * xsize + xsize * ysize * sizeof(char) * 4); + memcpy(to->rect, from->rect, xsize * ysize * sizeof(char) * 4); } } @@ -1733,7 +1733,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) /* unregister associated RNA types */ ntreeInterfaceTypeFree(ntree); - BKE_free_animdata((ID *)ntree); + BKE_animdata_free((ID *)ntree); id_us_min((ID *)ntree->gpd); @@ -1980,7 +1980,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) /* Make full copy. * Note: previews are not copied here. */ - ltree = ntreeCopyTree_internal(ntree, NULL, false, false, false); + ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false); ltree->flag |= NTREE_IS_LOCALIZED; for (node = ltree->nodes.first; node; node = node->next) { @@ -3082,10 +3082,14 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id) bNodeSocket *sock; Material *ma = (Material *)node->id; int a; + short check_flags = SOCK_UNAVAIL; + + if (!copy_to_id) + check_flags |= SOCK_HIDDEN; /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */ for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) { - if (!nodeSocketIsHidden(sock)) { + if (!(sock->flag & check_flags)) { if (copy_to_id) { switch (a) { case MAT_IN_COLOR: @@ -3475,6 +3479,7 @@ static void registerCompositNodes(void) register_node_type_cmp_bokehimage(); register_node_type_cmp_bokehblur(); register_node_type_cmp_switch(); + register_node_type_cmp_switch_view(); register_node_type_cmp_pixelate(); register_node_type_cmp_mask(); @@ -3568,6 +3573,7 @@ static void registerShaderNodes(void) register_node_type_sh_tex_magic(); register_node_type_sh_tex_checker(); register_node_type_sh_tex_brick(); + register_node_type_sh_tex_pointdensity(); } static void registerTextureNodes(void) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index b3bc9f222e9..04bdfe3b58e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -38,6 +38,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_cache_library_types.h" #include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_group_types.h" @@ -76,6 +77,7 @@ #include "BKE_armature.h" #include "BKE_action.h" #include "BKE_bullet.h" +#include "BKE_cache_library.h" #include "BKE_deform.h" #include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" @@ -97,6 +99,7 @@ #include "BKE_editmesh.h" #include "BKE_mball.h" #include "BKE_modifier.h" +#include "BKE_multires.h" #include "BKE_node.h" #include "BKE_object.h" #include "BKE_object_deform.h" @@ -108,6 +111,7 @@ #include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_smoke.h" #include "BKE_speaker.h" #include "BKE_softbody.h" #include "BKE_subsurf.h" @@ -236,7 +240,7 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) { - ModifierTypeInfo *mti; + const ModifierTypeInfo *mti; mti = modifierType_getInfo(modifier_type); @@ -249,7 +253,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) return true; } -void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; BKE_object_free_modifiers(ob_dst); @@ -265,8 +269,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) if (ELEM(md->type, eModifierType_Hook, - eModifierType_Softbody, - eModifierType_ParticleInstance, eModifierType_Collision)) { continue; @@ -274,21 +276,31 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) continue; - - if (md->type == eModifierType_Skin) { - /* ensure skin-node customdata exists */ - BKE_mesh_ensure_skin_customdata(ob_dst->data); + + switch (md->type) { + case eModifierType_Softbody: + BKE_object_copy_softbody(ob_dst, ob_src); + break; + case eModifierType_Skin: + /* ensure skin-node customdata exists */ + BKE_mesh_ensure_skin_customdata(ob_dst->data); + break; } nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); + + if (md->type == eModifierType_Multires) { + /* Has to be done after mod creation, but *before* we actually copy its settings! */ + multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); + } + modifier_copyData(md, nmd); BLI_addtail(&ob_dst->modifiers, nmd); modifier_unique_name(&ob_dst->modifiers, nmd); } BKE_object_copy_particlesystems(ob_dst, ob_src); - BKE_object_copy_softbody(ob_dst, ob_src); /* TODO: smoke?, cloth? */ } @@ -318,9 +330,12 @@ void BKE_object_free_derived_caches(Object *ob) } if (ob->derivedFinal) { - ob->derivedFinal->needsFree = 1; - ob->derivedFinal->release(ob->derivedFinal); - ob->derivedFinal = NULL; + /* dupli cache owns the derivedFinal, is freed by duplicator object */ + if (!(ob->transflag & OB_IS_DUPLI_CACHE)) { + ob->derivedFinal->needsFree = 1; + ob->derivedFinal->release(ob->derivedFinal); + ob->derivedFinal = NULL; + } } if (ob->derivedDeform) { ob->derivedDeform->needsFree = 1; @@ -329,9 +344,11 @@ void BKE_object_free_derived_caches(Object *ob) } BKE_object_free_curve_cache(ob); + + BKE_object_dupli_cache_clear(ob); } -void BKE_object_free_caches(Object *object) +void BKE_object_free_caches(Object *object, bool free_smoke_sim) { ModifierData *md; short update_flag = 0; @@ -344,7 +361,7 @@ void BKE_object_free_caches(Object *object) psys = psys->next) { psys_free_path_cache(psys, psys->edit); - update_flag |= PSYS_RECALC; + update_flag |= PSYS_RECALC_REDO; } } @@ -356,9 +373,32 @@ void BKE_object_free_caches(Object *object) psmd->dm->needsFree = 1; psmd->dm->release(psmd->dm); psmd->dm = NULL; + psmd->flag |= eParticleSystemFlag_file_loaded; update_flag |= OB_RECALC_DATA; } } + else if (md->type == eModifierType_Smoke) { + if (free_smoke_sim) { + SmokeModifierData *smd = (SmokeModifierData *) md; + SmokeDomainSettings *sds = smd->domain; + if (sds != NULL) { + bool use_sim = sds->point_cache[0] == NULL; + PointCache *cache; + /* We only reset cache if all the point caches are baked to file. */ + for (cache = sds->ptcaches[0].first; + cache != NULL && use_sim == false; + cache = cache->next) + { + use_sim |= ((cache->flag & (PTCACHE_BAKED|PTCACHE_DISK_CACHE)) != (PTCACHE_BAKED|PTCACHE_DISK_CACHE)); + } + if (!use_sim) { + smokeModifier_reset(smd); + smokeModifier_reset_turbulence(smd); + update_flag |= OB_RECALC_DATA; + } + } + } + } } /* Tag object for update, so once memory critical operation is over and @@ -410,7 +450,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) ob->iuser = NULL; if (ob->bb) MEM_freeN(ob->bb); ob->bb = NULL; - if (ob->adt) BKE_free_animdata((ID *)ob); + if (ob->adt) BKE_animdata_free((ID *)ob); if (ob->poselib) ob->poselib->id.us--; if (ob->gpd) ((ID *)ob->gpd)->us--; if (ob->defbase.first) @@ -438,7 +478,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) if (ob->bsoft) bsbFree(ob->bsoft); if (ob->gpulamp.first) GPU_lamp_free(ob); - BKE_free_sculptsession(ob); + BKE_sculptsession_free(ob); if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids); @@ -451,6 +491,8 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) free_path(ob->curve_cache->path); MEM_freeN(ob->curve_cache); } + + BKE_object_dupli_cache_free(ob); } void BKE_object_free(Object *ob) @@ -469,6 +511,15 @@ static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Objec } } +static void unlink_object__unlinkCacheModifierLinks(void *userData, CacheLibrary *UNUSED(cachelib), CacheModifier *UNUSED(md), ID **idpoin) +{ + Object *unlinkOb = userData; + + if (*idpoin == (ID *)unlinkOb) { + *idpoin = NULL; + } +} + void BKE_object_unlink(Object *ob) { Main *bmain = G.main; @@ -490,6 +541,7 @@ void BKE_object_unlink(Object *ob) ARegion *ar; RegionView3D *rv3d; LodLevel *lod; + CacheLibrary *cachelib; int a, found; unlink_controllers(&ob->controllers); @@ -535,7 +587,7 @@ void BKE_object_unlink(Object *ob) bPoseChannel *pchan; for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -566,7 +618,7 @@ void BKE_object_unlink(Object *ob) sca_remove_ob_poin(obt, ob); for (con = obt->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -677,6 +729,10 @@ void BKE_object_unlink(Object *ob) lod->source = NULL; } + /* dupli cache is cleared entirely if the object in question is duplified to keep it simple */ + if (BKE_object_dupli_cache_contains(obt, ob)) + BKE_object_dupli_cache_clear(obt); + obt = obt->id.next; } @@ -812,34 +868,11 @@ void BKE_object_unlink(Object *ob) } } } - else if (sl->spacetype == SPACE_OUTLINER) { - SpaceOops *so = (SpaceOops *)sl; - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == (ID *)ob) tselem->id = NULL; - } - } - } - else if (sl->spacetype == SPACE_BUTS) { - SpaceButs *sbuts = (SpaceButs *)sl; - - if (sbuts->pinid == (ID *)ob) { - sbuts->flag &= ~SB_PIN_CONTEXT; - sbuts->pinid = NULL; - } - } - else if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - - if (snode->from == (ID *)ob) { - snode->flag &= ~SNODE_PIN; - snode->from = NULL; - } +#if 0 + else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) { + /* now handled by WM_main_remove_editor_id_reference */ } +#endif } sa = sa->next; @@ -862,6 +895,15 @@ void BKE_object_unlink(Object *ob) } camera = camera->id.next; } + + /* cache libraries */ + for (cachelib = bmain->cache_library.first; cachelib; cachelib = cachelib->id.next) { + CacheModifier *md; + + for (md = cachelib->modifiers.first; md; md = md->next) { + BKE_cache_modifier_foreachIDLink(cachelib, md, unlink_object__unlinkCacheModifierLinks, ob); + } + } } /* actual check for internal data, not context or flags */ @@ -942,26 +984,6 @@ bool BKE_object_exists_check(Object *obtest) /* *************************************************** */ -void *BKE_object_obdata_add_from_type(Main *bmain, int type) -{ - switch (type) { - case OB_MESH: return BKE_mesh_add(bmain, "Mesh"); - case OB_CURVE: return BKE_curve_add(bmain, "Curve", OB_CURVE); - case OB_SURF: return BKE_curve_add(bmain, "Surf", OB_SURF); - case OB_FONT: return BKE_curve_add(bmain, "Text", OB_FONT); - case OB_MBALL: return BKE_mball_add(bmain, "Meta"); - case OB_CAMERA: return BKE_camera_add(bmain, "Camera"); - case OB_LAMP: return BKE_lamp_add(bmain, "Lamp"); - case OB_LATTICE: return BKE_lattice_add(bmain, "Lattice"); - case OB_ARMATURE: return BKE_armature_add(bmain, "Armature"); - case OB_SPEAKER: return BKE_speaker_add(bmain, "Speaker"); - case OB_EMPTY: return NULL; - default: - printf("BKE_object_obdata_add_from_type: Internal error, bad type: %d\n", type); - return NULL; - } -} - static const char *get_obdata_defname(int type) { switch (type) { @@ -982,6 +1004,30 @@ static const char *get_obdata_defname(int type) } } +void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) +{ + if (name == NULL) { + name = get_obdata_defname(type); + } + + switch (type) { + case OB_MESH: return BKE_mesh_add(bmain, name); + case OB_CURVE: return BKE_curve_add(bmain, name, OB_CURVE); + case OB_SURF: return BKE_curve_add(bmain, name, OB_SURF); + case OB_FONT: return BKE_curve_add(bmain, name, OB_FONT); + case OB_MBALL: return BKE_mball_add(bmain, name); + case OB_CAMERA: return BKE_camera_add(bmain, name); + case OB_LAMP: return BKE_lamp_add(bmain, name); + case OB_LATTICE: return BKE_lattice_add(bmain, name); + case OB_ARMATURE: return BKE_armature_add(bmain, name); + case OB_SPEAKER: return BKE_speaker_add(bmain, name); + case OB_EMPTY: return NULL; + default: + printf("%s: Internal error, bad type: %d\n", __func__, type); + return NULL; + } +} + /* more general add: creates minimum required data, but without vertices etc. */ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) { @@ -1052,7 +1098,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob->jump_speed = 10.0f; ob->fall_speed = 55.0f; ob->col_group = 0x01; - ob->col_mask = 0xff; + ob->col_mask = 0xffff; /* NT fluid sim defaults */ ob->fluidsimSettings = NULL; @@ -1067,16 +1113,16 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) /* general add: to scene, with layer from area and default name */ /* creates minimum required data, but without vertices etc. */ -Object *BKE_object_add(Main *bmain, Scene *scene, int type) +Object *BKE_object_add( + Main *bmain, Scene *scene, + int type, const char *name) { Object *ob; Base *base; - char name[MAX_ID_NAME]; - BLI_strncpy(name, get_obdata_defname(type), sizeof(name)); ob = BKE_object_add_only_object(bmain, type, name); - ob->data = BKE_object_obdata_add_from_type(bmain, type); + ob->data = BKE_object_obdata_add_from_type(bmain, type, name); ob->lay = scene->lay; @@ -1102,10 +1148,12 @@ void BKE_object_lod_add(Object *ob) BLI_addtail(&ob->lodlevels, base); base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT; base->source = ob; + base->obhysteresis = 10; last = ob->currentlod = base; } lod->distance = last->distance + 25.0f; + lod->obhysteresis = 10; lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT; BLI_addtail(&ob->lodlevels, lod); @@ -1221,7 +1269,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) #endif /* WITH_GAMEENGINE */ -SoftBody *copy_softbody(SoftBody *sb, bool copy_caches) +SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) { SoftBody *sbn; @@ -1323,6 +1371,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) psysn->pathcache = NULL; psysn->childcache = NULL; psysn->edit = NULL; + psysn->hairedit = NULL; psysn->pdd = NULL; psysn->effectors = NULL; psysn->tree = NULL; @@ -1334,36 +1383,30 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false); - /* XXX - from reading existing code this seems correct but intended usage of - * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */ - if (psysn->clmd) { - psysn->clmd->point_cache = psysn->pointcache; - } - id_us_plus((ID *)psysn->part); id_us_plus((ID *)psysn->key); return psysn; } -void BKE_object_copy_particlesystems(Object *obn, Object *ob) +void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) { ParticleSystem *psys, *npsys; ModifierData *md; - if (obn->type != OB_MESH) { + if (ob_dst->type != OB_MESH) { /* currently only mesh objects can have soft body */ return; } - BLI_listbase_clear(&obn->particlesystem); - for (psys = ob->particlesystem.first; psys; psys = psys->next) { + BLI_listbase_clear(&ob_dst->particlesystem); + for (psys = ob_src->particlesystem.first; psys; psys = psys->next) { npsys = BKE_object_copy_particlesystem(psys); - BLI_addtail(&obn->particlesystem, npsys); + BLI_addtail(&ob_dst->particlesystem, npsys); /* need to update particle modifiers too */ - for (md = obn->modifiers.first; md; md = md->next) { + for (md = ob_dst->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; if (psmd->psys == psys) @@ -1391,10 +1434,12 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob) } } -void BKE_object_copy_softbody(Object *obn, Object *ob) +void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src) { - if (ob->soft) - obn->soft = copy_softbody(ob->soft, false); + if (ob_src->soft) { + ob_dst->softflag = ob_src->softflag; + ob_dst->soft = copy_softbody(ob_src->soft, false); + } } static void copy_object_pose(Object *obn, Object *ob) @@ -1411,7 +1456,7 @@ static void copy_object_pose(Object *obn, Object *ob) chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE); for (con = chan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1533,6 +1578,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) id_us_plus((ID *)obn->data); id_us_plus((ID *)obn->gpd); id_lib_extern((ID *)obn->dup_group); + id_lib_extern((ID *)obn->cache_library); for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); @@ -1564,6 +1610,8 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) /* Copy runtime surve data. */ obn->curve_cache = NULL; + obn->dup_cache = NULL; + if (ob->id.lib) { BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id); } @@ -1595,6 +1643,7 @@ static void extern_local_object(Object *ob) id_lib_extern((ID *)ob->data); id_lib_extern((ID *)ob->dup_group); + id_lib_extern((ID *)ob->cache_library); id_lib_extern((ID *)ob->poselib); id_lib_extern((ID *)ob->gpd); @@ -1713,7 +1762,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* add new animdata block */ if (!ob->adt) - ob->adt = BKE_id_add_animdata(&ob->id); + ob->adt = BKE_animdata_add_id(&ob->id); /* make a copy of all the drivers (for now), then correct any links that need fixing */ free_fcurves(&ob->adt->drivers); @@ -1775,8 +1824,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat); if (gob->dup_group) { /* should always be true */ float tvec[3]; - copy_v3_v3(tvec, gob->dup_group->dupli_ofs); - mul_mat3_m4_v3(ob->obmat, tvec); + mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs); sub_v3_v3(ob->obmat[3], tvec); } BKE_object_apply_mat4(ob, ob->obmat, false, true); @@ -2071,14 +2119,12 @@ void BKE_object_to_mat4(Object *ob, float mat[4][4]) add_v3_v3v3(mat[3], ob->loc, ob->dloc); } -static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]); - void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]) { if (ob->parent) { float par_imat[4][4]; - ob_get_parent_matrix(NULL, ob, ob->parent, par_imat); + BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat); invert_m4(par_imat); mul_m4_m4m4(mat, par_imat, ob->obmat); } @@ -2098,7 +2144,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) unit_m4(mat); cu = par->data; - if (ELEM(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */ + if (par->curve_cache == NULL) /* only happens on reload file, but violates depsgraph still... fix! */ BKE_displist_make_curveTypes(scene, par, 0); if (par->curve_cache->path == NULL) return; @@ -2133,7 +2179,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) } /* vec: 4 items! */ - if (where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat : NULL, &radius, NULL)) { + if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) { if (cu->flag & CU_FOLLOW) { #if 0 @@ -2227,7 +2273,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) md != NULL; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); /* TODO(sergey): Check for disabled modifiers. */ if (mti->type != eModifierTypeType_OnlyDeform && md->next != NULL) { use_special_ss_case = false; @@ -2370,7 +2416,8 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4]) } } -static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]) + +void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]) { float tmat[4][4]; float vec[3]; @@ -2427,7 +2474,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4 if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat); - ob_get_parent_matrix(scene, ob, par, totmat); + BKE_object_get_parent_matrix(scene, ob, par, totmat); /* total */ mul_m4_m4m4(tmat, totmat, ob->parentinv); @@ -2585,7 +2632,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c if (use_parent && ob->parent) { float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4]; - ob_get_parent_matrix(NULL, ob, ob->parent, parent_mat); + BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat); mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv); invert_m4_m4(imat, diff_mat); @@ -2854,7 +2901,15 @@ bool BKE_object_minmax_dupli(Scene *scene, Object *ob, float r_min[3], float r_m /* pass */ } else { - BoundBox *bb = BKE_object_boundbox_get(dob->ob); + BoundBox *bb = NULL; + if (ob->dup_cache) { + DupliObjectData *dob_data = BKE_dupli_cache_find_data(ob->dup_cache, dob->ob); + if (dob_data && dob_data->dm) { + bb = &dob_data->bb; + } + } + if (!bb) + bb = BKE_object_boundbox_get(dob->ob); if (bb) { int i; @@ -3021,8 +3076,12 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, { if (ob->recalc & OB_RECALC_ALL) { /* speed optimization for animation lookups */ - if (ob->pose) + if (ob->pose) { BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + } if (ob->recalc & OB_RECALC_DATA) { if (ob->type == OB_ARMATURE) { @@ -3048,8 +3107,9 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); if (ob->proxy_from->proxy_group) { /* transform proxy into group space */ Object *obg = ob->proxy_from->proxy_group; - invert_m4_m4(obg->imat, obg->obmat); - mul_m4_m4m4(ob->obmat, obg->imat, ob->proxy_from->obmat); + float imat[4][4]; + invert_m4_m4(imat, obg->obmat); + mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat); if (obg->dup_group) { /* should always be true */ add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs); } @@ -3062,153 +3122,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, } if (ob->recalc & OB_RECALC_DATA) { - ID *data_id = (ID *)ob->data; - AnimData *adt = BKE_animdata_from_id(data_id); - Key *key; - ParticleSystem *psys; - - if (G.debug & G_DEBUG_DEPSGRAPH) - printf("recalcdata %s\n", ob->id.name + 2); - - if (adt) { - /* evaluate drivers - datalevel */ - /* XXX: for mesh types, should we push this to derivedmesh instead? */ - BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); - } - - key = BKE_key_from_object(ob); - if (key && key->block.first) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) - BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); - } - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - key = psys->key; - if (key && key->block.first) { - BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); - } - } - - /* includes all keys and modifiers */ - switch (ob->type) { - case OB_MESH: - { - BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; - uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; -#ifdef WITH_FREESTYLE - /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */ - if (eval_ctx->mode != DAG_EVAL_VIEWPORT) { - data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; - } -#endif - if (em) { - makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */ - } - else { - makeDerivedMesh(scene, ob, NULL, data_mask, 0); - } - break; - } - case OB_ARMATURE: - if (ob->id.lib && ob->proxy_from) { - if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { - printf("Proxy copy error, lib Object: %s proxy Object: %s\n", - ob->id.name + 2, ob->proxy_from->id.name + 2); - } - } - else { - BKE_pose_where_is(scene, ob); - } - break; - - case OB_MBALL: - BKE_displist_make_mball(eval_ctx, scene, ob); - break; - - case OB_CURVE: - case OB_SURF: - case OB_FONT: - BKE_displist_make_curveTypes(scene, ob, 0); - break; - - case OB_LATTICE: - BKE_lattice_modifiers_calc(scene, ob); - break; - - case OB_EMPTY: - if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) - if (BKE_image_is_animated(ob->data)) - BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0); - break; - } - - /* related materials */ - /* XXX: without depsgraph tagging, this will always need to be run, which will be slow! - * However, not doing anything (or trying to hack around this lack) is not an option - * anymore, especially due to Cycles [#31834] - */ - if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - - if (ma) { - /* recursively update drivers for this material */ - material_drivers_update(scene, ma, ctime); - } - } - } - else if (ob->type == OB_LAMP) - lamp_drivers_update(scene, ob->data, ctime); - - /* particles */ - if (ob != scene->obedit && ob->particlesystem.first) { - ParticleSystem *tpsys, *psys; - DerivedMesh *dm; - ob->transflag &= ~OB_DUPLIPARTS; - - psys = ob->particlesystem.first; - while (psys) { - /* ensure this update always happens even if psys is disabled */ - if (psys->recalc & PSYS_RECALC_TYPE) { - psys_changed_type(ob, psys); - } - - if (psys_check_enabled(ob, psys)) { - /* check use of dupli objects here */ - if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && - ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || - (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) - { - ob->transflag |= OB_DUPLIPARTS; - } - - particle_system_update(scene, ob, psys); - psys = psys->next; - } - else if (psys->flag & PSYS_DELETE) { - tpsys = psys->next; - BLI_remlink(&ob->particlesystem, psys); - psys_free(ob, psys); - psys = tpsys; - } - else - psys = psys->next; - } - - if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) { - /* this is to make sure we get render level duplis in groups: - * the derivedmesh must be created before init_render_mesh, - * since object_duplilist does dupliparticles before that */ - dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); - dm->release(dm); - - for (psys = ob->particlesystem.first; psys; psys = psys->next) - psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; - } - } - - /* quick cache removed */ + BKE_object_handle_data_update(eval_ctx, scene, ob); } ob->recalc &= ~OB_RECALC_ALL; @@ -3253,7 +3167,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) ss->pbvh = NULL; } - BKE_free_sculptsession_deformMats(ob->sculpt); + BKE_sculptsession_free_deformMats(ob->sculpt); } else { PBVHNode **nodes; @@ -3516,7 +3430,7 @@ static KeyBlock *insert_curvekey(Object *ob, const char *name, const bool from_m return kb; } -KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool from_mix) +KeyBlock *BKE_object_shapekey_insert(Object *ob, const char *name, const bool from_mix) { switch (ob->type) { case OB_MESH: @@ -3532,6 +3446,85 @@ KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool f } +bool BKE_object_shapekey_free(Main *bmain, Object *ob) +{ + Key **key_p, *key; + + key_p = BKE_key_from_object_p(ob); + if (ELEM(NULL, key_p, *key_p)) { + return false; + } + + key = *key_p; + *key_p = NULL; + + BKE_libblock_free_us(bmain, key); + + return false; +} + +bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb) +{ + KeyBlock *rkb; + Key *key = BKE_key_from_object(ob); + short kb_index; + + if (key == NULL) { + return false; + } + + kb_index = BLI_findindex(&key->block, kb); + BLI_assert(kb_index != -1); + + for (rkb = key->block.first; rkb; rkb = rkb->next) { + if (rkb->relative == kb_index) { + /* remap to the 'Basis' */ + rkb->relative = 0; + } + else if (rkb->relative >= kb_index) { + /* Fix positional shift of the keys when kb is deleted from the list */ + rkb->relative -= 1; + } + } + + BLI_remlink(&key->block, kb); + key->totkey--; + if (key->refkey == kb) { + key->refkey = key->block.first; + + if (key->refkey) { + /* apply new basis key on original data */ + switch (ob->type) { + case OB_MESH: + BKE_keyblock_convert_to_mesh(key->refkey, ob->data); + break; + case OB_CURVE: + case OB_SURF: + BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data)); + break; + case OB_LATTICE: + BKE_keyblock_convert_to_lattice(key->refkey, ob->data); + break; + } + } + } + + if (kb->data) { + MEM_freeN(kb->data); + } + MEM_freeN(kb); + + if (ob->shapenr > 1) { + ob->shapenr--; + } + + if (key->totkey == 0) { + BKE_object_shapekey_free(bmain, ob); + } + + return true; +} + bool BKE_object_flag_test_recursive(const Object *ob, short flag) { if (ob->flag & flag) { @@ -3683,7 +3676,7 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob) md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); bool can_deform = mti->type == eModifierTypeType_OnlyDeform || is_modifier_animated; @@ -3740,7 +3733,7 @@ void BKE_object_relink(Object *ob) modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL); if (ob->adt) - BKE_relink_animdata(ob->adt); + BKE_animdata_relink(ob->adt); if (ob->rigidbody_constraint) BKE_rigidbody_relink_constraint(ob->rigidbody_constraint); @@ -4053,3 +4046,51 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot) *r_tot = tot; return tree; } + +bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) +{ + if (modifier_dependsOnTime(md)) { + return true; + } + + /* Check whether modifier is animated. */ + /* TODO: this should be handled as part of build_animdata() -- Aligorith */ + if (ob->adt) { + AnimData *adt = ob->adt; + FCurve *fcu; + + char pattern[MAX_NAME + 10]; + /* TODO(sergey): Escape modifier name. */ + BLI_snprintf(pattern, sizeof(pattern), "modifiers[%s", md->name); + + /* action - check for F-Curves with paths containing 'modifiers[' */ + if (adt->action) { + for (fcu = (FCurve *)adt->action->curves.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + /* This here allows modifier properties to get driven and still update properly + * + * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven) + * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused + * by the RNA updates cache introduced in r.38649 + */ + for (fcu = (FCurve *)adt->drivers.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + + /* XXX: also, should check NLA strips, though for now assume that nobody uses + * that and we can omit that for performance reasons... */ + } + + return false; +} diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index e46929dde4a..f6e939a103e 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -163,7 +163,7 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id) /** * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes. * - * \param allverts If true, remove all vertices, else only selected ones. + * \param use_selection: Only operate on selection. * \return True if any vertex was removed, false otherwise. */ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection) @@ -241,7 +241,7 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele /** * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes. * - * \param allverts If true, remove all vertices, else only selected ones. + * \param use_selection: Only operate on selection. * \return True if any vertex was removed, false otherwise. */ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection) diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index c77f65f69e1..fd0d0daf7e4 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -35,11 +35,16 @@ #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_math.h" #include "BLI_rand.h" +#include "BLI_task.h" #include "DNA_anim_types.h" #include "DNA_group_types.h" @@ -48,6 +53,7 @@ #include "DNA_vfont_types.h" #include "BKE_animsys.h" +#include "BKE_cache_library.h" #include "BKE_DerivedMesh.h" #include "BKE_depsgraph.h" #include "BKE_font.h" @@ -56,15 +62,18 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_sample.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" #include "BKE_editmesh.h" #include "BKE_anim.h" - +#include "BKE_strands.h" #include "BLI_strict_flags.h" +#include "BLF_translation.h" + /* Dupli-Geometry */ typedef struct DupliContext { @@ -96,7 +105,7 @@ typedef struct DupliGenerator { static const DupliGenerator *get_dupli_generator(const DupliContext *ctx); /* create initial context for root object */ -static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, float space_mat[4][4], bool update) +static void init_context_ex(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, float space_mat[4][4], const DupliGenerator *gen, bool update) { r_ctx->eval_ctx = eval_ctx; r_ctx->scene = scene; @@ -110,14 +119,19 @@ static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene copy_m4_m4(r_ctx->space_mat, space_mat); else unit_m4(r_ctx->space_mat); - r_ctx->lay = ob->lay; + r_ctx->lay = ob ? ob->lay : 0; r_ctx->level = 0; - r_ctx->gen = get_dupli_generator(r_ctx); + r_ctx->gen = gen ? gen : get_dupli_generator(r_ctx); r_ctx->duplilist = NULL; } +static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update) +{ + init_context_ex(r_ctx, eval_ctx, scene, ob, NULL, NULL, update); +} + /* create sub-context for recursive duplis */ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated) { @@ -126,7 +140,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj r_ctx->animated |= animated; /* object animation makes all children animated */ /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */ - if (ctx->gen->type == OB_DUPLIGROUP) + if (ctx->gen->type == OB_DUPLIGROUP && ctx->object) r_ctx->group = ctx->object->dup_group; r_ctx->object = ob; @@ -219,7 +233,10 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild { Object *parent = ctx->object; Object *obedit = ctx->scene->obedit; - + + if (!parent) + return; + if (ctx->group) { unsigned int lay = ctx->group->layer; GroupObject *go; @@ -255,69 +272,84 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild /*---- Implementations ----*/ -/* OB_DUPLIGROUP */ -static void make_duplis_group(const DupliContext *ctx) +/* Intern function for creating instances of group content + * with or without a parent (parent == NULL is allowed!) + * Note: some of the group animation update functions use the parent object, + * but this is old NLA code that is currently disabled and might be removed entirely. + */ +static void make_duplis_group_intern(const DupliContext *ctx, Group *group, Object *parent) { - bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER); - Object *ob = ctx->object; - Group *group; + const bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER); + GroupObject *go; float group_mat[4][4]; int id; - bool animated, hide; - - if (ob->dup_group == NULL) return; - group = ob->dup_group; - - /* combine group offset and obmat */ + bool animated; + unit_m4(group_mat); sub_v3_v3(group_mat[3], group->dupli_ofs); - mul_m4_m4m4(group_mat, ob->obmat, group_mat); - /* don't access 'ob->obmat' from now on. */ - + + if (parent) { + /* combine group offset and obmat */ + mul_m4_m4m4(group_mat, parent->obmat, group_mat); + /* don't access 'parent->obmat' from now on. */ + } + /* handles animated groups */ - + /* we need to check update for objects that are not in scene... */ if (ctx->do_update) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ - BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, ob, group); + BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, parent, group); } - - animated = BKE_group_is_animated(group, ob); - + + animated = BKE_group_is_animated(group, parent); + for (go = group->gobject.first, id = 0; go; go = go->next, id++) { + float mat[4][4]; + bool hide; + /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ - if (go->ob != ob) { - float mat[4][4]; - - /* Special case for instancing dupli-groups, see: T40051 - * this object may be instanced via dupli-verts/faces, in this case we don't want to render - * (blender convention), but _do_ show in the viewport. - * - * Regular objects work fine but not if we're instancing dupli-groups, - * because the rules for rendering aren't applied to objects they instance. - * We could recursively pass down the 'hide' flag instead, but that seems unnecessary. - */ - if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) { - continue; - } - - /* group dupli offset, should apply after everything else */ - mul_m4_m4m4(mat, group_mat, go->ob->obmat); - - /* check the group instance and object layers match, also that the object visible flags are ok. */ - hide = (go->ob->lay & group->layer) == 0 || - (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW); - - make_dupli(ctx, go->ob, mat, id, animated, hide); - - /* recursion */ - make_recursive_duplis(ctx, go->ob, group_mat, id, animated); + if (go->ob == parent) + continue; + + /* Special case for instancing dupli-groups, see: T40051 + * this object may be instanced via dupli-verts/faces, in this case we don't want to render + * (blender convention), but _do_ show in the viewport. + * + * Regular objects work fine but not if we're instancing dupli-groups, + * because the rules for rendering aren't applied to objects they instance. + * We could recursively pass down the 'hide' flag instead, but that seems unnecessary. + */ + if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) { + continue; } + + /* group dupli offset, should apply after everything else */ + mul_m4_m4m4(mat, group_mat, go->ob->obmat); + + /* check the group instance and object layers match, also that the object visible flags are ok. */ + hide = (go->ob->lay & group->layer) == 0 || + (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW); + + make_dupli(ctx, go->ob, mat, id, animated, hide); + + /* recursion */ + make_recursive_duplis(ctx, go->ob, group_mat, id, animated); } } +/* OB_DUPLIGROUP */ +static void make_duplis_group(const DupliContext *ctx) +{ + Object *ob = ctx->object; + if (!ob || !ob->dup_group) + return; + + make_duplis_group_intern(ctx, ob->dup_group, ob); +} + const DupliGenerator gen_dupli_group = { OB_DUPLIGROUP, /* type */ make_duplis_group /* make_duplis */ @@ -331,8 +363,9 @@ static void make_duplis_frames(const DupliContext *ctx) extern int enable_cu_speed; /* object.c */ Object copyob; int cfrao = scene->r.cfra; - int dupend = ob->dupend; + if (!ob) + return; /* dupliframes not supported inside groups */ if (ctx->group) return; @@ -341,7 +374,7 @@ static void make_duplis_frames(const DupliContext *ctx) */ if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL) return; - + /* make a copy of the object's original data (before any dupli-data overwrites it) * as we'll need this to keep track of unkeyed data * - this doesn't take into account other data that can be reached from the object, @@ -356,7 +389,7 @@ static void make_duplis_frames(const DupliContext *ctx) * updates, as this is not a permanent change to the object */ ob->id.flag |= LIB_ANIM_NO_RECALC; - for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) { + for (scene->r.cfra = ob->dupsta; scene->r.cfra <= ob->dupend; scene->r.cfra++) { int ok = 1; /* - dupoff = how often a frames within the range shouldn't be made into duplis @@ -512,6 +545,9 @@ static void make_duplis_verts(const DupliContext *ctx) Object *parent = ctx->object; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); VertexDupliData vdd; + + if (!parent) + return; vdd.ctx = ctx; vdd.use_rotation = parent->transflag & OB_DUPLIROT; @@ -592,6 +628,8 @@ static void make_duplis_font(const DupliContext *ctx) const wchar_t *text = NULL; bool text_free = false; + if (!par) + return; /* font dupliverts not supported inside groups */ if (ctx->group) return; @@ -779,6 +817,9 @@ static void make_duplis_faces(const DupliContext *ctx) bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); FaceDupliData fdd; + if (!parent) + return; + fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0); /* gather mesh info */ @@ -842,7 +883,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem int no_draw_flag = PARS_UNEXIST; - if (psys == NULL) return; + if (!psys) + return; part = psys->part; @@ -983,7 +1025,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) - b = BLI_rand() % totgroup; + b = (int)(psys_frand(psys, (unsigned int)(a + 974)) * (float)totgroup) % totgroup; else b = a % totgroup; @@ -1123,6 +1165,9 @@ static void make_duplis_particles(const DupliContext *ctx) ParticleSystem *psys; int psysid; + if (!ctx->object) + return; + /* particle system take up one level in id, the particles another */ for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) { /* particles create one more level for persistent psys index */ @@ -1142,8 +1187,13 @@ const DupliGenerator gen_dupli_particles = { /* select dupli generator from given context */ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) { - int transflag = ctx->object->transflag; - int restrictflag = ctx->object->restrictflag; + int transflag, restrictflag; + + if (!ctx->object) + return NULL; + + transflag = ctx->object->transflag; + restrictflag = ctx->object->restrictflag; if ((transflag & OB_DUPLI) == 0) return NULL; @@ -1183,15 +1233,36 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) /* Returns a list of DupliObject */ ListBase *object_duplilist_ex(EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update) { - ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist"); - DupliContext ctx; - init_context(&ctx, eval_ctx, scene, ob, NULL, update); - if (ctx.gen) { - ctx.duplilist = duplilist; - ctx.gen->make_duplis(&ctx); + if (update) { + BKE_object_dupli_cache_update(scene, ob, eval_ctx, (float)scene->r.cfra + scene->r.subframe); + } + + if (ob->dup_cache && (ob->dup_cache->result != CACHE_READ_SAMPLE_INVALID)) { + /* Note: duplis in the cache don't have the main duplicator obmat applied. + * duplilist also should return a full copy of duplis, so we copy + * the cached list and apply the obmat to each. + */ + ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist"); + DupliObject *dob; + + BLI_duplicatelist(duplilist, &ob->dup_cache->duplilist); + + for (dob = duplilist->first; dob; dob = dob->next) { + mul_m4_m4m4(dob->mat, ob->obmat, dob->mat); + } + + return duplilist; + } + else { + ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist"); + DupliContext ctx; + init_context(&ctx, eval_ctx, scene, ob, update); + if (ctx.gen) { + ctx.duplilist = duplilist; + ctx.gen->make_duplis(&ctx); + } + return duplilist; } - - return duplilist; } /* note: previously updating was always done, this is why it defaults to be on @@ -1201,6 +1272,24 @@ ListBase *object_duplilist(EvaluationContext *eval_ctx, Scene *sce, Object *ob) return object_duplilist_ex(eval_ctx, sce, ob, true); } +ListBase *group_duplilist_ex(EvaluationContext *eval_ctx, Scene *scene, Group *group, bool update) +{ + ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist"); + DupliContext ctx; + + init_context_ex(&ctx, eval_ctx, scene, NULL, NULL, &gen_dupli_group, update); + ctx.duplilist = duplilist; + + make_duplis_group_intern(&ctx, group, NULL); + + return duplilist; +} + +ListBase *group_duplilist(EvaluationContext *eval_ctx, Scene *scene, Group *group) +{ + return group_duplilist_ex(eval_ctx, scene, group, true); +} + void free_object_duplilist(ListBase *lb) { BLI_freelistN(lb); @@ -1237,7 +1326,559 @@ int count_duplilist(Object *ob) return 1; } -DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist) +/* ------------------------------------------------------------------------- */ + +static void dupli_cache_calc_boundbox(DupliObjectData *data) +{ + DupliObjectDataStrands *link; + float min[3], max[3]; + bool has_data = false; + + INIT_MINMAX(min, max); + if (data->dm) { + data->dm->getMinMax(data->dm, min, max); + has_data = true; + } + for (link = data->strands.first; link; link = link->next) { + if (link->strands) { + BKE_strands_get_minmax(link->strands, min, max, true); + has_data = true; + } + if (link->strands_children) { + BKE_strands_children_get_minmax(link->strands_children, min, max); + has_data = true; + } + } + + if (!has_data) { + zero_v3(min); + zero_v3(max); + } + + BKE_boundbox_init_from_minmax(&data->bb, min, max); +} + +static bool UNUSED_FUNCTION(dupli_object_data_strands_unique_name)(ListBase *lb, DupliObjectDataStrands *link) +{ + if (lb && link) { + return BLI_uniquename(lb, link, DATA_("Strands"), '.', offsetof(DupliObjectDataStrands, name), sizeof(link->name)); + } + return false; +} + +void BKE_dupli_object_data_init(DupliObjectData *data, Object *ob) +{ + data->ob = ob; + + data->dm = NULL; + BLI_listbase_clear(&data->strands); + + memset(&data->bb, 0, sizeof(data->bb)); + dupli_cache_calc_boundbox(data); +} + +void BKE_dupli_object_data_clear(DupliObjectData *data) +{ + DupliObjectDataStrands *link; + + if (data->dm) { + /* we lock DMs in the cache to prevent freeing outside, + * now allow releasing again + */ + data->dm->needsFree = true; + data->dm->release(data->dm); + } + + for (link = data->strands.first; link; link = link->next) { + if (link->strands) + BKE_strands_free(link->strands); + if (link->strands_children) + BKE_strands_children_free(link->strands_children); + } + BLI_freelistN(&data->strands); +} + +void BKE_dupli_object_data_set_mesh(DupliObjectData *data, DerivedMesh *dm) +{ + if (data->dm) { + /* we lock DMs in the cache to prevent freeing outside, + * now allow releasing again + */ + data->dm->needsFree = true; + data->dm->release(data->dm); + } + + data->dm = dm; + /* we own this dm now and need to protect it until we free it ourselves */ + dm->needsFree = false; + + dupli_cache_calc_boundbox(data); +} + +void BKE_dupli_object_data_add_strands(DupliObjectData *data, const char *name, Strands *strands) +{ + DupliObjectDataStrands *link = NULL; + for (link = data->strands.first; link; link = link->next) { + if (STREQ(link->name, name)) + break; + } + + if (!link) { + link = MEM_callocN(sizeof(DupliObjectDataStrands), "strands link"); + BLI_strncpy(link->name, name, sizeof(link->name)); + link->strands = strands; + + BLI_addtail(&data->strands, link); + } + else { + if (link->strands && link->strands != strands) + BKE_strands_free(link->strands); + link->strands = strands; + } + + dupli_cache_calc_boundbox(data); +} + +void BKE_dupli_object_data_add_strands_children(DupliObjectData *data, const char *name, StrandsChildren *children) +{ + DupliObjectDataStrands *link = NULL; + for (link = data->strands.first; link; link = link->next) { + if (STREQ(link->name, name)) + break; + } + + if (!link) { + link = MEM_callocN(sizeof(DupliObjectDataStrands), "strands link"); + BLI_strncpy(link->name, name, sizeof(link->name)); + link->strands_children = children; + + BLI_addtail(&data->strands, link); + } + else { + if (link->strands_children && link->strands_children != children) + BKE_strands_children_free(link->strands_children); + link->strands_children = children; + } + + dupli_cache_calc_boundbox(data); +} + +void BKE_dupli_object_data_find_strands(DupliObjectData *data, const char *name, Strands **r_strands, StrandsChildren **r_children) +{ + DupliObjectDataStrands *link; + for (link = data->strands.first; link; link = link->next) { + if (STREQ(link->name, name)) { + if (r_strands) *r_strands = link->strands; + if (r_children) *r_children = link->strands_children; + return; + } + } + + if (r_strands) *r_strands = NULL; + if (r_children) *r_children = NULL; +} + +bool BKE_dupli_object_data_acquire_strands(DupliObjectData *data, Strands *strands) +{ + DupliObjectDataStrands *link, *link_next; + bool found = false; + + if (!data || !strands) + return false; + + for (link = data->strands.first; link; link = link_next) { + link_next = link->next; + if (link->strands == strands) { + link->strands = NULL; + found = true; + } + } + return found; +} + +bool BKE_dupli_object_data_acquire_strands_children(DupliObjectData *data, StrandsChildren *children) +{ + DupliObjectDataStrands *link, *link_next; + bool found = false; + + if (!data || !children) + return false; + + for (link = data->strands.first; link; link = link_next) { + link_next = link->next; + if (link->strands_children == children) { + link->strands_children = NULL; + found = true; + } + } + return found; +} + +/* ------------------------------------------------------------------------- */ + +static void dupli_object_data_free(DupliObjectData *data) +{ + BKE_dupli_object_data_clear(data); + MEM_freeN(data); +} + +static void dupli_object_free(DupliObject *dob) +{ + MEM_freeN(dob); +} + +DupliCache *BKE_dupli_cache_new(void) +{ + DupliCache *dupcache = MEM_callocN(sizeof(DupliCache), "dupli object cache"); + + dupcache->ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "dupli object data hash"); + + return dupcache; +} + +void BKE_dupli_cache_free(DupliCache *dupcache) +{ + BKE_dupli_cache_clear(dupcache); + + BLI_ghash_free(dupcache->ghash, NULL, (GHashValFreeFP)dupli_object_data_free); + MEM_freeN(dupcache); +} + +void BKE_dupli_cache_clear(DupliCache *dupcache) +{ + DupliObject *dob, *dob_next; + for (dob = dupcache->duplilist.first; dob; dob = dob_next) { + dob_next = dob->next; + + dupli_object_free(dob); + } + BLI_listbase_clear(&dupcache->duplilist); + + BLI_ghash_clear(dupcache->ghash, NULL, (GHashValFreeFP)dupli_object_data_free); +} + +void BKE_dupli_cache_clear_instances(DupliCache *dupcache) +{ + DupliObject *dob, *dob_next; + for (dob = dupcache->duplilist.first; dob; dob = dob_next) { + dob_next = dob->next; + + dupli_object_free(dob); + } + BLI_listbase_clear(&dupcache->duplilist); +} + +static DupliObjectData *dupli_cache_add_object_data(DupliCache *dupcache, Object *ob) +{ + DupliObjectData *data = MEM_callocN(sizeof(DupliObjectData), "dupli object data"); + + data->ob = ob; + BLI_ghash_insert(dupcache->ghash, data->ob, data); + return data; +} + +static DupliObject *dupli_cache_add_object(DupliCache *dupcache) +{ + DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupli object"); + + unit_m4(dob->mat); + + BLI_addtail(&dupcache->duplilist, dob); + return dob; +} + +static int count_hair_verts(ParticleSystem *psys) +{ + int numverts = 0; + int p; + for (p = 0; p < psys->totpart; ++p) { + numverts += psys->particles[p].totkey; + } + return numverts; +} + +static void dupli_strands_data_update(CacheLibrary *cachelib, DupliObjectData *data, + DupliObject *dob, bool calc_strands_base) { + ParticleSystem *psys; + for (psys = dob->ob->particlesystem.first; psys; psys = psys->next) { + if (cachelib->data_types & CACHE_TYPE_HAIR) { + if (psys->part && psys->part->type == PART_HAIR) { + int numstrands = psys->totpart; + int numverts = count_hair_verts(psys); + ParticleData *pa; + HairKey *hkey; + int p, k; + + Strands *strands = BKE_strands_new(numstrands, numverts); + StrandsCurve *scurve = strands->curves; + StrandsVertex *svert = strands->verts; + + for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) { + float hairmat[4][4]; + psys_mat_hair_to_object(dob->ob, data->dm, psys->part->from, pa, hairmat); + + scurve->numverts = pa->totkey; + copy_m3_m4(scurve->root_matrix, hairmat); + BKE_mesh_sample_from_particle(&scurve->msurf, psys, data->dm, pa); + + for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) { + copy_v3_v3(svert->co, hkey->co); + if (calc_strands_base) + copy_v3_v3(svert->base, hkey->co); + svert->time = hkey->time; + svert->weight = hkey->weight; + ++svert; + } + ++scurve; + } + + BKE_dupli_object_data_add_strands(data, psys->name, strands); + } + } + } +} + +typedef struct DupliObjectDataFromGroupState { + EvaluationContext *eval_ctx; + Scene *scene; + CacheLibrary *cachelib; + bool calc_strands_base; +} DupliObjectDataFromGroupState; + +typedef struct DupliObjectDataFromGroupTask { + DupliObject *dob; + DupliObjectData *data; +} DupliObjectDataFromGroupTask; + +static void dupli_object_data_from_group_func(TaskPool *pool, void *taskdata, int UNUSED(threadid)) +{ + DupliObjectDataFromGroupState *state = (DupliObjectDataFromGroupState *)BLI_task_pool_userdata(pool); + DupliObjectDataFromGroupTask *task = (DupliObjectDataFromGroupTask *)taskdata; + Object *object = task->dob->ob; + DerivedMesh *dm; + + if (state->eval_ctx->mode == DAG_EVAL_RENDER) { + dm = mesh_create_derived_render(state->scene, object, CD_MASK_BAREMESH); + } + else { + dm = mesh_create_derived_view(state->scene, object, CD_MASK_BAREMESH); + } + + if (dm != NULL) { + BKE_dupli_object_data_set_mesh(task->data, dm); + } + + dupli_strands_data_update(state->cachelib, task->data, task->dob, state->calc_strands_base); +} + +void BKE_dupli_cache_from_group(Scene *scene, Group *group, CacheLibrary *cachelib, DupliCache *dupcache, EvaluationContext *eval_ctx, bool calc_strands_base) +{ + DupliObject *dob; + TaskScheduler *task_scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + DupliObjectDataFromGroupState state; + + BKE_dupli_cache_clear(dupcache); + + if (!(group && cachelib)) + return; + + { + /* copy duplilist to the cache */ + ListBase *duplilist = group_duplilist(eval_ctx, scene, group); + dupcache->duplilist = *duplilist; + MEM_freeN(duplilist); + } + + state.eval_ctx = eval_ctx; + state.scene = scene; + state.cachelib = cachelib; + state.calc_strands_base = calc_strands_base; + task_pool = BLI_task_pool_create(task_scheduler, &state); + + /* tag objects for which to store data */ + BKE_cache_library_tag_used_objects(cachelib); + + for (dob = dupcache->duplilist.first; dob; dob = dob->next) { + DupliObjectData *data = BKE_dupli_cache_find_data(dupcache, dob->ob); + if (!data) { + bool strands_handled = false; + data = dupli_cache_add_object_data(dupcache, dob->ob); + + /* generate data only for filtered objects */ + if (dob->ob->id.flag & LIB_DOIT) { + if (cachelib->data_types & CACHE_TYPE_DERIVED_MESH) { + if (dob->ob->type == OB_MESH) { + /* TODO(sergey): Consider using memory pool instead. */ + DupliObjectDataFromGroupTask *task = MEM_mallocN(sizeof(DupliObjectDataFromGroupTask), + "dupcache task"); + task->dob = dob; + task->data = data; + BLI_task_pool_push(task_pool, dupli_object_data_from_group_func, task, true, TASK_PRIORITY_LOW); + /* Task is getting care of strands as well. */ + strands_handled = true; + } + } + if (!strands_handled) { + dupli_strands_data_update(cachelib, data, dob, calc_strands_base); + } + } + } + } + + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); +} + +/* ------------------------------------------------------------------------- */ + +void BKE_object_dupli_cache_update(Scene *scene, Object *ob, EvaluationContext *eval_ctx, float frame) +{ + bool use_render = (eval_ctx->mode == DAG_EVAL_RENDER); + bool is_dupligroup = (ob->transflag & OB_DUPLIGROUP) && ob->dup_group; + bool is_cached = ob->cache_library && (ob->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE || ob->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_RESULT); + bool do_modifiers = ob->cache_library && ob->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_MODIFIERS; + + /* cache is a group duplicator feature only */ + if (is_dupligroup && is_cached) { + + if (ob->dup_cache && !(ob->dup_cache->flag & DUPCACHE_FLAG_DIRTY)) { + /* skip if cache is valid */ + } + else { + if (G.debug & G_DEBUG) + printf("Update dupli cache for object '%s'\n", ob->id.name+2); + + if (ob->dup_cache) { + BKE_dupli_cache_clear(ob->dup_cache); + } + else { + ob->dup_cache = BKE_dupli_cache_new(); + } + + /* skip reading when the cachelib is baking, avoids unnecessary memory allocation */ + if (!(ob->cache_library->flag & CACHE_LIBRARY_BAKING)) { + bool do_strands_motion, do_strands_children; + CacheLibrary *cachelib = ob->cache_library; + CacheProcessData process_data; + + BKE_cache_library_get_read_flags(ob->cache_library, use_render, true, &do_strands_motion, &do_strands_children); + + /* TODO at this point we could apply animation offset */ + BKE_cache_read_dupli_cache(ob->cache_library, ob->dup_cache, scene, ob->dup_group, frame, use_render, true); + + process_data.lay = ob->lay; + copy_m4_m4(process_data.mat, ob->obmat); + process_data.dupcache = ob->dup_cache; + + BKE_cache_process_dupli_cache(cachelib, &process_data, scene, ob->dup_group, (float)scene->r.cfra, frame, do_modifiers, do_strands_children, do_strands_motion); + } + + ob->dup_cache->flag &= ~DUPCACHE_FLAG_DIRTY; + ob->dup_cache->cfra = frame; + } + + } + else { + if (ob->dup_cache) { + BKE_dupli_cache_free(ob->dup_cache); + ob->dup_cache = NULL; + } + } +} + +void BKE_object_dupli_cache_clear(Object *ob) +{ + if (ob->dup_cache) { + BKE_dupli_cache_clear(ob->dup_cache); + } +} + +void BKE_object_dupli_cache_free(Object *ob) +{ + if (ob->dup_cache) { + BKE_dupli_cache_free(ob->dup_cache); + ob->dup_cache = NULL; + } +} + +bool BKE_object_dupli_cache_contains(Object *ob, Object *other) +{ + if (ob->dup_cache) { + DupliObject *dob; + for (dob = ob->dup_cache->duplilist.first; dob; dob = dob->next) { + if (dob->ob == other) + return true; + } + } + return false; +} + + +DupliObjectData *BKE_dupli_cache_find_data(DupliCache *dupcache, Object *ob) +{ + DupliObjectData *data = BLI_ghash_lookup(dupcache->ghash, ob); + return data; +} + +DupliObjectData *BKE_dupli_cache_add_object(DupliCache *dupcache, Object *ob) +{ + DupliObjectData *data = BKE_dupli_cache_find_data(dupcache, ob); + if (!data) { + data = dupli_cache_add_object_data(dupcache, ob); + } + return data; +} + +DupliObject *BKE_dupli_cache_add_instance(DupliCache *dupcache, float obmat[4][4], DupliObjectData *data) +{ + DupliObject *dob = dupli_cache_add_object(dupcache); + + /* data must have been created correctly */ + BLI_assert(BLI_ghash_lookup(dupcache->ghash, data->ob) != NULL); + + dob->ob = data->ob; + copy_m4_m4(dob->mat, obmat); + + dob->data = data; + + return dob; +} + +/* ------------------------------------------------------------------------- */ + +typedef struct DupliCacheIterator { + int unused; +} DupliCacheIterator; + +DupliCacheIterator *BKE_dupli_cache_iter_new(struct DupliCache *dupcache) +{ + return (DupliCacheIterator *)BLI_ghashIterator_new(dupcache->ghash); +} + +void BKE_dupli_cache_iter_free(DupliCacheIterator *iter) +{ + BLI_ghashIterator_free((GHashIterator *)iter); +} + +bool BKE_dupli_cache_iter_valid(DupliCacheIterator *iter) +{ + return !BLI_ghashIterator_done((GHashIterator *)iter); +} + +void BKE_dupli_cache_iter_next(DupliCacheIterator *iter) +{ + BLI_ghashIterator_step((GHashIterator *)iter); +} + +DupliObjectData *BKE_dupli_cache_iter_get(DupliCacheIterator *iter) +{ + return BLI_ghashIterator_getValue((GHashIterator *)iter); +} + +/* ------------------------------------------------------------------------- */ + +DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist) { DupliApplyData *apply_data = NULL; int num_objects = BLI_listbase_count(duplilist); @@ -1253,6 +1894,13 @@ DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist) for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) { /* copy obmat from duplis */ copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat); + + /* make sure derivedmesh is calculated once, before drawing */ + if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) { + mesh_get_derived_final(scene, dob->ob, scene->customdata_mask); + dob->ob->transflag |= OB_DUPLICALCDERIVED; + } + copy_m4_m4(dob->ob->obmat, dob->mat); /* copy layers from the main duplicator object */ @@ -1273,6 +1921,7 @@ void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data) */ for (dob = duplilist->last, i = apply_data->num_objects - 1; dob; dob = dob->prev, --i) { copy_m4_m4(dob->ob->obmat, apply_data->extra[i].obmat); + dob->ob->transflag &= ~OB_DUPLICALCDERIVED; dob->ob->lay = apply_data->extra[i].lay; } diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c new file mode 100644 index 00000000000..6752beb6d3b --- /dev/null +++ b/source/blender/blenkernel/intern/object_update.c @@ -0,0 +1,355 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 20014 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/object_update.c + * \ingroup bke + */ + +#include "DNA_anim_types.h" +#include "DNA_constraint_types.h" +#include "DNA_group_types.h" +#include "DNA_key_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_threads.h" + +#include "BKE_global.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_constraint.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_animsys.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_key.h" +#include "BKE_lamp.h" +#include "BKE_lattice.h" +#include "BKE_editmesh.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_scene.h" +#include "BKE_material.h" +#include "BKE_image.h" + +#include "DEG_depsgraph.h" + +#ifdef WITH_LEGACY_DEPSGRAPH +# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf +#else +# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf +#endif + +static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER; + +void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx), + Scene *UNUSED(scene), + Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* calculate local matrix */ + BKE_object_to_mat4(ob, ob->obmat); +} + +/* Evaluate parent */ +/* NOTE: based on solve_parenting(), but with the cruft stripped out */ +void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) +{ + Object *par = ob->parent; + + float totmat[4][4]; + float tmat[4][4]; + float locmat[4][4]; + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* get local matrix (but don't calculate it, as that was done already!) */ + // XXX: redundant? + copy_m4_m4(locmat, ob->obmat); + + /* get parent effect matrix */ + BKE_object_get_parent_matrix(scene, ob, par, totmat); + + /* total */ + mul_m4_m4m4(tmat, totmat, ob->parentinv); + mul_m4_m4m4(ob->obmat, tmat, locmat); + + /* origin, for help line */ + if ((ob->partype & PARTYPE) == PARSKEL) { + copy_v3_v3(ob->orig, par->obmat[3]); + } + else { + copy_v3_v3(ob->orig, totmat[3]); + } +} + +void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) +{ + bConstraintOb *cob; + float ctime = BKE_scene_frame_get(scene); + + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* evaluate constraints stack */ + /* TODO: split this into: + * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e. + * - inner body of BKE_constraints_solve), + * - post (i.e. BKE_constraints_clear_evalob) + * + * Not sure why, this is from Joshua - sergey + * + */ + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_constraints_solve(&ob->constraints, cob, ctime); + BKE_constraints_clear_evalob(cob); +} + +void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + + /* Set negative scale flag in object. */ + if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; + else ob->transflag &= ~OB_NEG_SCALE; +} + +void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx, + struct Scene *scene, + struct Object *ob, + struct ModifierData *md) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + (void) eval_ctx; /* Ignored. */ + (void) scene; /* Ignored. */ + (void) ob; /* Ignored. */ + (void) md; /* Ignored. */ +} + +void BKE_object_handle_data_update(EvaluationContext *eval_ctx, + Scene *scene, + Object *ob) +{ + ID *data_id = (ID *)ob->data; + AnimData *adt = BKE_animdata_from_id(data_id); + Key *key; + ParticleSystem *psys; + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) + printf("recalcdata %s\n", ob->id.name + 2); + + /* TODO(sergey): Only used by legacy depsgraph. */ + if (adt) { + /* evaluate drivers - datalevel */ + /* XXX: for mesh types, should we push this to derivedmesh instead? */ + BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); + } + + /* TODO(sergey): Only used by legacy depsgraph. */ + key = BKE_key_from_object(ob); + if (key && key->block.first) { + if (!(ob->shapeflag & OB_SHAPE_LOCK)) + BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); + } + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + key = psys->key; + if (key && key->block.first) { + BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); + } + } + + /* includes all keys and modifiers */ + switch (ob->type) { + case OB_MESH: + { + BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; + uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; +#ifdef WITH_FREESTYLE + /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */ + if (eval_ctx->mode != DAG_EVAL_VIEWPORT) { + data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; + } +#endif + if (em) { + makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */ + } + else { + makeDerivedMesh(scene, ob, NULL, data_mask, 0); + } + break; + } + case OB_ARMATURE: + if (ob->id.lib && ob->proxy_from) { + if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { + printf("Proxy copy error, lib Object: %s proxy Object: %s\n", + ob->id.name + 2, ob->proxy_from->id.name + 2); + } + } + else { + BKE_pose_where_is(scene, ob); + } + break; + + case OB_MBALL: + BKE_displist_make_mball(eval_ctx, scene, ob); + break; + + case OB_CURVE: + case OB_SURF: + case OB_FONT: + BKE_displist_make_curveTypes(scene, ob, 0); + break; + + case OB_LATTICE: + BKE_lattice_modifiers_calc(scene, ob); + break; + + case OB_EMPTY: + if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) + if (BKE_image_is_animated(ob->data)) + BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0); + break; + } + + /* related materials */ + /* XXX: without depsgraph tagging, this will always need to be run, which will be slow! + * However, not doing anything (or trying to hack around this lack) is not an option + * anymore, especially due to Cycles [#31834] + */ + if (ob->totcol) { + int a; + if (ob->totcol != 0) { + BLI_mutex_lock(&material_lock); + for (a = 1; a <= ob->totcol; a++) { + Material *ma = give_current_material(ob, a); + if (ma) { + /* recursively update drivers for this material */ + material_drivers_update(scene, ma, ctime); + } + } + BLI_mutex_unlock(&material_lock); + } + } + else if (ob->type == OB_LAMP) + lamp_drivers_update(scene, ob->data, ctime); + + /* particles */ + if (ob != scene->obedit && ob->particlesystem.first) { + ParticleSystem *tpsys, *psys; + DerivedMesh *dm; + ob->transflag &= ~OB_DUPLIPARTS; + psys = ob->particlesystem.first; + while (psys) { + /* ensure this update always happens even if psys is disabled */ + if (psys->recalc & PSYS_RECALC_TYPE) { + psys_changed_type(ob, psys); + } + + if (psys_check_enabled(ob, psys)) { + /* check use of dupli objects here */ + if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && + ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || + (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) + { + ob->transflag |= OB_DUPLIPARTS; + } + + particle_system_update(scene, ob, psys); + psys = psys->next; + } + else if (psys->flag & PSYS_DELETE) { + tpsys = psys->next; + BLI_remlink(&ob->particlesystem, psys); + psys_free(ob, psys); + psys = tpsys; + } + else + psys = psys->next; + } + + if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) { + /* this is to make sure we get render level duplis in groups: + * the derivedmesh must be created before init_render_mesh, + * since object_duplilist does dupliparticles before that */ + dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + dm->release(dm); + + for (psys = ob->particlesystem.first; psys; psys = psys->next) + psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; + } + } + + /* quick cache removed */ +} + +void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx), + Scene *UNUSED(scene), + Object *ob) +{ + /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */ + // XXX: it's almost redundant now... + + /* Handle proxy copy for target, */ + if (ob->id.lib && ob->proxy_from) { + if (ob->proxy_from->proxy_group) { + /* Transform proxy into group space. */ + Object *obg = ob->proxy_from->proxy_group; + float imat[4][4]; + invert_m4_m4(imat, obg->obmat); + mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat); + /* Should always be true. */ + if (obg->dup_group) { + add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs); + } + } + else + copy_m4_m4(ob->obmat, ob->proxy_from->obmat); + } + + ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME); + if (ob->data == NULL) { + ob->recalc &= ~OB_RECALC_DATA; + } +} + +void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, + Scene *scene, + Object *ob) +{ + DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + BLI_assert(ob->type != OB_ARMATURE); + BKE_object_handle_data_update(eval_ctx, scene, ob); + + ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); +} diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 12e82d3a34f..1a178fb2bdf 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -494,7 +494,7 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j) BLI_rw_mutex_unlock(&oc->oceanmutex); } -void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount) +void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount) { int i, j; @@ -732,14 +732,14 @@ static void set_height_normalize_factor(struct Ocean *oc) oc->normalize_factor = 1.0; - BKE_simulate_ocean(oc, 0.0, 1.0, 0); + BKE_ocean_simulate(oc, 0.0, 1.0, 0); BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); for (i = 0; i < oc->_M; ++i) { for (j = 0; j < oc->_N; ++j) { - if (max_h < fabsf(oc->_disp_y[i * oc->_N + j])) { - max_h = fabsf(oc->_disp_y[i * oc->_N + j]); + if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) { + max_h = fabs(oc->_disp_y[i * oc->_N + j]); } } } @@ -754,7 +754,7 @@ static void set_height_normalize_factor(struct Ocean *oc) oc->normalize_factor = res; } -struct Ocean *BKE_add_ocean(void) +struct Ocean *BKE_ocean_add(void) { Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data"); @@ -763,7 +763,7 @@ struct Ocean *BKE_add_ocean(void) return oc; } -void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, +void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) { @@ -900,7 +900,7 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, BLI_rng_free(rng); } -void BKE_free_ocean_data(struct Ocean *oc) +void BKE_ocean_free_data(struct Ocean *oc) { if (!oc) return; @@ -962,11 +962,11 @@ void BKE_free_ocean_data(struct Ocean *oc) BLI_rw_mutex_unlock(&oc->oceanmutex); } -void BKE_free_ocean(struct Ocean *oc) +void BKE_ocean_free(struct Ocean *oc) { if (!oc) return; - BKE_free_ocean_data(oc); + BKE_ocean_free_data(oc); BLI_rw_mutex_end(&oc->oceanmutex); MEM_freeN(oc); @@ -1002,7 +1002,7 @@ static void cache_filename(char *string, const char *path, const char *relbase, BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname); - BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true); + BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, ""); } /* silly functions but useful to inline when the args do a lot of indirections */ @@ -1021,7 +1021,7 @@ MINLINE void value_to_rgba_unit_alpha(float r_rgba[4], const float value) r_rgba[3] = 1.0f; } -void BKE_free_ocean_cache(struct OceanCache *och) +void BKE_ocean_free_cache(struct OceanCache *och) { int i, f = 0; @@ -1111,7 +1111,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in } } -struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale, +struct OceanCache *BKE_ocean_init_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale, float chop_amount, float foam_coverage, float foam_fade, int resolution) { OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); @@ -1138,7 +1138,7 @@ struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbas return och; } -void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) +void BKE_ocean_simulate_cache(struct OceanCache *och, int frame) { char string[FILE_MAX]; int f = frame; @@ -1182,7 +1182,7 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) } -void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), +void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data) { /* note: some of these values remain uninitialized unless certain options @@ -1221,7 +1221,7 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); - BKE_simulate_ocean(o, och->time[i], och->wave_scale, och->chop_amount); + BKE_ocean_simulate(o, och->time[i], och->wave_scale, och->chop_amount); /* add new foam */ for (y = 0; y < res_y; y++) { @@ -1371,29 +1371,29 @@ void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr) { } -void BKE_simulate_ocean(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount)) +void BKE_ocean_simulate(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount)) { } -struct Ocean *BKE_add_ocean(void) +struct Ocean *BKE_ocean_add(void) { Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data"); return oc; } -void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), +void BKE_ocean_init(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) { } -void BKE_free_ocean_data(struct Ocean *UNUSED(oc)) +void BKE_ocean_free_data(struct Ocean *UNUSED(oc)) { } -void BKE_free_ocean(struct Ocean *oc) +void BKE_ocean_free(struct Ocean *oc) { if (!oc) return; MEM_freeN(oc); @@ -1403,7 +1403,7 @@ void BKE_free_ocean(struct Ocean *oc) /* ********* Baking/Caching ********* */ -void BKE_free_ocean_cache(struct OceanCache *och) +void BKE_ocean_free_cache(struct OceanCache *och) { if (!och) return; @@ -1420,7 +1420,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult { } -OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start), +OceanCache *BKE_ocean_init_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start), int UNUSED(end), float UNUSED(wave_scale), float UNUSED(chop_amount), float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) { @@ -1429,11 +1429,11 @@ OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSE return och; } -void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame)) +void BKE_ocean_simulate_cache(struct OceanCache *UNUSED(och), int UNUSED(frame)) { } -void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), +void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) { /* unused */ diff --git a/source/blender/blenkernel/intern/treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index 866502c4ae1..f31ba34a984 100644 --- a/source/blender/blenkernel/intern/treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -20,7 +20,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file treehash.c +/** \file outliner_treehash.c * \ingroup bke * * Tree hash for the outliner space. @@ -28,7 +28,7 @@ #include <stdlib.h> -#include "BKE_treehash.h" +#include "BKE_outliner_treehash.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -38,8 +38,7 @@ #include "MEM_guardedalloc.h" -typedef struct TseGroup -{ +typedef struct TseGroup { TreeStoreElem **elems; int size; int allocated; @@ -103,12 +102,15 @@ static void fill_treehash(void *treehash, BLI_mempool *treestore) TreeStoreElem *tselem; BLI_mempool_iter iter; BLI_mempool_iternew(treestore, &iter); + + BLI_assert(treehash); + while ((tselem = BLI_mempool_iterstep(&iter))) { - BKE_treehash_add_element(treehash, tselem); + BKE_outliner_treehash_add_element(treehash, tselem); } } -void *BKE_treehash_create_from_treestore(BLI_mempool *treestore) +void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore) { GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore)); fill_treehash(treehash, treestore); @@ -120,35 +122,46 @@ static void free_treehash_group(void *key) tse_group_free(key); } -void *BKE_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) +void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) { + BLI_assert(treehash); + BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore)); fill_treehash(treehash, treestore); return treehash; } -void BKE_treehash_add_element(void *treehash, TreeStoreElem *elem) +void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem) { - TseGroup *group = BLI_ghash_lookup(treehash, elem); - if (!group) { - group = tse_group_create(); - BLI_ghash_insert(treehash, elem, group); + TseGroup *group; + void **val_p; + + if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) { + *val_p = tse_group_create(); } + group = *val_p; tse_group_add(group, elem); } -static TseGroup *BKE_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) +static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) { TreeStoreElem tse_template; tse_template.type = type; tse_template.nr = type ? nr : 0; // we're picky! :) tse_template.id = id; + + BLI_assert(th); + return BLI_ghash_lookup(th, &tse_template); } -TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id) +TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id) { - TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id); + TseGroup *group; + + BLI_assert(treehash); + + group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); if (group) { int i; for (i = 0; i < group->size; i++) { @@ -160,13 +173,19 @@ TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, return NULL; } -TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id) +TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id) { - TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id); + TseGroup *group; + + BLI_assert(treehash); + + group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); return group ? group->elems[0] : NULL; } -void BKE_treehash_free(void *treehash) +void BKE_outliner_treehash_free(void *treehash) { + BLI_assert(treehash); + BLI_ghash_free(treehash, NULL, free_treehash_group); } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 8d56b1247fe..800df252c69 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -128,8 +128,8 @@ int countPackedFiles(Main *bmain) /* let's check if there are packed files... */ for (ima = bmain->image.first; ima; ima = ima->id.next) - if (ima->packedfile) - count++; + if (BKE_image_has_packedfile(ima)) + count ++; for (vf = bmain->vfont.first; vf; vf = vf->id.next) if (vf->packedfile) @@ -224,7 +224,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char } /* no libraries for now */ -void packAll(Main *bmain, ReportList *reports) +void packAll(Main *bmain, ReportList *reports, bool verbose) { Image *ima; VFont *vfont; @@ -232,12 +232,12 @@ void packAll(Main *bmain, ReportList *reports) int tot = 0; for (ima = bmain->image.first; ima; ima = ima->id.next) { - if (ima->packedfile == NULL && ima->id.lib == NULL) { + if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) { if (ima->source == IMA_SRC_FILE) { - ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id)); + BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id)); tot ++; } - else if (BKE_image_is_animated(ima)) { + else if (BKE_image_is_animated(ima) && verbose) { BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported", ima->id.name + 2); } @@ -258,10 +258,10 @@ void packAll(Main *bmain, ReportList *reports) } } - if (tot == 0) - BKE_report(reports, RPT_INFO, "No new files have been packed"); - else + if (tot > 0) BKE_reportf(reports, RPT_INFO, "Packed %d files", tot); + else if (verbose) + BKE_report(reports, RPT_INFO, "No new files have been packed"); } @@ -478,7 +478,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na } static void unpack_generate_paths( - const char *name, ID *id, char *abspath_r, char *relpath_r, size_t abspathlen, size_t relpathlen) + const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen) { char tempname[FILE_MAX]; char tempdir[FILE_MAXDIR]; @@ -500,19 +500,19 @@ static void unpack_generate_paths( switch (GS(id->name)) { case ID_VF: - BLI_snprintf(relpath_r, relpathlen, "//fonts/%s", tempname); + BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname); break; case ID_SO: - BLI_snprintf(relpath_r, relpathlen, "//sounds/%s", tempname); + BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname); break; case ID_IM: - BLI_snprintf(relpath_r, relpathlen, "//textures/%s", tempname); + BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname); break; } { - size_t len = BLI_strncpy_rlen(abspath_r, tempdir, abspathlen); - BLI_strncpy(abspath_r + len, tempname, abspathlen - len); + size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen); + BLI_strncpy(r_abspath + len, tempname, abspathlen - len); } } @@ -553,7 +553,7 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) freePackedFile(sound->packedfile); sound->packedfile = NULL; - sound_load(bmain, sound); + BKE_sound_load(bmain, sound); ret_value = RET_OK; } @@ -564,23 +564,47 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) int unpackImage(ReportList *reports, Image *ima, int how) { - char localname[FILE_MAX], absname[FILE_MAX]; - char *newname; int ret_value = RET_ERROR; - + if (ima != NULL && ima->name[0]) { - unpack_generate_paths(ima->name, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile(reports, absname, localname, ima->packedfile, how); - if (newname != NULL) { - ret_value = RET_OK; - freePackedFile(ima->packedfile); - ima->packedfile = NULL; - BLI_strncpy(ima->name, newname, sizeof(ima->name)); - MEM_freeN(newname); - BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + while (ima->packedfiles.last) { + char localname[FILE_MAX], absname[FILE_MAX]; + char *newname; + ImagePackedFile *imapf = ima->packedfiles.last; + + unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname)); + newname = unpackFile(reports, absname, localname, imapf->packedfile, how); + + if (newname != NULL) { + ImageView *iv; + + ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK; + freePackedFile(imapf->packedfile); + imapf->packedfile = NULL; + + /* update the new corresponding view filepath */ + iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath)); + if (iv) { + BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath)); + } + + /* keep the new name in the image for non-pack specific reasons */ + BLI_strncpy(ima->name, newname, sizeof(imapf->filepath)); + MEM_freeN(newname); + } + else { + ret_value = RET_ERROR; + } + + BLI_remlink(&ima->packedfiles, imapf); + MEM_freeN(imapf); } } - + + if (ret_value == RET_OK) { + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + } + return(ret_value); } @@ -636,7 +660,7 @@ void unpackAll(Main *bmain, ReportList *reports, int how) bSound *sound; for (ima = bmain->image.first; ima; ima = ima->id.next) - if (ima->packedfile) + if (BKE_image_has_packedfile(ima)) unpackImage(reports, ima, how); for (vf = bmain->vfont.first; vf; vf = vf->id.next) @@ -655,7 +679,7 @@ bool BKE_pack_check(ID *id) case ID_IM: { Image *ima = (Image *)id; - return ima->packedfile != NULL; + return BKE_image_has_packedfile(ima); } case ID_VF: { @@ -683,7 +707,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how) case ID_IM: { Image *ima = (Image *)id; - if (ima->packedfile) { + if (BKE_image_has_packedfile(ima)) { unpackImage(reports, ima, how); } break; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 431eec0d220..0bda740af53 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -313,25 +313,33 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc) } } +void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_index) +{ + pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0; +} + /* remove colour from palette. Must be certain color is inside the palette! */ void BKE_palette_color_remove(Palette *palette, PaletteColor *color) { - if (color) { - int numcolors = BLI_listbase_count(&palette->colors); - if ((numcolors == palette->active_color + 1) && (numcolors != 1)) - palette->active_color--; - - BLI_remlink(&palette->colors, color); - BLI_addhead(&palette->deleted, color); + if (BLI_listbase_count_ex(&palette->colors, palette->active_color) == palette->active_color) { + palette->active_color--; } + + BLI_remlink(&palette->colors, color); + + if (palette->active_color < 0 && !BLI_listbase_is_empty(&palette->colors)) { + palette->active_color = 0; + } + + MEM_freeN(color); } -void BKE_palette_cleanup(Palette *palette) +void BKE_palette_clear(Palette *palette) { - BLI_freelistN(&palette->deleted); + BLI_freelistN(&palette->colors); + palette->active_color = 0; } - Palette *BKE_palette_add(Main *bmain, const char *name) { Palette *palette; @@ -353,7 +361,6 @@ PaletteColor *BKE_palette_color_add(Palette *palette) { PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color"); BLI_addtail(&palette->colors, color); - palette->active_color = BLI_listbase_count(&palette->colors) - 1; return color; } @@ -512,7 +519,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, /* threshold to move before updating the brush rotation */ #define RAKE_THRESHHOLD 20 -static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation) +void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation) { if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ups->brush_rotation = rotation; @@ -520,7 +527,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, ups->brush_rotation = 0.0f; if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE) - /* here, translation contains the mouse coordinates. */ ups->brush_rotation_sec = rotation; else ups->brush_rotation_sec = 0.0f; @@ -529,7 +535,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) { if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { - const float u = 0.5f; const float r = RAKE_THRESHHOLD; float rotation; @@ -539,17 +544,16 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons if (len_squared_v2(dpos) >= r * r) { rotation = atan2f(dpos[0], dpos[1]); - interp_v2_v2v2(ups->last_rake, ups->last_rake, - mouse_pos, u); + copy_v2_v2(ups->last_rake, mouse_pos); ups->last_rake_angle = rotation; - update_brush_rake_rotation(ups, brush, rotation); + paint_update_brush_rake_rotation(ups, brush, rotation); } /* make sure we reset here to the last rotation to avoid accumulating * values in case a random rotation is also added */ else { - update_brush_rake_rotation(ups, brush, ups->last_rake_angle); + paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle); } } else { @@ -557,15 +561,11 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons } } -void BKE_free_sculptsession_deformMats(SculptSession *ss) +void BKE_sculptsession_free_deformMats(SculptSession *ss) { - if (ss->orig_cos) MEM_freeN(ss->orig_cos); - if (ss->deform_cos) MEM_freeN(ss->deform_cos); - if (ss->deform_imats) MEM_freeN(ss->deform_imats); - - ss->orig_cos = NULL; - ss->deform_cos = NULL; - ss->deform_imats = NULL; + MEM_SAFE_FREE(ss->orig_cos); + MEM_SAFE_FREE(ss->deform_cos); + MEM_SAFE_FREE(ss->deform_imats); } /* Write out the sculpt dynamic-topology BMesh to the Mesh */ @@ -624,7 +624,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object) } } -void BKE_free_sculptsession(Object *ob) +void BKE_sculptsession_free(Object *ob) { if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; @@ -718,7 +718,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) /* exception for shape keys because we can edit those */ for (; md; md = md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) continue; @@ -765,7 +765,12 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, } /* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */ - BKE_mesh_tessface_ensure(me); + if (ss->bm) { + BKE_mesh_tessface_clear(me); + } + else { + BKE_mesh_tessface_ensure(me); + } if (!mmd) ss->kb = BKE_keyblock_from_object(ob); else ss->kb = NULL; @@ -780,7 +785,6 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->mvert = NULL; ss->mpoly = NULL; ss->mloop = NULL; - ss->face_normals = NULL; } else { ss->totvert = me->totvert; @@ -788,7 +792,6 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->mvert = me->mvert; ss->mpoly = me->mpoly; ss->mloop = me->mloop; - ss->face_normals = NULL; ss->multires = NULL; ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); } @@ -802,7 +805,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, if (!ss->orig_cos) { int a; - BKE_free_sculptsession_deformMats(ss); + BKE_sculptsession_free_deformMats(ss); ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL); @@ -815,7 +818,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, } } else { - BKE_free_sculptsession_deformMats(ss); + BKE_sculptsession_free_deformMats(ss); } if (ss->kb != NULL && ss->deform_cos == NULL) { diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index f081c964bdd..a928ed69b9e 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -65,6 +65,7 @@ #include "BKE_boids.h" #include "BKE_cloth.h" #include "BKE_colortools.h" +#include "BKE_editstrands.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_group.h" @@ -103,6 +104,8 @@ void psys_init_rng(void) static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); +static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, + int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra); extern void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3], ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t); @@ -405,7 +408,7 @@ void BKE_particlesettings_free(ParticleSettings *part) { MTex *mtex; int a; - BKE_free_animdata(&part->id); + BKE_animdata_free(&part->id); if (part->clumpcurve) curvemapping_free(part->clumpcurve); @@ -576,6 +579,11 @@ void psys_free(Object *ob, ParticleSystem *psys) if (psys->edit && psys->free_edit) psys->free_edit(psys->edit); + if (psys->hairedit) { + BKE_editstrands_free(psys->hairedit); + MEM_freeN(psys->hairedit); + psys->hairedit = NULL; + } if (psys->child) { MEM_freeN(psys->child); @@ -1173,6 +1181,11 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ return 1; } +int psys_get_index_on_dm(ParticleSystem *psys, DerivedMesh *dm, ParticleData *pa, int *mapindex, float mapfw[4]) +{ + return psys_map_index_on_dm(dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, mapindex, mapfw); +} + /* interprets particle data to get a point on a mesh in object space */ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3], @@ -1599,9 +1612,11 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) } void psys_find_parents(ParticleSimulationData *sim) { + ParticleSystem *psys = sim->psys; ParticleSettings *part = sim->psys->part; KDTree *tree; ChildParticle *cpa; + ParticleTexture ptex; int p, totparent, totchild = sim->psys->totchild; float co[3], orco[3]; int from = PART_FROM_FACE; @@ -1619,7 +1634,13 @@ void psys_find_parents(ParticleSimulationData *sim) for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) { psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0); - BLI_kdtree_insert(tree, p, orco); + + /* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */ + get_cpa_texture(sim->psmd->dm, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra); + + if (ptex.exist >= psys_frand(psys, p + 24)) { + BLI_kdtree_insert(tree, p, orco); + } } BLI_kdtree_balance(tree); @@ -1646,7 +1667,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi if (psys_in_edit_mode(scene, psys)) { ParticleEditSettings *pset = &scene->toolsettings->particle; - if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) + if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) totchild = 0; segments = 1 << pset->draw_step; @@ -1662,7 +1683,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi between = 1; } - if (psys->renderdata) + if (psys->renderdata || G.is_rendering) segments = 1 << part->ren_step; else { totchild = (int)((float)totchild * (float)part->disp / 100.0f); @@ -1747,9 +1768,9 @@ static void psys_calc_child_parent_weights(ParticleTask *task, struct ChildParti } /* modify weights to create parting */ - if (p_fac > 0.f) { + if (p_fac > 0.f && key[0]->segments != -1) { for (w = 0; w < 4; w++) { - if (w && weight[w] > 0.f) { + if (w && weight[w] > 0.f && key[w]->segments != -1) { float d; if (part->flag & PART_CHILD_LONG_HAIR) { /* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */ @@ -1941,17 +1962,28 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp ParticleCacheKey *par = NULL; float par_co[3]; float par_orco[3]; - + if (ctx->totparent) { if (i >= ctx->totparent) { pa = &psys->particles[cpa->parent]; /* this is now threadsafe, virtual parents are calculated before rest of children */ + BLI_assert(cpa->parent < psys->totchildcache); par = cache[cpa->parent]; } } else if (cpa->parent >= 0) { pa = &psys->particles[cpa->parent]; par = pcache[cpa->parent]; + + /* If particle is unexisting, try to pick a viable parent from particles used for interpolation. */ + for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) { + if (cpa->pa[k] >= 0) { + pa = &psys->particles[cpa->pa[k]]; + par = pcache[cpa->pa[k]]; + } + } + + if (pa->flag & PARS_UNEXIST) pa = NULL; } if (pa) { @@ -1983,6 +2015,7 @@ static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UN cpa = psys->child + task->begin; for (i = task->begin; i < task->end; ++i, ++cpa) { + BLI_assert(i < psys->totchildcache); psys_thread_create_path(task, cpa, cache[i], i); } } @@ -2021,7 +2054,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd /* cache parent paths */ ctx.parent_pass = 1; - psys_tasks_create(&ctx, totparent, &tasks_parent, &numtasks_parent); + psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent); for (i = 0; i < numtasks_parent; ++i) { ParticleTask *task = &tasks_parent[i]; @@ -2032,7 +2065,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd /* cache child paths */ ctx.parent_pass = 0; - psys_tasks_create(&ctx, totchild, &tasks_child, &numtasks_child); + psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child); for (i = 0; i < numtasks_child; ++i) { ParticleTask *task = &tasks_child[i]; @@ -2116,7 +2149,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4]; float rotmat[3][3]; int k; - int segments = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step)); + int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step)); int totpart = psys->totpart; float length, vec[3]; float *vg_effector = NULL; @@ -2646,6 +2679,25 @@ void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleDa mul_m4_m4m4(hairmat, ob->obmat, facemat); } +void psys_child_mat_to_object(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ChildParticle *cpa, float hairmat[4][4]) +{ + const bool between = (psys->part->childtype == PART_CHILD_FACES); + float co[3]; + + if (between) { + ParticleData *pa = &psys->particles[cpa->pa[0]]; + psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, NULL, NULL, NULL, NULL, NULL); + psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat); + } + else { + ParticleData *pa = &psys->particles[cpa->parent]; + psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL, NULL); + psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat); + } + + copy_v3_v3(hairmat[3], co); +} + /************************************************/ /* ParticleSettings handling */ /************************************************/ @@ -2734,7 +2786,7 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob) if (ob->particlesystem.first) ((ParticleSystem *) ob->particlesystem.first)->flag |= PSYS_CURRENT; else - ob->mode &= ~OB_MODE_PARTICLE_EDIT; + ob->mode &= ~(OB_MODE_PARTICLE_EDIT | OB_MODE_HAIR_EDIT); DAG_relations_tag_update(G.main); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -3011,6 +3063,11 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co pvalue = texture_value_blend(def, pvalue, value, texfac, blend); \ } (void)0 +#define SET_PARTICLE_TEXTURE_RGB(type, prgb, texfac) \ + if ((event & mtex->mapto) & type) { \ + texture_rgb_blend(prgb, rgba, prgb, value, texfac, blend); \ + } (void)0 + #define CLAMP_PARTICLE_TEXTURE_POS(type, pvalue) \ if (event & type) { \ if (pvalue < 0.0f) \ @@ -3023,6 +3080,11 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co CLAMP(pvalue, -1.0f, 1.0f); \ } (void)0 +#define CLAMP_PARTICLE_TEXTURE_RGB(type, prgb) \ + if (event & type) { \ + CLAMP3(prgb, 0.0f, 1.0f); \ + } (void)0 + /* actual usable texco mode for particles */ BLI_INLINE int particle_texco(ParticleSettings *part, MTex *mtex) { @@ -3042,6 +3104,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp = ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f; + ptex->color[0] = ptex->color[1] = ptex->color[2] = 1.0f; ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26); ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f; @@ -3087,6 +3150,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac); SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac); SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac); + SET_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color, mtex->pacolfac); } } @@ -3096,6 +3160,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist); + CLAMP_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color); } bool particle_mtex_eval(ParticleSimulationData *sim, MTex *mtex, ParticleData *pa, float cfra, float *value, float rgba[4]) @@ -3167,6 +3232,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp = ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f; + ptex->color[0] = ptex->color[1] = ptex->color[2] = 1.0f; ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart; @@ -3196,6 +3262,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac); SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac); SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac); + SET_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color, mtex->pacolfac); } } @@ -3208,6 +3275,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length); + CLAMP_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color); } /* specialized texture eval for shapekey influences */ diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 5ce1aea9ed7..13bb7c65025 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -333,7 +333,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount) rng = BLI_rng_new(31415926 + num + seed2); x= 0; - num2 = 2 * num; + num2 = 2 * num; for (i=0; i<num2; i+=2) { jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng)); @@ -468,10 +468,9 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv); } else { - ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel); - if (!isnan(ctx->jitoff[i])) { - psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv); - ctx->jitoff[i]++; + float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel); + if (!isnan(offset)) { + psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv); } } break; @@ -492,7 +491,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) { ParticleThreadContext *ctx= thread->ctx; DerivedMesh *dm= ctx->dm; - float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3]; + float *v1, *v2, *v3, *v4, nor[3], co[3]; float cur_d, min_d, randu, randv; int distr= ctx->distr; int i, intersect, tot; @@ -513,10 +512,9 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv); } else { - ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel); - if (!isnan(ctx->jitoff[i])) { - psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv); - ctx->jitoff[i]++; + float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel); + if (!isnan(offset)) { + psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv); } } break; @@ -533,14 +531,12 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, /* experimental */ tot=dm->getNumTessFaces(dm); - psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0); + psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0); normalize_v3(nor); - mul_v3_fl(nor,-100.0); + negate_v3(nor); - add_v3_v3v3(co2,co1,nor); - - min_d=2.0; + min_d=FLT_MAX; intersect=0; for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) { @@ -550,20 +546,20 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, v2=mvert[mface->v2].co; v3=mvert[mface->v3].co; - if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) { + if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, 0)) { if (cur_d<min_d) { min_d=cur_d; - pa->foffset=cur_d*50.0f; /* to the middle of volume */ + pa->foffset=cur_d*0.5f; /* to the middle of volume */ intersect=1; } } if (mface->v4) { v4=mvert[mface->v4].co; - if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) { + if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, 0)) { if (cur_d<min_d) { min_d=cur_d; - pa->foffset=cur_d*50.0f; /* to the middle of volume */ + pa->foffset=cur_d*0.5f; /* to the middle of volume */ intersect=1; } } @@ -671,6 +667,8 @@ static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int U ParticleSystem *psys= task->ctx->sim.psys; ParticleData *pa; int p; + + BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin); pa= psys->particles + task->begin; switch (psys->part->from) { @@ -1124,7 +1122,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) task_pool = BLI_task_pool_create(task_scheduler, &ctx); totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart); - psys_tasks_create(&ctx, totpart, &tasks, &numtasks); + psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks); for (i = 0; i < numtasks; ++i) { ParticleTask *task = &tasks[i]; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 7148f5e79a8..68dda2611fd 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -91,6 +91,7 @@ #include "BKE_modifier.h" #include "BKE_scene.h" #include "BKE_bvhutils.h" +#include "BKE_depsgraph.h" #include "PIL_time.h" @@ -298,7 +299,7 @@ int psys_get_child_number(Scene *scene, ParticleSystem *psys) else nbr= psys->part->child_nbr; - return get_render_child_particle_number(&scene->r, nbr); + return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL); } int psys_get_tot_child(Scene *scene, ParticleSystem *psys) @@ -449,24 +450,24 @@ BLI_INLINE int ceil_ii(int a, int b) return (a + b - 1) / b; } -void psys_tasks_create(ParticleThreadContext *ctx, int totpart, ParticleTask **r_tasks, int *r_numtasks) +void psys_tasks_create(ParticleThreadContext *ctx, int startpart, int endpart, ParticleTask **r_tasks, int *r_numtasks) { ParticleTask *tasks; - int numtasks = ceil_ii(totpart, MAX_PARTICLES_PER_TASK); - float particles_per_task = (float)totpart / (float)numtasks, p, pnext; + int numtasks = ceil_ii((endpart - startpart), MAX_PARTICLES_PER_TASK); + float particles_per_task = (float)(endpart - startpart) / (float)numtasks, p, pnext; int i; tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread"); *r_numtasks = numtasks; *r_tasks = tasks; - p = 0.0f; + p = (float)startpart; for (i = 0; i < numtasks; i++, p = pnext) { pnext = p + particles_per_task; tasks[i].ctx = ctx; tasks[i].begin = (int)p; - tasks[i].end = min_ii((int)pnext, totpart); + tasks[i].end = min_ii((int)pnext, endpart); } } @@ -560,17 +561,24 @@ static void initialize_all_particles(ParticleSimulationData *sim) ParticleSystem *psys = sim->psys; PARTICLE_P; + LOOP_PARTICLES { + initialize_particle(sim, pa); + } +} + +static void free_unexisting_particles(ParticleSimulationData *sim) +{ + ParticleSystem *psys = sim->psys; + PARTICLE_P; + psys->totunexist = 0; LOOP_PARTICLES { - if ((pa->flag & PARS_UNEXIST)==0) - initialize_particle(sim, pa); - - if (pa->flag & PARS_UNEXIST) + if (pa->flag & PARS_UNEXIST) { psys->totunexist++; + } } - /* Free unexisting particles. */ if (psys->totpart && psys->totunexist == psys->totpart) { if (psys->particles->boid) MEM_freeN(psys->particles->boid); @@ -1178,7 +1186,7 @@ void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys) PTCacheID pid; BKE_ptcache_id_from_particles(&pid, ob, psys); cache->flag &= ~PTCACHE_DISK_CACHE; - BKE_ptcache_disk_to_mem(&pid); + BKE_ptcache_disk_to_mem(&pid, false); cache->flag |= PTCACHE_DISK_CACHE; } } @@ -1268,7 +1276,7 @@ static void psys_update_effectors(ParticleSimulationData *sim) { pdEndEffectors(&sim->psys->effectors); sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys, - sim->psys->part->effector_weights, true); + sim->psys->part->effector_weights); precalc_guides(sim, sim->psys->effectors); } @@ -4087,6 +4095,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) initialize_all_particles(sim); /* reset only just created particles (on startframe all particles are recreated) */ reset_all_particles(sim, 0.0, cfra, oldtotpart); + free_unexisting_particles(sim); if (psys->fluid_springs) { MEM_freeN(psys->fluid_springs); @@ -4433,6 +4442,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) { PARTICLE_P; float disp = psys_get_current_display_percentage(psys); + bool free_unexisting = false; /* Particles without dynamics haven't been reset yet because they don't use pointcache */ if (psys->recalc & PSYS_RECALC_RESET) @@ -4442,6 +4452,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) free_keyed_keys(psys); distribute_particles(&sim, part->from); initialize_all_particles(&sim); + free_unexisting = true; /* flag for possible explode modifiers after this system */ sim.psmd->flag |= eParticleSystemFlag_Pars; @@ -4460,6 +4471,10 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) pa->flag &= ~PARS_NO_DISP; } + /* free unexisting after reseting particles */ + if (free_unexisting) + free_unexisting_particles(&sim); + if (part->phystype == PART_PHYS_KEYED) { psys_count_keyed_targets(&sim); set_keyed_keys(&sim); @@ -4492,3 +4507,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) invert_m4_m4(psys->imat, ob->obmat); } +/* **** Depsgraph evaluation **** */ + +void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), + Object *ob, + ParticleSystem *psys) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s:%s\n", __func__, ob->id.name, psys->name); + } +} diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 5e07437d426..95d8e37d1c7 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -232,16 +232,11 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi) void pbvh_grow_nodes(PBVH *bvh, int totnode) { - if (totnode > bvh->node_mem_count) { - PBVHNode *prev = bvh->nodes; - bvh->node_mem_count *= 1.33; + if (UNLIKELY(totnode > bvh->node_mem_count)) { + bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3); if (bvh->node_mem_count < totnode) bvh->node_mem_count = totnode; - bvh->nodes = MEM_mallocN(sizeof(PBVHNode) * bvh->node_mem_count, - "bvh nodes"); - memcpy(bvh->nodes, prev, bvh->totnode * sizeof(PBVHNode)); - memset(bvh->nodes + bvh->totnode, 0, (bvh->node_mem_count - bvh->totnode) * sizeof(PBVHNode)); - MEM_freeN(prev); + bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count); } bvh->totnode = totnode; @@ -575,7 +570,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int } /* Do a full rebuild with on Grids data structure */ -void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, +void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { BBC *prim_bbc = NULL; @@ -585,7 +580,6 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, bvh->type = PBVH_GRIDS; bvh->grids = grids; - bvh->gridadj = gridadj; bvh->gridfaces = gridfaces; bvh->grid_flag_mats = flagmats; bvh->totgrid = totgrid; @@ -699,16 +693,16 @@ static void pbvh_iter_end(PBVHIter *iter) static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting) { - if (iter->stacksize == iter->stackspace) { - PBVHStack *newstack; - + if (UNLIKELY(iter->stacksize == iter->stackspace)) { iter->stackspace *= 2; - newstack = MEM_callocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack"); - memcpy(newstack, iter->stack, sizeof(PBVHStack) * iter->stacksize); - if (iter->stackspace > STACK_FIXED_DEPTH) - MEM_freeN(iter->stack); - iter->stack = newstack; + if (iter->stackspace != STACK_FIXED_DEPTH) { + iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace); + } + else { + iter->stack = MEM_mallocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack"); + memcpy(iter->stack, iter->stackfixed, sizeof(PBVHStack) * iter->stacksize); + } } iter->stack[iter->stacksize].node = node; @@ -800,7 +794,7 @@ void BKE_pbvh_search_gather(PBVH *bvh, while ((node = pbvh_iter_next(&iter))) { if (node->flag & PBVH_Leaf) { - if (tot == space) { + if (UNLIKELY(tot == space)) { /* resize array if needed */ space = (tot == 0) ? 32 : space * 2; array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__); @@ -948,6 +942,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, int n; if (bvh->type == PBVH_BMESH) { + BLI_assert(face_nors == NULL); pbvh_bmesh_normals_update(nodes, totnode); return; } @@ -1285,6 +1280,16 @@ PBVHType BKE_pbvh_type(const PBVH *bvh) return bvh->type; } +bool BKE_pbvh_has_faces(const PBVH *bvh) +{ + if (bvh->type == PBVH_BMESH) { + return (bvh->bm->totface != 0); + } + else { + return (bvh->totprim != 0); + } +} + void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]) { if (bvh->totnode) { @@ -1377,7 +1382,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to } } -void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) +void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata) { switch (bvh->type) { case PBVH_GRIDS: @@ -1386,7 +1391,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int if (maxgrid) *maxgrid = bvh->totgrid; if (gridsize) *gridsize = bvh->gridkey.grid_size; if (griddata) *griddata = bvh->grids; - if (gridadj) *gridadj = bvh->gridadj; break; case PBVH_FACES: case PBVH_BMESH: @@ -1395,7 +1399,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int if (maxgrid) *maxgrid = 0; if (gridsize) *gridsize = 0; if (griddata) *griddata = NULL; - if (gridadj) *gridadj = NULL; break; } } @@ -1424,6 +1427,15 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro } } +void BKE_pbvh_node_get_bm_orco_data( + PBVHNode *node, + int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3]) +{ + *r_orco_tris = node->bm_ortri; + *r_orco_tris_num = node->bm_tot_ortri; + *r_orco_coords = node->bm_orco; +} + /********************************* Raycast ***********************************/ typedef struct { @@ -1597,7 +1609,9 @@ bool BKE_pbvh_node_raycast( return hit; } -void BKE_pbvh_raycast_project_ray_root (PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]) +void BKE_pbvh_raycast_project_ray_root( + PBVH *bvh, bool original, + float ray_start[3], float ray_end[3], float ray_normal[3]) { if (bvh->nodes) { float rootmin_start, rootmin_end; @@ -1770,13 +1784,12 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], pbvh_draw_BB(bvh); } -void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, +void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { int a; bvh->grids = grids; - bvh->gridadj = gridadj; bvh->gridfaces = gridfaces; if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) { @@ -1955,7 +1968,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->fno = NULL; vi->mvert = NULL; - BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); + BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids); BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); vi->key = &bvh->gridkey; diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 01bca44d3b6..9f092bd651f 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -29,6 +29,7 @@ #include "BLI_ghash.h" #include "BLI_heap.h" #include "BLI_math.h" +#include "BLI_memarena.h" #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" @@ -41,6 +42,27 @@ #include <assert.h> +/* Avoid skinny faces */ +#define USE_EDGEQUEUE_EVEN_SUBDIV +#ifdef USE_EDGEQUEUE_EVEN_SUBDIV +# include "BKE_global.h" +#endif + +/* Support for only operating on front-faces */ +#define USE_EDGEQUEUE_FRONTFACE + +/* don't add edges into the queue multiple times */ +#define USE_EDGEQUEUE_TAG +/** + * Ensure we don't have dirty tags for the edge queue, and that they are left cleared. + * (slow, even for debug mode, so leave disabled for now). + */ +#if defined(USE_EDGEQUEUE_TAG) && 0 +# if !defined(NDEBUG) +# define USE_EDGEQUEUE_TAG_VERIFY +# endif +#endif + // #define USE_VERIFY #ifdef USE_VERIFY @@ -107,7 +129,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver } /* Recursively split the node if it exceeds the leaf_limit */ -static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) +static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index) { GSet *empty, *other; GSetIterator gs_iter; @@ -129,7 +151,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) BB_reset(&cb); GSET_ITER (gs_iter, n->bm_faces) { const BMFace *f = BLI_gsetIterator_getKey(&gs_iter); - const BBC *bbc = BLI_ghash_lookup(prim_bbc, f); + const BBC *bbc = &bbc_array[BM_elem_index_get(f)]; BB_expand(&cb, bbc->bcentroid); } @@ -157,7 +179,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) /* Partition the parent node's faces between the two children */ GSET_ITER (gs_iter, n->bm_faces) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); - const BBC *bbc = BLI_ghash_lookup(prim_bbc, f); + const BBC *bbc = &bbc_array[BM_elem_index_get(f)]; if (bbc->bcentroid[axis] < mid) BLI_gset_insert(c1->bm_faces, f); @@ -221,8 +243,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) /* Recurse */ c1 = c2 = NULL; - pbvh_bmesh_node_split(bvh, prim_bbc, children); - pbvh_bmesh_node_split(bvh, prim_bbc, children + 1); + pbvh_bmesh_node_split(bvh, bbc_array, children); + pbvh_bmesh_node_split(bvh, bbc_array, children + 1); /* Array maybe reallocated, update current node pointer */ n = &bvh->nodes[node_index]; @@ -237,7 +259,6 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) /* Recursively split the node if it exceeds the leaf_limit */ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) { - GHash *prim_bbc; GSet *bm_faces; int bm_faces_size; GSetIterator gs_iter; @@ -252,8 +273,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) } /* For each BMFace, store the AABB and AABB centroid */ - prim_bbc = BLI_ghash_ptr_new_ex("prim_bbc", bm_faces_size); - bbc_array = MEM_callocN(sizeof(BBC) * bm_faces_size, "BBC"); + bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC"); GSET_ITER_INDEX (gs_iter, bm_faces, i) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); @@ -268,12 +288,14 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) } while ((l_iter = l_iter->next) != l_first); BBC_update_centroid(bbc); - BLI_ghash_insert(prim_bbc, f, bbc); + /* so we can do direct lookups on 'bbc_array' */ + BM_elem_index_set(f, i); /* set_dirty! */ } + /* likely this is already dirty */ + bvh->bm->elem_index_dirty |= BM_FACE; - pbvh_bmesh_node_split(bvh, prim_bbc, node_index); + pbvh_bmesh_node_split(bvh, bbc_array, node_index); - BLI_ghash_free(prim_bbc, NULL, NULL); MEM_freeN(bbc_array); return true; @@ -321,15 +343,21 @@ static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key) static BMVert *pbvh_bmesh_vert_create( PBVH *bvh, int node_index, - const float co[3], - const BMVert *example, + const float co[3], const float no[3], const int cd_vert_mask_offset) { - BMVert *v = BM_vert_create(bvh->bm, co, example, BM_CREATE_NOP); PBVHNode *node = &bvh->nodes[node_index]; + BMVert *v; BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode); + /* avoid initializing customdata because its quite involved */ + v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD); + CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data); + + /* This value is logged below */ + copy_v3_v3(v->no, no); + BLI_gset_insert(node->bm_unique_verts, v); BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index); @@ -352,7 +380,7 @@ static BMFace *pbvh_bmesh_face_create( /* ensure we never add existing face */ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); - f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); + f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -369,6 +397,7 @@ static BMFace *pbvh_bmesh_face_create( } /* Return the number of faces in 'node' that use vertex 'v' */ +#if 0 static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) { BMIter bm_iter; @@ -376,12 +405,33 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) int count = 0; BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node; + PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + if (f_node == node) { + count++; + } + } - f_node = pbvh_bmesh_node_lookup(bvh, f); + return count; +} +#endif + +#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \ + (pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n) - if (f_node == node) +static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) +{ + BMIter bm_iter; + BMFace *f; + int count = 0; + + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + if (f_node == node) { count++; + if (count == count_max) { + break; + } + } } return count; @@ -484,13 +534,13 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { v = l_iter->v; - if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) { + if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) { if (BLI_gset_haskey(f_node->bm_unique_verts, v)) { /* Find a different node that uses 'v' */ PBVHNode *new_node; new_node = pbvh_bmesh_vert_other_node_find(bvh, v); - BLI_assert(new_node || BM_vert_face_count(v) == 1); + BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1)); if (new_node) { pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v); @@ -548,6 +598,15 @@ typedef struct { const float *center; float radius_squared; float limit_len_squared; +#ifdef USE_EDGEQUEUE_EVEN_SUBDIV + float limit_len; +#endif + +#ifdef USE_EDGEQUEUE_FRONTFACE + const float *view_normal; + unsigned int use_view_normal : 1; +#endif + } EdgeQueue; typedef struct { @@ -559,6 +618,44 @@ typedef struct { int cd_face_node_offset; } EdgeQueueContext; +/* only tag'd edges are in the queue */ +#ifdef USE_EDGEQUEUE_TAG +# define EDGE_QUEUE_TEST(e) (BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)) +# define EDGE_QUEUE_ENABLE(e) BM_elem_flag_enable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG) +# define EDGE_QUEUE_DISABLE(e) BM_elem_flag_disable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG) +#endif + +#ifdef USE_EDGEQUEUE_TAG_VERIFY +/* simply check no edges are tagged + * (it's a requirement that edges enter and leave a clean tag state) */ +static void pbvh_bmesh_edge_tag_verify(PBVH *bvh) +{ + int n; + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + GSetIterator gs_iter; + if (node->bm_faces) { + GSET_ITER (gs_iter, node->bm_faces) { + BMFace *f = BLI_gsetIterator_getKey(&gs_iter); + BMEdge *e_tri[3]; + BMLoop *l_iter; + + BLI_assert(f->len == 3); + l_iter = BM_FACE_FIRST_LOOP(f); + e_tri[0] = l_iter->e; l_iter = l_iter->next; + e_tri[1] = l_iter->e; l_iter = l_iter->next; + e_tri[2] = l_iter->e; + + BLI_assert((EDGE_QUEUE_TEST(e_tri[0]) == false) && + (EDGE_QUEUE_TEST(e_tri[1]) == false) && + (EDGE_QUEUE_TEST(e_tri[2]) == false)); + } + } + } +} +#endif + static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) { BMVert *v_tri[3]; @@ -580,8 +677,9 @@ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v) return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f); } -static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, - float priority) +static void edge_queue_insert( + EdgeQueueContext *eq_ctx, BMEdge *e, + float priority) { BMVert **pair; @@ -600,28 +698,120 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, pair[0] = e->v1; pair[1] = e->v2; BLI_heap_insert(eq_ctx->q->heap, priority, pair); +#ifdef USE_EDGEQUEUE_TAG + BLI_assert(EDGE_QUEUE_TEST(e) == false); + EDGE_QUEUE_ENABLE(e); +#endif } } -static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, - BMEdge *e) +static void long_edge_queue_edge_add( + EdgeQueueContext *eq_ctx, + BMEdge *e) { - const float len_sq = BM_edge_calc_length_squared(e); - if (len_sq > eq_ctx->q->limit_len_squared) - edge_queue_insert(eq_ctx, e, -len_sq); +#ifdef USE_EDGEQUEUE_TAG + if (EDGE_QUEUE_TEST(e) == false) +#endif + { + const float len_sq = BM_edge_calc_length_squared(e); + if (len_sq > eq_ctx->q->limit_len_squared) { + edge_queue_insert(eq_ctx, e, -len_sq); + } + } } -static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, - BMEdge *e) +#ifdef USE_EDGEQUEUE_EVEN_SUBDIV +static void long_edge_queue_edge_add_recursive( + EdgeQueueContext *eq_ctx, + BMLoop *l_edge, BMLoop *l_end, + const float len_sq, float limit_len) { - const float len_sq = BM_edge_calc_length_squared(e); - if (len_sq < eq_ctx->q->limit_len_squared) - edge_queue_insert(eq_ctx, e, len_sq); + BLI_assert(len_sq > SQUARE(limit_len)); + +#ifdef USE_EDGEQUEUE_FRONTFACE + if (eq_ctx->q->use_view_normal) { + if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) { + return; + } + } +#endif + +#ifdef USE_EDGEQUEUE_TAG + if (EDGE_QUEUE_TEST(l_edge->e) == false) +#endif + { + edge_queue_insert(eq_ctx, l_edge->e, -len_sq); + } + + /* temp support previous behavior! */ + if (UNLIKELY(G.debug_value == 1234)) { + return; + } + + if ((l_edge->radial_next != l_edge)) { + /* how much longer we need to be to consider for subdividing + * (avoids subdividing faces which are only *slightly* skinny) */ +#define EVEN_EDGELEN_THRESHOLD 1.2f + /* how much the limit increases per recursion + * (avoids performing subdvisions too far away) */ +#define EVEN_GENERATION_SCALE 1.6f + + const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD; + float limit_len_sq; + BMLoop *l_iter; + + limit_len *= EVEN_GENERATION_SCALE; + limit_len_sq = SQUARE(limit_len); + + l_iter = l_edge; + do { + float len_sq_other; + BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev}; + int i; + for (i = 0; i < ARRAY_SIZE(l_adjacent); i++) { + len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e); + if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) { +// edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other); + long_edge_queue_edge_add_recursive( + eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i], + len_sq_other, limit_len); + } + } + } while ((l_iter = l_iter->radial_next) != l_end); + +#undef EVEN_EDGELEN_THRESHOLD +#undef EVEN_GENERATION_SCALE + } } +#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */ -static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, - BMFace *f) +static void short_edge_queue_edge_add( + EdgeQueueContext *eq_ctx, + BMEdge *e) { +#ifdef USE_EDGEQUEUE_TAG + if (EDGE_QUEUE_TEST(e) == false) +#endif + { + const float len_sq = BM_edge_calc_length_squared(e); + if (len_sq < eq_ctx->q->limit_len_squared) { + edge_queue_insert(eq_ctx, e, len_sq); + } + } +} + +static void long_edge_queue_face_add( + EdgeQueueContext *eq_ctx, + BMFace *f) +{ +#ifdef USE_EDGEQUEUE_FRONTFACE + if (eq_ctx->q->use_view_normal) { + if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) { + return; + } + } +#endif + if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { BMLoop *l_iter; BMLoop *l_first; @@ -629,14 +819,34 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, /* Check each edge of the face */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - long_edge_queue_edge_add(eq_ctx, l_iter->e); + { +#ifdef USE_EDGEQUEUE_EVEN_SUBDIV + const float len_sq = BM_edge_calc_length_squared(l_iter->e); + if (len_sq > eq_ctx->q->limit_len_squared) { + long_edge_queue_edge_add_recursive( + eq_ctx, l_iter->radial_next, l_iter, + len_sq, eq_ctx->q->limit_len); + } +#else + long_edge_queue_edge_add(eq_ctx, l_iter->e); +#endif + } } while ((l_iter = l_iter->next) != l_first); } } -static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, - BMFace *f) +static void short_edge_queue_face_add( + EdgeQueueContext *eq_ctx, + BMFace *f) { +#ifdef USE_EDGEQUEUE_FRONTFACE + if (eq_ctx->q->use_view_normal) { + if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) { + return; + } + } +#endif + if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { BMLoop *l_iter; BMLoop *l_first; @@ -658,9 +868,10 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, * * The highest priority (lowest number) is given to the longest edge. */ -static void long_edge_queue_create(EdgeQueueContext *eq_ctx, - PBVH *bvh, const float center[3], - float radius) +static void long_edge_queue_create( + EdgeQueueContext *eq_ctx, + PBVH *bvh, const float center[3], const float view_normal[3], + float radius) { int n; @@ -668,6 +879,21 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx, eq_ctx->q->center = center; eq_ctx->q->radius_squared = radius * radius; eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len; +#ifdef USE_EDGEQUEUE_EVEN_SUBDIV + eq_ctx->q->limit_len = bvh->bm_max_edge_len; +#endif + +#ifdef USE_EDGEQUEUE_FRONTFACE + eq_ctx->q->view_normal = view_normal; + eq_ctx->q->use_view_normal = (view_normal != NULL); +#else + UNUSED_VARS(view_normal); +#endif + +#ifdef USE_EDGEQUEUE_TAG_VERIFY + pbvh_bmesh_edge_tag_verify(bvh); +#endif + for (n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -698,9 +924,10 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx, * * The highest priority (lowest number) is given to the shortest edge. */ -static void short_edge_queue_create(EdgeQueueContext *eq_ctx, - PBVH *bvh, const float center[3], - float radius) +static void short_edge_queue_create( + EdgeQueueContext *eq_ctx, + PBVH *bvh, const float center[3], const float view_normal[3], + float radius) { int n; @@ -708,6 +935,16 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx, eq_ctx->q->center = center; eq_ctx->q->radius_squared = radius * radius; eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; +#ifdef USE_EDGEQUEUE_EVEN_SUBDIV + eq_ctx->q->limit_len = bvh->bm_min_edge_len; +#endif + +#ifdef USE_EDGEQUEUE_FRONTFACE + eq_ctx->q->view_normal = view_normal; + eq_ctx->q->use_view_normal = (view_normal != NULL); +#else + UNUSED_VARS(view_normal); +#endif for (n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -738,21 +975,24 @@ static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); } -static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, - BMEdge *e, BLI_Buffer *edge_loops) +static void pbvh_bmesh_split_edge( + EdgeQueueContext *eq_ctx, PBVH *bvh, + BMEdge *e, BLI_Buffer *edge_loops) { BMVert *v_new; - float mid[3]; + float co_mid[3], no_mid[3]; int i, node_index; /* Get all faces adjacent to the edge */ pbvh_bmesh_edge_loops(edge_loops, e); /* Create a new vertex in current node at the edge's midpoint */ - mid_v3_v3v3(mid, e->v1->co, e->v2->co); + mid_v3_v3v3(co_mid, e->v1->co, e->v2->co); + mid_v3_v3v3(no_mid, e->v1->no, e->v2->no); + normalize_v3(no_mid); node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset); - v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1, eq_ctx->cd_vert_mask_offset); + v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset); /* update paint mask */ if (eq_ctx->cd_vert_mask_offset != -1) { @@ -788,6 +1028,32 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, if (ni != node_index && i == 0) pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new); + /** + * The 2 new faces created and assigned to ``f_new`` have their + * verts & edges shuffled around. + * + * - faces wind anticlockwise in this example. + * - original edge is ``(v1, v2)`` + * - oroginal face is ``(v1, v2, v3)`` + * + * <pre> + * + v3(v_opp) + * /|\ + * / | \ + * / | \ + * e4/ | \ e3 + * / |e5 \ + * / | \ + * / e1 | e2 \ + * +-------+-------+ + * v1 v4(v_new) v2 + * (first) (second) + * </pre> + * + * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)`` + * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)`` + */ + /* Create two new faces */ v_tri[0] = v1; v_tri[1] = v_new; @@ -810,13 +1076,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, BM_face_kill(bvh->bm, f_adj); /* Ensure new vertex is in the node */ - if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new) && - !BLI_gset_haskey(bvh->nodes[ni].bm_other_verts, v_new)) - { - BLI_gset_insert(bvh->nodes[ni].bm_other_verts, v_new); + if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) { + BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new); } - if (BM_vert_edge_count(v_opp) >= 9) { + if (BM_vert_edge_count_is_over(v_opp, 8)) { BMIter bm_iter; BMEdge *e2; @@ -829,8 +1093,9 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, BM_edge_kill(bvh->bm, e); } -static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh, - BLI_Buffer *edge_loops) +static bool pbvh_bmesh_subdivide_long_edges( + EdgeQueueContext *eq_ctx, PBVH *bvh, + BLI_Buffer *edge_loops) { bool any_subdivided = false; @@ -842,13 +1107,22 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh, BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; - if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared) - continue; - /* Check that the edge still exists */ if (!(e = BM_edge_exists(v1, v2))) { continue; } +#ifdef USE_EDGEQUEUE_TAG + EDGE_QUEUE_DISABLE(e); +#endif + + /* At the moment edges never get shorter (subdiv will make new edges) + * unlike collapse where edges can become longer. */ +#if 0 + if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared) + continue; +#else + BLI_assert(len_squared_v3v3(v1->co, v2->co) > eq_ctx->q->limit_len_squared); +#endif /* Check that the edge's vertices are still in the PBVH. It's * possible that an edge collapse has deleted adjacent faces @@ -865,6 +1139,10 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh, pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops); } +#ifdef USE_EDGEQUEUE_TAG_VERIFY + pbvh_bmesh_edge_tag_verify(bvh); +#endif + return any_subdivided; } @@ -945,10 +1223,8 @@ static void pbvh_bmesh_collapse_edge( pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f); /* Ensure that v_conn is in the new face's node */ - if (!BLI_gset_haskey(n->bm_unique_verts, v_conn) && - !BLI_gset_haskey(n->bm_other_verts, v_conn)) - { - BLI_gset_insert(n->bm_other_verts, v_conn); + if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) { + BLI_gset_add(n->bm_other_verts, v_conn); } } @@ -970,18 +1246,6 @@ static void pbvh_bmesh_collapse_edge( v_tri[1] = l_iter->v; e_tri[1] = l_iter->e; l_iter = l_iter->next; v_tri[2] = l_iter->v; e_tri[2] = l_iter->e; - /* Check if any of the face's vertices are now unused, if so - * remove them from the PBVH */ - for (j = 0; j < 3; j++) { - if (v_tri[j] != v_del && BM_vert_face_count(v_tri[j]) == 1) { - BLI_gset_insert(deleted_verts, v_tri[j]); - pbvh_bmesh_vert_remove(bvh, v_tri[j]); - } - else { - v_tri[j] = NULL; - } - } - /* Remove the face */ pbvh_bmesh_face_remove(bvh, f_del); BM_face_kill(bvh->bm, f_del); @@ -993,9 +1257,13 @@ static void pbvh_bmesh_collapse_edge( BM_edge_kill(bvh->bm, e_tri[j]); } - /* Delete unused vertices */ + /* Check if any of the face's vertices are now unused, if so + * remove them from the PBVH */ for (j = 0; j < 3; j++) { - if (v_tri[j]) { + if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) { + BLI_gset_insert(deleted_verts, v_tri[j]); + pbvh_bmesh_vert_remove(bvh, v_tri[j]); + BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset); BM_vert_kill(bvh->bm, v_tri[j]); } @@ -1007,10 +1275,12 @@ static void pbvh_bmesh_collapse_edge( if (!BLI_gset_haskey(deleted_verts, v_conn)) { BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset); mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co); + add_v3_v3(v_conn->no, v_del->no); + normalize_v3(v_conn->no); } /* Delete v_del */ - BLI_assert(BM_vert_face_count(v_del) == 0); + BLI_assert(!BM_vert_face_check(v_del)); BLI_gset_insert(deleted_verts, v_del); BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset); BM_vert_kill(bvh->bm, v_del); @@ -1042,13 +1312,16 @@ static bool pbvh_bmesh_collapse_short_edges( continue; } - if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared) - continue; - /* Check that the edge still exists */ if (!(e = BM_edge_exists(v1, v2))) { continue; } +#ifdef USE_EDGEQUEUE_TAG + EDGE_QUEUE_DISABLE(e); +#endif + + if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared) + continue; /* Check that the edge's vertices are still in the PBVH. It's * possible that an edge collapse has deleted adjacent faces @@ -1074,9 +1347,10 @@ static bool pbvh_bmesh_collapse_short_edges( /************************* Called from pbvh.c *************************/ -bool pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], - const float ray_normal[3], float *dist, - bool use_original) +bool pbvh_bmesh_node_raycast( + PBVHNode *node, const float ray_start[3], + const float ray_normal[3], float *dist, + bool use_original) { bool hit = false; @@ -1189,36 +1463,225 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) } } -/***************************** Public API *****************************/ +typedef struct FastNodeBuildInfo { + int totface; /* number of faces */ + int start; /* start of faces in array */ + struct FastNodeBuildInfo *child1; + struct FastNodeBuildInfo *child2; +} FastNodeBuildInfo; -static void pbvh_bmesh_node_layers_reset(PBVH *bvh) +/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies + * to a sub part of the arrays */ +static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena) { BMFace *f; - BMVert *v; - BMIter iter; - BMesh *bm = bvh->bm; - int cd_vert_node_offset = bvh->cd_vert_node_offset; - int cd_face_node_offset = bvh->cd_face_node_offset; + BB cb; + BBC *bbc; + float mid; + int axis, i; + int end; + FastNodeBuildInfo *child1, *child2; + int num_child1, num_child2; + BMFace *tmp; - /* clear the elements of the node information */ - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { - BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE); + if (node->totface <= bvh->leaf_limit) { + return; } - BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { - BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE); + /* Calculate bounding box around primitive centroids */ + BB_reset(&cb); + for (i = 0; i < node->totface; i++) { + f = nodeinfo[i + node->start]; + bbc = &bbc_array[BM_elem_index_get(f)]; + + BB_expand(&cb, bbc->bcentroid); + } + + /* initialize the children */ + + /* Find widest axis and its midpoint */ + axis = BB_widest_axis(&cb); + mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + + num_child1 = 0, num_child2 = 0; + + /* split vertices along the middle line */ + end = node->start + node->totface; + for (i = node->start; i < end - num_child2; i++) { + f = nodeinfo[i]; + bbc = &bbc_array[BM_elem_index_get(f)]; + + if (bbc->bcentroid[axis] > mid) { + int i_iter = end - num_child2 - 1; + int candidate = -1; + /* found a face that should be part of another node, look for a face to substitute with */ + + for (;i_iter > i; i_iter--) { + BMFace *f_iter = nodeinfo[i_iter]; + const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)]; + if (bbc_iter->bcentroid[axis] <= mid) { + candidate = i_iter; + break; + } + else { + num_child2++; + } + } + + if (candidate != -1) { + tmp = nodeinfo[i]; + nodeinfo[i] = nodeinfo[candidate]; + nodeinfo[candidate] = tmp; + /* increase both counts */ + num_child1++; + num_child2++; + } + else { + /* not finding candidate means second half of array part is full of + * second node parts, just increase the number of child nodes for it */ + num_child2++; + } + } + else { + num_child1++; + } + } + + /* ensure at least one child in each node */ + if (num_child2 == 0) { + num_child2++; + num_child1--; + } + else if (num_child1 == 0) { + num_child1++; + num_child2--; + } + + /* at this point, faces should have been split along the array range sequentially, + * each sequential part belonging to one node only */ + BLI_assert((num_child1 + num_child2) == node->totface); + + node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); + node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); + + child1->totface = num_child1; + child1->start = node->start; + child2->totface = num_child2; + child2->start = node->start + num_child1; + child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL; + + pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena); + pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena); + + return; +} + +static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index) +{ + PBVHNode *n = bvh->nodes + node_index; + /* two cases, node does not have children or does have children */ + if (node->child1) { + int children_offset = bvh->totnode; + + n->children_offset = children_offset; + pbvh_grow_nodes(bvh, bvh->totnode + 2); + pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child1, children_offset); + pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child2, children_offset + 1); + + n = &bvh->nodes[node_index]; + + /* Update bounding box */ + BB_reset(&n->vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb); + n->orig_vb = n->vb; + } + else { + /* node does not have children so it's a leaf node, populate with faces and tag accordingly + * this is an expensive part but it's not so easily threadable due to vertex node indices */ + const int cd_vert_node_offset = bvh->cd_vert_node_offset; + const int cd_face_node_offset = bvh->cd_face_node_offset; + + bool has_visible = false; + int i, end; + BMFace *f; + BMLoop *l_iter; + BMLoop *l_first; + BMVert *v; + BBC *bbc; + + n->flag = PBVH_Leaf; + n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface); + + /* Create vert hash sets */ + n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts"); + n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts"); + + BB_reset(&n->vb); + + end = node->start + node->totface; + + for (i = node->start; i < end; i++) { + f = nodeinfo[i]; + bbc = &bbc_array[BM_elem_index_get(f)]; + + /* Update ownership of faces */ + BLI_gset_insert(n->bm_faces, f); + BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index); + + /* Update vertices */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + v = l_iter->v; + if (!BLI_gset_haskey(n->bm_unique_verts, v)) { + if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) { + BLI_gset_add(n->bm_other_verts, v); + } + else { + BLI_gset_insert(n->bm_unique_verts, v); + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index); + } + } + /* Update node bounding box */ + } while ((l_iter = l_iter->next) != l_first); + + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) + has_visible = true; + + BB_expand_with_bb(&n->vb, (BB *)bbc); + } + + BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && + n->vb.bmin[1] <= n->vb.bmax[1] && + n->vb.bmin[2] <= n->vb.bmax[2]); + + n->orig_vb = n->vb; + + /* Build GPU buffers for new node and update vertex normals */ + BKE_pbvh_node_mark_rebuild_draw(n); + + BKE_pbvh_node_fully_hidden_set(n, !has_visible); + n->flag |= PBVH_UpdateNormals; } } +/***************************** Public API *****************************/ + /* Build a PBVH from a BMesh */ -void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, - const int cd_vert_node_offset, const int cd_face_node_offset) +void BKE_pbvh_build_bmesh( + PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, + const int cd_vert_node_offset, const int cd_face_node_offset) { BMIter iter; BMFace *f; - PBVHNode *n; - int node_index = 0; + BMVert *v; + int i; + /* bounding box array of all faces, no need to recalculate every time */ + BBC *bbc_array; + BMFace **nodeinfo; + FastNodeBuildInfo rootnode = {0}; + MemArena *arena; bvh->cd_vert_node_offset = cd_vert_node_offset; bvh->cd_face_node_offset = cd_face_node_offset; @@ -1235,26 +1698,61 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, if (smooth_shading) bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; - pbvh_bmesh_node_layers_reset(bvh); + /* calculate all bounding boxes once for all faces */ + bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC"); + nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo"); + arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage"); + + BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) { + BBC *bbc = &bbc_array[i]; + BMLoop *l_iter; + BMLoop *l_first; + + BB_reset((BB *)bbc); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BB_expand((BB *)bbc, l_iter->v->co); + } while ((l_iter = l_iter->next) != l_first); + BBC_update_centroid(bbc); + + /* so we can do direct lookups on 'bbc_array' */ + BM_elem_index_set(f, i); /* set_dirty! */ + nodeinfo[i] = f; + BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE); + } + + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE); + } + + /* likely this is already dirty */ + bm->elem_index_dirty |= BM_FACE; + + /* setup root node */ + rootnode.totface = bm->totface; + + /* start recursion, assign faces to nodes accordingly */ + pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena); + + /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */ /* Start with all faces in the root node */ - n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); + bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); bvh->totnode = 1; - n->flag = PBVH_Leaf; - n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", bvh->bm->totface); - BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BLI_gset_insert(n->bm_faces, f); - } - /* Recursively split the node until it is under the limit; if no - * splitting occurs then finalize the existing leaf node */ - if (!pbvh_bmesh_node_limit_ensure(bvh, node_index)) - pbvh_bmesh_node_finalize(bvh, 0, cd_vert_node_offset, cd_face_node_offset); + /* take root node and visit and populate children recursively */ + pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0); + + BLI_memarena_free(arena); + MEM_freeN(bbc_array); + MEM_freeN(nodeinfo); } /* Collapse short edges, subdivide long edges */ -bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, - const float center[3], float radius) +bool BKE_pbvh_bmesh_update_topology( + PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], const float view_normal[3], + float radius) { /* 2 is enough for edge faces - manifold edge */ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2); @@ -1266,12 +1764,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, bool modified = false; int n; + if (view_normal) { + BLI_assert(len_squared_v3(view_normal) != 0.0f); + } + if (mode & PBVH_Collapse) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; - short_edge_queue_create(&eq_ctx, bvh, center, radius); + short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); modified |= !BLI_heap_is_empty(q.heap); pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &deleted_faces); @@ -1284,7 +1786,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; - long_edge_queue_create(&eq_ctx, bvh, center, radius); + long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); modified |= !BLI_heap_is_empty(q.heap); pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops); BLI_heap_free(q.heap, NULL); @@ -1641,7 +2143,7 @@ static void pbvh_bmesh_verify(PBVH *bvh) GSET_ITER (gs_iter, n->bm_other_verts) { BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - BLI_assert(BM_vert_face_count(v) > 0); + BLI_assert(!BM_vert_face_check(v)); BLI_assert(BLI_gset_haskey(verts_all, v)); } } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 6b3ef8eb5da..7daccb47c92 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -139,7 +139,6 @@ struct PBVH { /* Grid Data */ CCGKey gridkey; CCGElem **grids; - DMGridAdjacency *gridadj; void **gridfaces; const DMFlagMat *grid_flag_mats; int totgrid; @@ -175,9 +174,10 @@ void BB_expand_with_bb(BB *bb, BB *bb2); void BBC_update_centroid(BBC *bbc); int BB_widest_axis(const BB *bb); void pbvh_grow_nodes(PBVH *bvh, int totnode); -bool ray_face_intersection(const float ray_start[3], const float ray_normal[3], - const float *t0, const float *t1, const float *t2, - const float *t3, float *fdist); +bool ray_face_intersection( + const float ray_start[3], const float ray_normal[3], + const float *t0, const float *t1, const float *t2, + const float *t3, float *fdist); void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag); /* pbvh_bmesh.c */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index e6d41063262..4711a5900f0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -84,8 +84,12 @@ #endif #ifdef WITH_LZO -#include "minilzo.h" -#define LZO_HEAP_ALLOC(var,size) \ +# ifdef WITH_SYSTEM_LZO +# include <lzo/lzo1x.h> +# else +# include "minilzo.h" +# endif +# define LZO_HEAP_ALLOC(var,size) \ lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] #endif @@ -2533,7 +2537,7 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra) */ /* Clears & resets */ -void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) +void BKE_ptcache_id_clear_ex(PTCacheID *pid, int mode, unsigned int cfra, bool allow_file_delete) { unsigned int len; /* store the length of the string */ unsigned int sta, end; @@ -2591,8 +2595,10 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */ if (mode == PTCACHE_CLEAR_ALL) { pid->cache->last_exact = MIN2(pid->cache->startframe, 0); - BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); - BLI_delete(path_full, false, false); + if (allow_file_delete) { + BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); + BLI_delete(path_full, false, false); + } } else { /* read the number of the file */ @@ -2607,8 +2613,10 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) (mode == PTCACHE_CLEAR_AFTER && frame > cfra)) { - BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); - BLI_delete(path_full, false, false); + if (allow_file_delete) { + BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); + BLI_delete(path_full, false, false); + } if (pid->cache->cached_frames && frame >=sta && frame <= end) pid->cache->cached_frames[frame-sta] = 0; } @@ -2661,8 +2669,10 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) case PTCACHE_CLEAR_FRAME: if (pid->cache->flag & PTCACHE_DISK_CACHE) { if (BKE_ptcache_id_exist(pid, cfra)) { - ptcache_filename(pid, filename, cfra, 1, 1); /* no path */ - BLI_delete(filename, false, false); + if (allow_file_delete) { + ptcache_filename(pid, filename, cfra, 1, 1); /* no path */ + BLI_delete(filename, false, false); + } } } else { @@ -2684,6 +2694,13 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) BKE_ptcache_update_info(pid); } + +/* Clears & resets */ +void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) +{ + BKE_ptcache_id_clear_ex(pid, mode, cfra, false); +} + int BKE_ptcache_id_exist(PTCacheID *pid, int cfra) { if (!pid->cache) @@ -2955,49 +2972,6 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) return reset; } -/* Use this when quitting blender, with unsaved files */ -void BKE_ptcache_remove(void) -{ - char path[MAX_PTCACHE_PATH]; - char path_full[MAX_PTCACHE_PATH]; - int rmdir = 1; - - ptcache_path(NULL, path); - - if (BLI_exists(path)) { - /* The pointcache dir exists? - remove all pointcache */ - - DIR *dir; - struct dirent *de; - - dir = opendir(path); - if (dir==NULL) - return; - - while ((de = readdir(dir)) != NULL) { - if (FILENAME_IS_CURRPAR(de->d_name)) { - /* do nothing */ - } - else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/ - BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); - BLI_delete(path_full, false, false); - } - else { - rmdir = 0; /* unknown file, don't remove the dir */ - } - } - - closedir(dir); - } - else { - rmdir = 0; /* path dosnt exist */ - } - - if (rmdir) { - BLI_delete(path, true, false); - } -} - /* Point Cache handling */ PointCache *BKE_ptcache_add(ListBase *ptcaches) @@ -3089,7 +3063,7 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data) } /* returns first point cache */ -PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old, bool copy_data) +PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data) { PointCache *cache = ptcaches_old->first; @@ -3350,7 +3324,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) } } - BLI_end_threads(&threads); + BLI_end_threads(&threads); } /* clear baking flag */ if (pid) { @@ -3408,21 +3382,24 @@ void BKE_ptcache_bake(PTCacheBaker *baker) /* TODO: call redraw all windows somehow */ } /* Helpers */ -void BKE_ptcache_disk_to_mem(PTCacheID *pid) +void BKE_ptcache_disk_to_mem(PTCacheID *pid, bool clear) { PointCache *cache = pid->cache; PTCacheMem *pm = NULL; - int baked = cache->flag & PTCACHE_BAKED; int cfra, sfra = cache->startframe, efra = cache->endframe; - /* Remove possible bake flag to allow clear */ - cache->flag &= ~PTCACHE_BAKED; - - /* PTCACHE_DISK_CACHE flag was cleared already */ - BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); - - /* restore possible bake flag */ - cache->flag |= baked; + if (clear) { + int baked = cache->flag & PTCACHE_BAKED; + + /* Remove possible bake flag to allow clear */ + cache->flag &= ~PTCACHE_BAKED; + + /* PTCACHE_DISK_CACHE flag was cleared already */ + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + /* restore possible bake flag */ + cache->flag |= baked; + } for (cfra=sfra; cfra <= efra; cfra++) { pm = ptcache_disk_frame_to_mem(pid, cfra); @@ -3431,20 +3408,23 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid) BLI_addtail(&pid->cache->mem_cache, pm); } } -void BKE_ptcache_mem_to_disk(PTCacheID *pid) +void BKE_ptcache_mem_to_disk(PTCacheID *pid, bool clear) { PointCache *cache = pid->cache; PTCacheMem *pm = cache->mem_cache.first; - int baked = cache->flag & PTCACHE_BAKED; - - /* Remove possible bake flag to allow clear */ - cache->flag &= ~PTCACHE_BAKED; - - /* PTCACHE_DISK_CACHE flag was set already */ - BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); - /* restore possible bake flag */ - cache->flag |= baked; + if (clear) { + int baked = cache->flag & PTCACHE_BAKED; + + /* Remove possible bake flag to allow clear */ + cache->flag &= ~PTCACHE_BAKED; + + /* PTCACHE_DISK_CACHE flag was set already */ + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + /* restore possible bake flag */ + cache->flag |= baked; + } for (; pm; pm=pm->next) { if (ptcache_mem_frame_to_disk(pid, pm)==0) { @@ -3475,9 +3455,9 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) } if (cache->flag & PTCACHE_DISK_CACHE) - BKE_ptcache_mem_to_disk(pid); + BKE_ptcache_mem_to_disk(pid, true); else - BKE_ptcache_disk_to_mem(pid); + BKE_ptcache_disk_to_mem(pid, true); cache->flag ^= PTCACHE_DISK_CACHE; BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index aaf54b82f32..b4218378eb8 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -54,6 +54,7 @@ #include "DNA_scene_types.h" #include "BKE_cdderivedmesh.h" +#include "BKE_depsgraph.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_library.h" @@ -61,6 +62,7 @@ #include "BKE_object.h" #include "BKE_pointcache.h" #include "BKE_rigidbody.h" +#include "BKE_scene.h" #ifdef WITH_BULLET @@ -1236,7 +1238,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o ListBase *effectors; /* get effectors present in the group specified by effector_weights */ - effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true); + effectors = pdInitEffectors(scene, ob, NULL, effector_weights); if (effectors) { float eff_force[3] = {0.0f, 0.0f, 0.0f}; float eff_loc[3], eff_vel[3]; @@ -1610,3 +1612,51 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {} #endif #endif /* WITH_BULLET */ + +/* -------------------- */ +/* Depsgraph evaluation */ + +void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx), + Scene *scene) +{ + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s at %f\n", __func__, ctime); + } + + /* rebuild sim data (i.e. after resetting to start of timeline) */ + if (BKE_scene_check_rigidbody_active(scene)) { + BKE_rigidbody_rebuild_world(scene, ctime); + } +} + +void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx), + Scene *scene) +{ + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s at %f\n", __func__, ctime); + } + + /* evaluate rigidbody sim */ + if (BKE_scene_check_rigidbody_active(scene)) { + BKE_rigidbody_do_simulation(scene, ctime); + } +} + +void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + Object *ob) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + float ctime = BKE_scene_frame_get(scene); + + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, ob->id.name); + } + + /* read values pushed into RBO from sim/cache... */ + BKE_rigidbody_sync_transforms(rbw, ob, ctime); +} diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 32d568f5729..b6fede75d96 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -64,6 +64,7 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_cache_library.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" #include "BKE_editmesh.h" @@ -75,6 +76,7 @@ #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_mask.h" #include "BKE_node.h" @@ -82,16 +84,20 @@ #include "BKE_paint.h" #include "BKE_rigidbody.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_sound.h" #include "BKE_unit.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" + #include "RE_engine.h" #include "PIL_time.h" #include "IMB_colormanagement.h" +#include "IMB_imbuf.h" #include "bmesh.h" @@ -153,18 +159,21 @@ Scene *BKE_scene_copy(Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; + FreestyleLineSet *lineset; ToolSettings *ts; Base *base, *obase; if (type == SCE_COPY_EMPTY) { - ListBase lb; + ListBase rl, rv; /* XXX. main should become an arg */ scen = BKE_scene_add(G.main, sce->id.name + 2); - lb = scen->r.layers; + rl = scen->r.layers; + rv = scen->r.views; scen->r = sce->r; - scen->r.layers = lb; + scen->r.layers = rl; scen->r.actlay = 0; + scen->r.views = rv; scen->unit = sce->unit; scen->physics_settings = sce->physics_settings; scen->gm = sce->gm; @@ -187,6 +196,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) scen->ed = NULL; scen->theDag = NULL; + scen->depsgraph = NULL; scen->obedit = NULL; scen->stats = NULL; scen->fps_info = NULL; @@ -197,6 +207,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) BLI_duplicatelist(&(scen->markers), &(sce->markers)); BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces)); BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers)); + BLI_duplicatelist(&(scen->r.views), &(sce->r.views)); BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets)); if (sce->nodetree) { @@ -224,7 +235,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) sizeof(scen->sequencer_colorspace_settings.name)); /* copy action and remove animation used by sequencer */ - BKE_copy_animdata_id_action(&scen->id); + BKE_animdata_copy_id_action(&scen->id); if (type != SCE_COPY_FULL) remove_sequencer_fcurves(scen); @@ -233,6 +244,14 @@ Scene *BKE_scene_copy(Scene *sce, int type) new_srl = scen->r.layers.first; for (srl = sce->r.layers.first; srl; srl = srl->next) { BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig); + if (type == SCE_COPY_FULL) { + for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + id_us_plus((ID *)lineset->linestyle); + lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle); + } + } + } new_srl = new_srl->next; } } @@ -293,14 +312,14 @@ Scene *BKE_scene_copy(Scene *sce, int type) } /* before scene copy */ - sound_create_scene(scen); + BKE_sound_create_scene(scen); /* world */ if (type == SCE_COPY_FULL) { if (scen->world) { id_us_plus((ID *)scen->world); scen->world = BKE_world_copy(scen->world); - BKE_copy_animdata_id_action((ID *)scen->world); + BKE_animdata_copy_id_action((ID *)scen->world); } if (sce->ed) { @@ -361,7 +380,7 @@ void BKE_scene_free(Scene *sce) BLI_freelistN(&sce->base); BKE_sequencer_editing_free(sce); - BKE_free_animdata((ID *)sce); + BKE_animdata_free((ID *)sce); BKE_keyingsets_free(&sce->keyingsets); if (sce->rigidbody_world) @@ -390,6 +409,7 @@ void BKE_scene_free(Scene *sce) BLI_freelistN(&sce->markers); BLI_freelistN(&sce->transform_spaces); BLI_freelistN(&sce->r.layers); + BLI_freelistN(&sce->r.views); if (sce->toolsettings) { if (sce->toolsettings->vpaint) { @@ -415,6 +435,8 @@ void BKE_scene_free(Scene *sce) } DAG_scene_free(sce); + if (sce->depsgraph) + DEG_graph_free(sce->depsgraph); if (sce->nodetree) { ntreeFreeTree(sce->nodetree); @@ -426,7 +448,7 @@ void BKE_scene_free(Scene *sce) if (sce->fps_info) MEM_freeN(sce->fps_info); - sound_destroy_scene(sce); + BKE_sound_destroy_scene(sce); BKE_color_managed_view_settings_free(&sce->view_settings); } @@ -437,6 +459,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name) ParticleEditSettings *pset; int a; const char *colorspace_name; + SceneRenderView *srv; sce = BKE_libblock_alloc(bmain, ID_SCE, name); sce->lay = sce->layact = 1; @@ -628,7 +651,16 @@ Scene *BKE_scene_add(Main *bmain, const char *name) /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */ BKE_scene_add_render_layer(sce, NULL); - + + /* multiview - stereo */ + BKE_scene_add_render_view(sce, STEREO_LEFT_NAME); + srv = sce->r.views.first; + BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix)); + + BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME); + srv = sce->r.views.last; + BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix)); + /* game data */ sce->gm.stereoflag = STEREO_NOSTEREO; sce->gm.stereomode = STEREO_ANAGLYPH; @@ -665,7 +697,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->gm.recastData.cellsize = 0.3f; sce->gm.recastData.cellheight = 0.2f; - sce->gm.recastData.agentmaxslope = M_PI / 2; + sce->gm.recastData.agentmaxslope = M_PI_4; sce->gm.recastData.agentmaxclimb = 0.9f; sce->gm.recastData.agentheight = 2.0f; sce->gm.recastData.agentradius = 0.6f; @@ -677,9 +709,12 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->gm.recastData.detailsampledist = 6.0f; sce->gm.recastData.detailsamplemaxerror = 1.0f; + sce->gm.lodflag = SCE_LOD_USE_HYST; + sce->gm.scehysteresis = 10; + sce->gm.exitkey = 218; // Blender key code for ESC - sound_create_scene(sce); + BKE_sound_create_scene(sce); /* color management */ colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER); @@ -698,6 +733,19 @@ Scene *BKE_scene_add(Main *bmain, const char *name) return sce; } +Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) +{ + Base *base; + + for (base = scene->base.first; base; base = base->next) { + if (STREQ(base->object->id.name + 2, name)) { + break; + } + } + + return base; +} + Base *BKE_scene_base_find(Scene *scene, Object *ob) { return BLI_findptr(&scene->base, ob, offsetof(Base, object)); @@ -767,33 +815,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) return NULL; } -static void scene_unlink_space_node(SpaceNode *snode, Scene *sce) -{ - if (snode->id == &sce->id) { - /* nasty DNA logic for SpaceNode: - * ideally should be handled by editor code, but would be bad level call - */ - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; - MEM_freeN(path); - } - BLI_listbase_clear(&snode->treepath); - - snode->id = NULL; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; - } -} - -static void scene_unlink_space_buts(SpaceButs *sbuts, Scene *sce) -{ - if (sbuts->pinid == &sce->id) { - sbuts->pinid = NULL; - } -} - void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) { Scene *sce1; @@ -818,24 +839,11 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) /* all screens */ for (screen = bmain->screen.first; screen; screen = screen->id.next) { - ScrArea *area; - - if (screen->scene == sce) + if (screen->scene == sce) { screen->scene = newsce; - - for (area = screen->areabase.first; area; area = area->next) { - SpaceLink *space_link; - for (space_link = area->spacedata.first; space_link; space_link = space_link->next) { - switch (space_link->spacetype) { - case SPACE_NODE: - scene_unlink_space_node((SpaceNode *)space_link, sce); - break; - case SPACE_BUTS: - scene_unlink_space_buts((SpaceButs *)space_link, sce); - break; - } - } } + + /* editors are handled by WM_main_remove_editor_id_reference */ } BKE_libblock_free(bmain, sce); @@ -1140,13 +1148,13 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) /* This function is needed to cope with fractional frames - including two Blender rendering features * mblur (motion blur that renders 'subframes' and blurs them together), and fields rendering. */ -float BKE_scene_frame_get(Scene *scene) +float BKE_scene_frame_get(const Scene *scene) { return BKE_scene_frame_get_from_ctime(scene, scene->r.cfra); } /* This function is used to obtain arbitrary fractional frames */ -float BKE_scene_frame_get_from_ctime(Scene *scene, const float frame) +float BKE_scene_frame_get_from_ctime(const Scene *scene, const float frame) { float ctime = frame; ctime += scene->r.subframe; @@ -1165,6 +1173,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) scene->r.cfra = (int)intpart; } +#ifdef WITH_LEGACY_DEPSGRAPH /* drivers support/hacks * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render * - these are always run since the depsgraph can't handle non-object data @@ -1265,6 +1274,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen } } } +#endif /* WITH_LEGACY_DEPSGRAPH */ /* That's like really a bummer, because currently animation data for armatures * might want to use pose, and pose might be missing on the object. @@ -1294,6 +1304,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain) } #endif +#ifdef WITH_LEGACY_DEPSGRAPH static void scene_rebuild_rbw_recursive(Scene *scene, float ctime) { if (scene->set) @@ -1311,12 +1322,18 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) if (BKE_scene_check_rigidbody_active(scene)) BKE_rigidbody_do_simulation(scene, ctime); } +#endif /* Used to visualize CPU threads activity during threaded object update, * would pollute STDERR with whole bunch of timing information which then * could be parsed and nicely visualized. */ -#undef DETAILED_ANALYSIS_OUTPUT +#ifdef WITH_LEGACY_DEPSGRAPH +# undef DETAILED_ANALYSIS_OUTPUT +#else +/* ALWAYS KEEY DISABLED! */ +# undef DETAILED_ANALYSIS_OUTPUT +#endif /* Mballs evaluation uses BKE_scene_base_iter_next which calls * duplilist for all objects in the scene. This leads to conflict @@ -1328,6 +1345,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) */ #define MBALL_SINGLETHREAD_HACK +#ifdef WITH_LEGACY_DEPSGRAPH typedef struct StatisicsEntry { struct StatisicsEntry *next, *prev; Object *object; @@ -1342,13 +1360,13 @@ typedef struct ThreadedObjectUpdateState { Scene *scene_parent; double base_time; - /* Execution statistics */ - ListBase statistics[BLENDER_MAX_THREADS]; - bool has_updated_objects; - #ifdef MBALL_SINGLETHREAD_HACK bool has_mballs; #endif + + /* Execution statistics */ + bool has_updated_objects; + ListBase *statistics; } ThreadedObjectUpdateState; static void scene_update_object_add_task(void *node, void *user_data); @@ -1417,6 +1435,8 @@ static void scene_update_object_func(TaskPool *pool, void *taskdata, int threadi if (add_to_stats) { StatisicsEntry *entry; + BLI_assert(threadid < BLI_pool_get_num_threads(pool)); + entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics"); entry->object = object; entry->start_time = start_time; @@ -1446,6 +1466,7 @@ static void scene_update_object_add_task(void *node, void *user_data) static void print_threads_statistics(ThreadedObjectUpdateState *state) { int i, tot_thread; + double finish_time; if ((G.debug & G_DEBUG_DEPSGRAPH) == 0) { return; @@ -1471,6 +1492,7 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state) } } #else + finish_time = PIL_check_seconds_timer(); tot_thread = BLI_system_thread_count(); for (i = 0; i < tot_thread; i++) { @@ -1500,6 +1522,9 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state) BLI_freelistN(&state->statistics[i]); } + if (state->has_updated_objects) { + printf("Scene update in %f sec\n", finish_time - state->base_time); + } #endif } @@ -1545,7 +1570,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene /* Those are only needed when blender is run with --debug argument. */ if (G.debug & G_DEBUG_DEPSGRAPH) { - memset(state.statistics, 0, sizeof(state.statistics)); + const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler); + state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics), + "scene update objects stats"); state.has_updated_objects = false; state.base_time = PIL_check_seconds_timer(); } @@ -1555,6 +1582,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene #endif task_pool = BLI_task_pool_create(task_scheduler, &state); + if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { + BLI_pool_set_num_threads(task_pool, 1); + } DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool); BLI_task_pool_work_and_wait(task_pool); @@ -1562,6 +1592,7 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene if (G.debug & G_DEBUG_DEPSGRAPH) { print_threads_statistics(&state); + MEM_freeN(state.statistics); } /* We do single thread pass to update all the objects which are in cyclic dependency. @@ -1607,6 +1638,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma BKE_mask_update_scene(bmain, scene); } +#endif /* WITH_LEGACY_DEPSGRAPH */ static bool check_rendered_viewport_visible(Main *bmain) { @@ -1658,13 +1690,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; - +#ifdef WITH_LEGACY_DEPSGRAPH + bool use_new_eval = !DEG_depsgraph_use_legacy(); +#endif + /* keep this first */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); /* (re-)build dependency graph if needed */ - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) + for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) { DAG_scene_relations_update(bmain, sce_iter); + /* Uncomment this to check if graph was properly tagged for update. */ +#if 0 +#ifdef WITH_LEGACY_DEPSGRAPH + if (use_new_eval) +#endif + { + DAG_scene_relations_validate(bmain, sce_iter); + } +#endif + } /* flush editing data if needed */ prepare_mesh_for_viewport_render(bmain, scene); @@ -1685,9 +1730,19 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ - scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); +#ifdef WITH_LEGACY_DEPSGRAPH + if (use_new_eval) { + DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); + } + else { + scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); + } +#else + DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); +#endif + /* update sound system animation (TODO, move to depsgraph) */ - sound_update_scene(bmain, scene); + BKE_sound_update_scene(bmain, scene); /* extra call here to recalc scene animation (for sequencer) */ { @@ -1703,7 +1758,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc * Need to do this so changing material settings from the graph/dopesheet * will update stuff in the viewport. */ - if (DAG_id_type_tagged(bmain, ID_MA)) { +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) { Material *material; float ctime = BKE_scene_frame_get(scene); @@ -1718,7 +1774,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc } /* Also do the same for node trees. */ - if (DAG_id_type_tagged(bmain, ID_NT)) { + if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) { float ctime = BKE_scene_frame_get(scene); FOREACH_NODETREE(bmain, ntree, id) @@ -1729,9 +1785,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc } FOREACH_NODETREE_END } +#endif /* notify editors and python about recalc */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); + + /* Inform editors about possible changes. */ DAG_ids_check_recalc(bmain, scene, false); /* clear recalc flags */ @@ -1751,6 +1810,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, #ifdef DETAILED_ANALYSIS_OUTPUT double start_time = PIL_check_seconds_timer(); #endif +#ifdef WITH_LEGACY_DEPSGRAPH + bool use_new_eval = !DEG_depsgraph_use_legacy(); +#else + /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */ + (void) do_invisible_flush; +#endif /* keep this first */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE); @@ -1760,28 +1825,39 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, * call this at the start so modifiers with textures don't lag 1 frame */ BKE_image_update_frame(bmain, sce->r.cfra); +#ifdef WITH_LEGACY_DEPSGRAPH /* rebuild rigid body worlds before doing the actual frame update * this needs to be done on start frame but animation playback usually starts one frame later * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive */ - scene_rebuild_rbw_recursive(sce, ctime); - - sound_set_cfra(sce->r.cfra); + if (!use_new_eval) { + scene_rebuild_rbw_recursive(sce, ctime); + } +#endif + + BKE_sound_set_cfra(sce->r.cfra); /* clear animation overrides */ /* XXX TODO... */ + /* tag cached objects */ + BKE_cache_library_dag_recalc_tag(eval_ctx, bmain); + for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set) DAG_scene_relations_update(bmain, sce_iter); - /* flush recalc flags to dependencies, if we were only changing a frame - * this would not be necessary, but if a user or a script has modified - * some datablock before BKE_scene_update_tagged was called, we need the flush */ - DAG_ids_flush_tagged(bmain); +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + /* flush recalc flags to dependencies, if we were only changing a frame + * this would not be necessary, but if a user or a script has modified + * some datablock before BKE_scene_update_tagged was called, we need the flush */ + DAG_ids_flush_tagged(bmain); - /* Following 2 functions are recursive - * so don't call within 'scene_update_tagged_recursive' */ - DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still + /* Following 2 functions are recursive + * so don't call within 'scene_update_tagged_recursive' */ + DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still + } +#endif BKE_mask_evaluate_all_masks(bmain, ctime, true); @@ -1795,8 +1871,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, * can be overridden by settings from Scene, which owns the Texture through a hierarchy * such as Scene->World->MTex/Texture) can still get correctly overridden. */ - BKE_animsys_evaluate_all_animation(bmain, sce, ctime); - /*...done with recursive funcs */ +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + BKE_animsys_evaluate_all_animation(bmain, sce, ctime); + /*...done with recursive funcs */ + } +#endif /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later * when trying to find materials with drivers that need evaluating [#32017] @@ -1806,19 +1886,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, /* run rigidbody sim */ /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */ - scene_do_rb_simulation_recursive(sce, ctime); - +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + scene_do_rb_simulation_recursive(sce, ctime); + } +#endif + /* BKE_object_handle_update() on all objects, groups and sets */ - scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); +#ifdef WITH_LEGACY_DEPSGRAPH + if (use_new_eval) { + DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); + } + else { + scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); + } +#else + DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); +#endif + /* update sound system animation (TODO, move to depsgraph) */ - sound_update_scene(bmain, sce); + BKE_sound_update_scene(bmain, sce); - scene_depsgraph_hack(eval_ctx, sce, sce); +#ifdef WITH_LEGACY_DEPSGRAPH + if (!use_new_eval) { + scene_depsgraph_hack(eval_ctx, sce, sce); + } +#endif /* notify editors and python about recalc */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST); BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST); + /* Inform editors about possible changes. */ DAG_ids_check_recalc(bmain, sce, true); /* clear recalc flags */ @@ -1829,6 +1928,45 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, #endif } +void BKE_scene_update_group_for_newframe(EvaluationContext *eval_ctx, + Main *bmain, + Scene *scene, + Group *group, + unsigned int lay) +{ + float ctime = BKE_scene_frame_get(scene); + Scene *sce_iter; + + /* Step 1: Preparation, same as in regular frame update. */ + BKE_image_update_frame(bmain, scene->r.cfra); + scene_rebuild_rbw_recursive(scene, ctime); + BKE_cache_library_dag_recalc_tag(eval_ctx, bmain); + for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) { + DAG_scene_relations_update(bmain, sce_iter); + } + + /* Step 2: Tag objects which we need to update. */ + DAG_ids_flush_tagged(bmain); + DAG_scene_update_group_flags(bmain, scene, group, lay, true, false); + + /* Step 3: Update animation. */ +#ifdef POSE_ANIMATION_WORKAROUND + scene_armature_depsgraph_workaround(bmain); +#endif + BKE_animsys_evaluate_all_animation(bmain, scene, ctime); + + /* Step 4: Actual evaluation. */ + BKE_main_id_tag_idcode(bmain, ID_MA, false); + BKE_main_id_tag_idcode(bmain, ID_LA, false); + scene_do_rb_simulation_recursive(scene, ctime); + scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); + scene_depsgraph_hack(eval_ctx, scene, scene); + + /* Step 5: Cleanup after evaluaiton. */ + DAG_ids_check_recalc(bmain, scene, true); + DAG_ids_clear_recalc(bmain); +} + /* return default layer, also used to patch old files */ SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name) { @@ -1889,25 +2027,71 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer * return true; } +/* return default view */ +SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name) +{ + SceneRenderView *srv; + + if (!name) + name = DATA_("RenderView"); + + srv = MEM_callocN(sizeof(SceneRenderView), "new render view"); + BLI_strncpy(srv->name, name, sizeof(srv->name)); + BLI_uniquename(&sce->r.views, srv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(srv->name)); + BLI_addtail(&sce->r.views, srv); + + return srv; +} + +bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv) +{ + const int act = BLI_findindex(&scene->r.views, srv); + + if (act == -1) { + return false; + } + else if (scene->r.views.first == scene->r.views.last) { + /* ensure 1 view is kept */ + return false; + } + + BLI_remlink(&scene->r.views, srv); + MEM_freeN(srv); + + scene->r.actview = 0; + + return true; +} + /* render simplification */ -int get_render_subsurf_level(RenderData *r, int lvl) +int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render) { - if (r->mode & R_SIMPLIFY) - return min_ii(r->simplify_subsurf, lvl); - else + if (r->mode & R_SIMPLIFY) { + if (for_render) + return min_ii(r->simplify_subsurf_render, lvl); + else + return min_ii(r->simplify_subsurf, lvl); + } + else { return lvl; + } } -int get_render_child_particle_number(RenderData *r, int num) +int get_render_child_particle_number(const RenderData *r, int num, bool for_render) { - if (r->mode & R_SIMPLIFY) - return (int)(r->simplify_particles * num); - else + if (r->mode & R_SIMPLIFY) { + if (for_render) + return (int)(r->simplify_particles_render * num); + else + return (int)(r->simplify_particles * num); + } + else { return num; + } } -int get_render_shadow_samples(RenderData *r, int samples) +int get_render_shadow_samples(const RenderData *r, int samples) { if ((r->mode & R_SIMPLIFY) && samples > 0) return min_ii(r->simplify_shadowsamples, samples); @@ -1915,7 +2099,7 @@ int get_render_shadow_samples(RenderData *r, int samples) return samples; } -float get_render_aosss_error(RenderData *r, float error) +float get_render_aosss_error(const RenderData *r, float error) { if (r->mode & R_SIMPLIFY) return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error; @@ -1947,18 +2131,24 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base) return NULL; } -bool BKE_scene_use_new_shading_nodes(Scene *scene) +bool BKE_scene_use_new_shading_nodes(const Scene *scene) { - RenderEngineType *type = RE_engines_find(scene->r.engine); + const RenderEngineType *type = RE_engines_find(scene->r.engine); return (type && type->flag & RE_USE_SHADING_NODES); } -bool BKE_scene_uses_blender_internal(struct Scene *scene) +bool BKE_scene_use_shading_nodes_custom(Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); +} + +bool BKE_scene_uses_blender_internal(const Scene *scene) { return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER); } -bool BKE_scene_uses_blender_game(struct Scene *scene) +bool BKE_scene_uses_blender_game(const Scene *scene) { return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME); } @@ -2059,3 +2249,283 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl return value; } } + +/******************** multiview *************************/ + +size_t BKE_scene_multiview_num_views_get(const RenderData *rd) +{ + SceneRenderView *srv; + size_t totviews = 0; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return 1; + + if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name)); + if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) { + totviews++; + } + + srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name)); + if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) { + totviews++; + } + } + else { + for (srv = rd->views.first; srv; srv = srv->next) { + if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) { + totviews++; + } + } + } + return totviews; +} + +bool BKE_scene_multiview_is_stereo3d(const RenderData *rd) +{ + SceneRenderView *srv[2]; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return false; + + srv[0] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name)); + srv[1] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name)); + + return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) && + srv[1] && ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0)); +} + +/* return whether to render this SceneRenderView */ +bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv) +{ + if (srv == NULL) + return false; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return false; + + if ((srv->viewflag & SCE_VIEW_DISABLE)) + return false; + + if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) + return true; + + /* SCE_VIEWS_SETUP_BASIC */ + if (STREQ(srv->name, STEREO_LEFT_NAME) || + STREQ(srv->name, STEREO_RIGHT_NAME)) + { + return true; + } + + return false; +} + +/* return true if viewname is the first or if the name is NULL or not found */ +bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname) +{ + SceneRenderView *srv; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return true; + + if ((!viewname) || (!viewname[0])) + return true; + + for (srv = rd->views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv)) { + return STREQ(viewname, srv->name); + } + } + + return true; +} + +/* return true if viewname is the last or if the name is NULL or not found */ +bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname) +{ + SceneRenderView *srv; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return true; + + if ((!viewname) || (!viewname[0])) + return true; + + for (srv = rd->views.last; srv; srv = srv->prev) { + if (BKE_scene_multiview_is_render_view_active(rd, srv)) { + return STREQ(viewname, srv->name); + } + } + + return true; +} + +SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, const int view_id) +{ + SceneRenderView *srv; + size_t nr; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return NULL; + + nr = 0; + for (srv = rd->views.first, nr = 0; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv)) { + if (nr++ == view_id) + return srv; + } + } + return srv; +} + +const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const int view_id) +{ + SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id); + + if (srv) + return srv->name; + else + return ""; +} + +size_t BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname) +{ + SceneRenderView *srv; + size_t nr; + + if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0)) + return 0; + + if ((!viewname) || (!viewname[0])) + return 0; + + nr = 0; + for (srv = rd->views.first, nr = 0; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv)) { + if (STREQ(viewname, srv->name)) { + return nr; + } + else { + nr += 1; + } + } + } + + return 0; +} + +void BKE_scene_multiview_filepath_get( + SceneRenderView *srv, const char *filepath, + char *r_filepath) +{ + BLI_strncpy(r_filepath, filepath, FILE_MAX); + BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, ""); +} + +/** + * When multiview is not used the filepath is as usual (e.g., ``Image.jpg``). + * When multiview is on, even if only one view is enabled the view is incorporated + * into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render + * individual views. + */ +void BKE_scene_multiview_view_filepath_get( + const RenderData *rd, const char *filepath, const char *viewname, + char *r_filepath) +{ + SceneRenderView *srv; + char suffix[FILE_MAX]; + + srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name)); + if (srv) + BLI_strncpy(suffix, srv->suffix, sizeof(suffix)); + else + BLI_strncpy(suffix, viewname, sizeof(suffix)); + + BLI_strncpy(r_filepath, filepath, FILE_MAX); + BLI_path_suffix(r_filepath, FILE_MAX, suffix, ""); +} + +const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char *viewname) +{ + SceneRenderView *srv; + + if ((viewname == NULL) || (viewname[0] == '\0')) + return viewname; + + srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name)); + if (srv) + return srv->suffix; + else + return viewname; +} + +const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const size_t view_id) +{ + if ((rd->scemode & R_MULTIVIEW) == 0) { + return ""; + } + else { + const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id); + return BKE_scene_multiview_view_suffix_get(rd, viewname); + } +} + +void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *rprefix, char **rext) +{ + SceneRenderView *srv; + size_t index_act; + char *suf_act; + const char delims[] = {'.', '\0'}; + + rprefix[0] = '\0'; + + /* begin of extension */ + index_act = BLI_str_rpartition(name, delims, rext, &suf_act); + BLI_assert(index_act > 0); + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { + size_t len = strlen(srv->suffix); + if (STREQLEN(*rext - len, srv->suffix, len)) { + BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1); + break; + } + } + } +} + +void BKE_scene_multiview_videos_dimensions_get( + const RenderData *rd, const size_t width, const size_t height, + size_t *r_width, size_t *r_height) +{ + if ((rd->scemode & R_MULTIVIEW) && + rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) + { + IMB_stereo3d_write_dimensions( + rd->im_format.stereo3d_format.display_mode, + (rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0, + width, height, + r_width, r_height); + } + else { + *r_width = width; + *r_height = height; + } +} + +size_t BKE_scene_multiview_num_videos_get(const RenderData *rd) +{ + if (BKE_imtype_is_movie(rd->im_format.imtype) == false) + return 0; + + if ((rd->scemode & R_MULTIVIEW) == 0) + return 1; + + if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { + return 1; + } + else { + /* R_IMF_VIEWS_INDIVIDUAL */ + return BKE_scene_multiview_num_views_get(rd); + } +} diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index ebbfc3d2a40..83aac79ae0b 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -276,6 +276,19 @@ void BKE_spacedata_draw_locks(int set) } } +static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL; + +void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)) +{ + spacedata_id_unref_cb = func; +} + +void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id) +{ + if (spacedata_id_unref_cb) { + spacedata_id_unref_cb(sl, id); + } +} /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) @@ -416,6 +429,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa) return NULL; } +ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y) +{ + ARegion *ar_found = NULL; + if (sa) { + ARegion *ar; + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) { + if (BLI_rcti_isect_pt(&ar->winrct, x, y)) { + ar_found = ar; + break; + } + } + } + } + return ar_found; +} + /** * \note, ideally we can get the area from the context, * there are a few places however where this isn't practical. @@ -499,6 +529,23 @@ unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const stru return BKE_screen_view3d_layer_active_ex(v3d, scene, true); } +/** + * Accumulate all visible layers on this screen. + */ +unsigned int BKE_screen_view3d_layer_all(const bScreen *sc) +{ + const ScrArea *sa; + unsigned int lay = 0; + for (sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_VIEW3D) { + View3D *v3d = sa->spacedata.first; + lay |= v3d->lay; + } + } + + return lay; +} + void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) { int bit; @@ -521,8 +568,8 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) if ((v3d->lay & v3d->layact) == 0) { for (bit = 0; bit < 32; bit++) { - if (v3d->lay & (1 << bit)) { - v3d->layact = 1 << bit; + if (v3d->lay & (1u << bit)) { + v3d->layact = (1u << bit); break; } } diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index 05d6bf136a4..69ba7618981 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -35,6 +35,7 @@ #include "MEM_guardedalloc.h" #include "DNA_sequence_types.h" +#include "DNA_scene_types.h" #include "IMB_moviecache.h" #include "IMB_imbuf.h" @@ -43,6 +44,7 @@ #include "BLI_listbase.h" #include "BKE_sequencer.h" +#include "BKE_scene.h" typedef struct SeqCacheKey { struct Sequence *seq; @@ -79,7 +81,9 @@ static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b) (a->bmain != b->bmain) || (a->scene != b->scene) || (a->motion_blur_shutter != b->motion_blur_shutter) || - (a->motion_blur_samples != b->motion_blur_samples)); + (a->motion_blur_samples != b->motion_blur_samples) || + (a->scene->r.views_format != b->scene->r.views_format) || + (a->view_id != b->view_id)); } static unsigned int seq_hash_render_data(const SeqRenderData *a) @@ -91,6 +95,7 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a) rval ^= ((intptr_t) a->scene) << 6; rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10; rval ^= a->motion_blur_samples << 24; + rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 32; return rval; } diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 6157d63047e..a8787d44914 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -52,9 +52,6 @@ #include "RNA_access.h" -/* TODO(sergey): Could be considered a bad level call, but - * need this for gaussian table. - */ #include "RE_pipeline.h" static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index b78529f51b4..f543a9f4c65 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -77,9 +77,9 @@ typedef struct ModifierThread { } ModifierThread; -static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, bool make_float) +static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, int fra_offset, bool make_float) { - return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, make_float); + return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, fra_offset, make_float); } static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v) @@ -531,15 +531,11 @@ static void maskmodifier_apply_threaded(int width, int height, unsigned char *re } } -static void maskmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask) +static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask) { - BrightContrastModifierData *bcmd = (BrightContrastModifierData *) smd; - BrightContrastThreadData data; - - data.bright = bcmd->bright; - data.contrast = bcmd->contrast; + // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd; - modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, &data); + modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL); } static SequenceModifierTypeInfo seqModifier_Mask = { @@ -567,7 +563,7 @@ static void sequence_modifier_type_info_init(void) #undef INIT_TYPE } -SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type) +const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type) { if (!modifierTypesInit) { sequence_modifier_type_info_init(); @@ -580,7 +576,7 @@ SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type) SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type) { SequenceModifierData *smd; - SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type); + const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type); smd = MEM_callocN(smti->struct_size, "sequence modifier"); @@ -627,7 +623,7 @@ void BKE_sequence_modifier_clear(Sequence *seq) void BKE_sequence_modifier_free(SequenceModifierData *smd) { - SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); if (smti && smti->free_data) { smti->free_data(smd); @@ -638,7 +634,7 @@ void BKE_sequence_modifier_free(SequenceModifierData *smd) void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd) { - SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); BLI_uniquename(&seq->modifiers, smd, CTX_DATA_(BLF_I18NCONTEXT_ID_SEQUENCE, smti->name), '.', offsetof(SequenceModifierData, name), sizeof(smd->name)); @@ -660,7 +656,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence } for (smd = seq->modifiers.first; smd; smd = smd->next) { - SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); /* could happen if modifier is being removed or not exists in current version of blender */ if (!smti) @@ -671,7 +667,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence continue; if (smti->apply) { - ImBuf *mask = modifier_mask_get(smd, context, cfra, ibuf->rect_float != NULL); + ImBuf *mask = modifier_mask_get(smd, context, cfra, seq->start, ibuf->rect_float != NULL); if (processed_ibuf == ibuf) processed_ibuf = IMB_dupImBuf(ibuf); @@ -696,7 +692,7 @@ void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq) for (smd = seq->modifiers.first; smd; smd = smd->next) { SequenceModifierData *smdn; - SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); smdn = MEM_dupallocN(smd); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index ee41c2b3208..1cff097df5e 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -53,6 +53,12 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#ifdef WIN32 +# include "BLI_winstuff.h" +#else +# include <unistd.h> +#endif + #include "BLF_translation.h" #include "BKE_animsys.h" @@ -66,6 +72,7 @@ #include "BKE_scene.h" #include "BKE_mask.h" #include "BKE_library.h" +#include "BKE_idprop.h" #include "RNA_access.h" @@ -88,6 +95,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra); static void seq_free_animdata(Scene *scene, Sequence *seq); static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float); +static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview); +static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id); /* **** XXX ******** */ #define SELECT 1 @@ -180,10 +189,7 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach if (seq->strip) seq_free_strip(seq->strip); - if (seq->anim) { - IMB_free_anim(seq->anim); - seq->anim = NULL; - } + BKE_sequence_free_anim(seq); if (seq->type & SEQ_TYPE_EFFECT) { struct SeqEffectHandle sh = BKE_sequence_get_effect(seq); @@ -195,6 +201,10 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach ((ID *)seq->sound)->us--; } + if (seq->stereo3d_format) { + MEM_freeN(seq->stereo3d_format); + } + /* clipboard has no scene and will never have a sound handle or be active * same goes to sequences copy for proxy rebuild job */ @@ -205,11 +215,16 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach ed->act_seq = NULL; if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) - sound_remove_scene_sound(scene, seq->scene_sound); + BKE_sound_remove_scene_sound(scene, seq->scene_sound); seq_free_animdata(scene, seq); } + if (seq->prop) { + IDP_FreeProperty(seq->prop); + MEM_freeN(seq->prop); + } + /* free modifiers */ BKE_sequence_modifier_clear(seq); @@ -234,6 +249,22 @@ void BKE_sequence_free(Scene *scene, Sequence *seq) BKE_sequence_free_ex(scene, seq, true); } +/* Function to free imbuf and anim data on changes */ +void BKE_sequence_free_anim(Sequence *seq) +{ + while (seq->anims.last) { + StripAnim *sanim = seq->anims.last; + + if (sanim->anim) { + IMB_free_anim(sanim->anim); + sanim->anim = NULL; + } + + BLI_freelinkN(&seq->anims, sanim); + } + BLI_listbase_clear(&seq->anims); +} + /* cache must be freed before calling this function * since it leaves the seqbase in an invalid state */ static void seq_free_sequence_recurse(Scene *scene, Sequence *seq) @@ -316,7 +347,7 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt) { id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name)); if (id_restore == NULL) { - id_restore = sound_new_file(bmain, ((bSound *)ID_PT)->name); + id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name); (ID_PT)->newid = id_restore; /* reuse next time */ } break; @@ -531,6 +562,7 @@ void BKE_sequencer_new_render_data( r_context->motion_blur_shutter = 0; r_context->skip_cache = false; r_context->is_proxy_render = false; + r_context->view_id = 0; } /* ************************* iterator ************************** */ @@ -652,7 +684,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metase if (seq->start + seq->len - seq->endofs > end) endofs = seq->start + seq->len - end; - sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs, + BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs, seq->start + seq->len - endofs, startofs + seq->anim_startofs); } } @@ -765,10 +797,17 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) } } +static void seq_multiview_name(Scene *scene, const size_t view_id, const char *prefix, + const char *ext, char *r_path, size_t r_size) +{ + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); + BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext); +} + /* note: caller should run BKE_sequence_calc(scene, seq) after */ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_range) { - char str[FILE_MAX]; + char path[FILE_MAX]; int prev_startdisp = 0, prev_enddisp = 0; /* note: don't rename the strip, will break animation curves */ @@ -801,22 +840,67 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r break; } case SEQ_TYPE_MOVIE: - BLI_join_dirfile(str, sizeof(str), seq->strip->dir, + { + StripAnim *sanim; + bool is_multiview_loaded = false; + const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && + (scene->r.scemode & R_MULTIVIEW) != 0; + + BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(str, G.main->name); + BLI_path_abs(path, G.main->name); + + BKE_sequence_free_anim(seq); + + if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) { + char prefix[FILE_MAX]; + char *ext = NULL; + size_t totfiles = seq_num_files(scene, seq->views_format, true); + int i = 0; + + BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext); + + if (prefix[0] != '\0') { + for (i = 0; i < totfiles; i++) { + struct anim *anim; + char str[FILE_MAX]; - if (seq->anim) IMB_free_anim(seq->anim); + seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX); + anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); - seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), - seq->streamindex, seq->strip->colorspace_settings.name); + if (anim) { + seq_anim_add_suffix(scene, anim, i); + sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim"); + BLI_addtail(&seq->anims, sanim); + sanim->anim = anim; + } + } + is_multiview_loaded = true; + } + } + + if (is_multiview_loaded == false) { + struct anim *anim; + anim = openanim(path, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + if (anim) { + sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim"); + BLI_addtail(&seq->anims, sanim); + sanim->anim = anim; + } + } - if (!seq->anim) { + /* use the first video as reference for everything */ + sanim = seq->anims.first; + + if ((!sanim) || (!sanim->anim)) { return; } - seq->len = IMB_anim_get_duration(seq->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN); - - seq->anim_preseek = IMB_anim_get_preseek(seq->anim); + seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN); + + seq->anim_preseek = IMB_anim_get_preseek(sanim->anim); seq->len -= seq->anim_startofs; seq->len -= seq->anim_endofs; @@ -824,6 +908,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r seq->len = 0; } break; + } case SEQ_TYPE_MOVIECLIP: if (seq->clip == NULL) return; @@ -1103,30 +1188,25 @@ static void make_black_ibuf(ImBuf *ibuf) } } -static void multibuf(ImBuf *ibuf, float fmul) +static void multibuf(ImBuf *ibuf, const float fmul) { char *rt; float *rt_float; - int a, mul, icol; + int a; - mul = (int)(256.0f * fmul); rt = (char *)ibuf->rect; rt_float = ibuf->rect_float; if (rt) { + const int imul = (int)(256.0f * fmul); a = ibuf->x * ibuf->y; while (a--) { + rt[0] = min_ii((imul * rt[0]) >> 8, 255); + rt[1] = min_ii((imul * rt[1]) >> 8, 255); + rt[2] = min_ii((imul * rt[2]) >> 8, 255); + rt[3] = min_ii((imul * rt[3]) >> 8, 255); - icol = (mul * rt[0]) >> 8; - if (icol > 254) rt[0] = 255; else rt[0] = icol; - icol = (mul * rt[1]) >> 8; - if (icol > 254) rt[1] = 255; else rt[1] = icol; - icol = (mul * rt[2]) >> 8; - if (icol > 254) rt[2] = 255; else rt[2] = icol; - icol = (mul * rt[3]) >> 8; - if (icol > 254) rt[3] = 255; else rt[3] = icol; - rt += 4; } } @@ -1318,6 +1398,7 @@ typedef struct SeqIndexBuildContext { int size_flags; int quality; bool overwrite; + size_t view_id; Main *bmain; Scene *scene; @@ -1357,54 +1438,164 @@ static double seq_rendersize_to_scale_factor(int size) return 0.25; } -static void seq_open_anim_file(Sequence *seq, bool openfile) +/* the number of files will vary according to the stereo format */ +static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview) +{ + if (!is_multiview) { + return 1; + } + else if (views_format == R_IMF_VIEWS_STEREO_3D) { + return 1; + } + /* R_IMF_VIEWS_INDIVIDUAL */ + else { + return BKE_scene_multiview_num_views_get(&scene->r); + } +} + +static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir) { + char dir[FILE_MAX]; + char fname[FILE_MAXFILE]; + + IMB_anim_get_fname(anim, fname, FILE_MAXFILE); + BLI_strncpy(dir, base_dir, sizeof(dir)); + BLI_path_append(dir, sizeof(dir), fname); + IMB_anim_set_index_dir(anim, dir); +} + +static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) +{ + char dir[FILE_MAX]; char name[FILE_MAX]; StripProxy *proxy; + bool use_proxy; + bool is_multiview_loaded = false; + Editing *ed = scene->ed; + const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0; - if (seq->anim != NULL) { + if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) { return; } + /* reset all the previously created anims */ + BKE_sequence_free_anim(seq); + BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(name, G.main->name); - - if (openfile) { - seq->anim = openanim(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), - seq->streamindex, seq->strip->colorspace_settings.name); - } - else { - seq->anim = openanim_noload(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), - seq->streamindex, seq->strip->colorspace_settings.name); - } - if (seq->anim == NULL) { - return; + proxy = seq->strip->proxy; + + use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 || + (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE)); + + if (use_proxy) { + if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) { + if (ed->proxy_dir[0] == 0) + BLI_strncpy(dir, "//BL_proxy", sizeof(dir)); + else + BLI_strncpy(dir, ed->proxy_dir, sizeof(dir)); + } + else { + BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); + } + BLI_path_abs(dir, G.main->name); } - proxy = seq->strip->proxy; + if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) { + size_t totfiles = seq_num_files(scene, seq->views_format, true); + char prefix[FILE_MAX]; + char *ext = NULL; + int i; - if (proxy == NULL) { - return; + BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext); + + if (prefix[0] != '\0') { + for (i = 0; i < totfiles; i++) { + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i); + char str[FILE_MAX]; + StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim"); + + BLI_addtail(&seq->anims, sanim); + + BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext); + + if (openfile) { + sanim->anim = openanim( + str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + } + else { + sanim->anim = openanim_noload( + str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + } + + if (sanim->anim) { +#if 0 + seq_anim_add_suffix(scene, sanim->anim, i); +#else + /* we already have the suffix */ + IMB_suffix_anim(sanim->anim, suffix); +#endif + } + else { + if (openfile) { + sanim->anim = openanim( + name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + } + else { + sanim->anim = openanim_noload( + name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + } + + /* no individual view files - monoscopic, stereo 3d or exr multiview */ + totfiles = 1; + } + + if (sanim->anim && use_proxy) { + seq_proxy_index_dir_set(sanim->anim, dir); + } + } + is_multiview_loaded = true; + } } - if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) { - char dir[FILE_MAX]; - BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); - BLI_path_abs(dir, G.main->name); + if (is_multiview_loaded == false) { + StripAnim *sanim; + + sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim"); + BLI_addtail(&seq->anims, sanim); - IMB_anim_set_index_dir(seq->anim, dir); + if (openfile) { + sanim->anim = openanim( + name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + } + else { + sanim->anim = openanim_noload( + name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), + seq->streamindex, seq->strip->colorspace_settings.name); + } + + if (sanim->anim && use_proxy) { + seq_proxy_index_dir_set(sanim->anim, dir); + } } } - -static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *name) +static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const size_t view_id) { int frameno; char dir[PROXY_MAXFILE]; + StripAnim *sanim; + char suffix[24] = {'\0'}; - if (!seq->strip->proxy) { + StripProxy *proxy = seq->strip->proxy; + if (!proxy) { return false; } @@ -1416,8 +1607,32 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char * * have both, a directory full of jpeg files and proxy avis, so * sorry folks, please rebuild your proxies... */ - if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR | SEQ_USE_PROXY_CUSTOM_FILE)) { + sanim = BLI_findlink(&seq->anims, view_id); + + if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) { + char fname[FILE_MAXFILE]; + if (ed->proxy_dir[0] == 0) + BLI_strncpy(dir, "//BL_proxy", sizeof(dir)); + else + BLI_strncpy(dir, ed->proxy_dir, sizeof(dir)); + + if (sanim && sanim->anim) { + IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE); + } + else if (seq->type == SEQ_TYPE_IMAGE) { + fname[0] = 0; + } + BLI_path_append(dir, sizeof(dir), fname); + BLI_path_abs(name, G.main->name); + } + else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) { + BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); + } + else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) { + char fname[FILE_MAXFILE]; BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); + IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE); + BLI_path_append(dir, sizeof(dir), fname); } else if (seq->type == SEQ_TYPE_IMAGE) { BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir); @@ -1426,10 +1641,16 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char * return false; } - if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + if (view_id > 0) + BLI_snprintf(suffix, sizeof(suffix), "_%zu", view_id); + + if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim && + ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) + { BLI_join_dirfile(name, PROXY_MAXFILE, - dir, seq->strip->proxy->file); + dir, proxy->file); BLI_path_abs(name, G.main->name); + BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", name, suffix); return true; } @@ -1437,13 +1658,13 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char * /* generate a separate proxy directory for each preview size */ if (seq->type == SEQ_TYPE_IMAGE) { - BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, render_size, - BKE_sequencer_give_stripelem(seq, cfra)->name); + BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy%s", dir, render_size, + 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/####", dir, render_size); + BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix); } BLI_path_abs(name, G.main->name); @@ -1460,45 +1681,48 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c 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; + + if (!(seq->flag & SEQ_USE_PROXY)) { + return NULL; + } /* dirty hack to distinguish 100% render size from PROXY_100 */ if (render_size == 99) { render_size = 100; } - if (!(seq->flag & SEQ_USE_PROXY)) { - return NULL; - } - - size_flags = seq->strip->proxy->build_size_flags; + 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)) { return NULL; } - if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; - if (seq->strip->proxy->anim == NULL) { - if (seq_proxy_get_fname(seq, cfra, render_size, name) == 0) { + if (proxy->anim == NULL) { + if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) { return NULL; } - seq->strip->proxy->anim = openanim(name, IB_rect, 0, - seq->strip->colorspace_settings.name); + proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name); } - if (seq->strip->proxy->anim == NULL) { + if (proxy->anim == NULL) { return NULL; } - seq_open_anim_file(seq, true); + seq_open_anim_file(context->scene, seq, true); + sanim = seq->anims.first; - frameno = IMB_anim_index_get_frame_index(seq->anim, seq->strip->proxy->tc, frameno); + frameno = IMB_anim_index_get_frame_index(sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno); - return IMB_anim_absolute(seq->strip->proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); + return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); } - if (seq_proxy_get_fname(seq, cfra, render_size, name) == 0) { + if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) { return NULL; } @@ -1523,8 +1747,9 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i int rectx, recty; int ok; ImBuf *ibuf_tmp, *ibuf; + Editing *ed = context->scene->ed; - if (!seq_proxy_get_fname(seq, cfra, proxy_render_size, name)) { + if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) { return; } @@ -1539,6 +1764,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) { ibuf = IMB_dupImBuf(ibuf_tmp); + IMB_metadata_copy(ibuf, ibuf_tmp); IMB_freeImBuf(ibuf_tmp); IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty); } @@ -1565,44 +1791,133 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i IMB_freeImBuf(ibuf); } -SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list) +/* returns whether the file this context would read from even exist, if not, don't create the context +*/ +static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const size_t view_id) +{ + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return false; + + if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) { + static char prefix[FILE_MAX]; + static char *ext = NULL; + char str[FILE_MAX]; + + if (view_id == 0) { + char path[FILE_MAX]; + BLI_join_dirfile(path, sizeof(path), seq->strip->dir, + seq->strip->stripdata->name); + BLI_path_abs(path, G.main->name); + BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext); + } + else { + prefix[0] = '\0'; + } + + if (prefix[0] == '\0') + return view_id != 0; + + seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX); + + if (BLI_access(str, R_OK) == 0) + return false; + else + return view_id != 0; + } + return false; +} + +/** This returns the maximum possible number of required contexts +*/ +static size_t seq_proxy_context_count(Sequence *seq, Scene *scene) +{ + size_t num_views = 1; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return 1; + + switch (seq->type) { + case SEQ_TYPE_MOVIE: + { + num_views = BLI_listbase_count(&seq->anims); + break; + } + case SEQ_TYPE_IMAGE: + { + switch (seq->views_format) { + case R_IMF_VIEWS_INDIVIDUAL: + num_views = BKE_scene_multiview_num_views_get(&scene->r); + break; + case R_IMF_VIEWS_STEREO_3D: + num_views = 2; + break; + case R_IMF_VIEWS_MULTIVIEW: + /* not supported at the moment */ + /* pass through */ + default: + num_views = 1; + } + break; + } + } + + return num_views; +} + +void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue) { SeqIndexBuildContext *context; Sequence *nseq; + LinkData *link; + size_t i; + size_t num_files; if (!seq->strip || !seq->strip->proxy) { - return NULL; + return; } if (!(seq->flag & SEQ_USE_PROXY)) { - return NULL; + return; } - context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context"); + num_files = seq_proxy_context_count(seq, scene); + + for (i = 0; i < num_files; i++) { + if (seq_proxy_multiview_context_invalid(seq, scene, i)) + continue; + + context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context"); + + nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0); + + context->tc_flags = nseq->strip->proxy->build_tc_flags; + context->size_flags = nseq->strip->proxy->build_size_flags; + context->quality = nseq->strip->proxy->quality; + context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0; - nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0); + context->bmain = bmain; + context->scene = scene; + context->orig_seq = seq; + context->seq = nseq; - context->tc_flags = nseq->strip->proxy->build_tc_flags; - context->size_flags = nseq->strip->proxy->build_size_flags; - context->quality = nseq->strip->proxy->quality; - context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0; + context->view_id = i; /* only for images */ - context->bmain = bmain; - context->scene = scene; - context->orig_seq = seq; - context->seq = nseq; + link = BLI_genericNodeN(context); + BLI_addtail(queue, link); - if (nseq->type == SEQ_TYPE_MOVIE) { - seq_open_anim_file(nseq, true); + if (nseq->type == SEQ_TYPE_MOVIE) { + StripAnim *sanim; - if (nseq->anim) { - context->index_context = IMB_anim_index_rebuild_context(nseq->anim, - context->tc_flags, context->size_flags, context->quality, - context->overwrite, file_list); + seq_open_anim_file(scene, nseq, true); + sanim = BLI_findlink(&nseq->anims, i); + + if (sanim->anim) { + context->index_context = IMB_anim_index_rebuild_context(sanim->anim, + context->tc_flags, context->size_flags, context->quality, + context->overwrite, file_list); + } } } - - return context; } void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress) @@ -1627,7 +1942,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho } /* that's why it is called custom... */ - if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { return; } @@ -1641,6 +1956,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho render_context.skip_cache = true; render_context.is_proxy_render = true; + render_context.view_id = context->view_id; for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) { if (context->size_flags & IMB_PROXY_25) { @@ -1667,8 +1983,14 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop) { if (context->index_context) { - IMB_close_anim_proxies(context->seq->anim); - IMB_close_anim_proxies(context->orig_seq->anim); + StripAnim *sanim; + + for (sanim = context->seq->anims.first; sanim; sanim = sanim->next) + IMB_close_anim_proxies(sanim->anim); + + for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) + IMB_close_anim_proxies(sanim->anim); + IMB_anim_index_rebuild_finish(context->index_context, stop); } @@ -1947,7 +2269,10 @@ static void *color_balance_do_thread(void *thread_data_v) return NULL; } -ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, int cfra, bool make_float) +/* cfra is offset by fra_offset only in case we are using a real mask. */ +ImBuf *BKE_sequencer_render_mask_input( + const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, + int cfra, int fra_offset, bool make_float) { ImBuf *mask_input = NULL; @@ -1966,7 +2291,7 @@ ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_in } } else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) { - mask_input = seq_render_mask(context, mask_id, cfra, make_float); + mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float); } return mask_input; @@ -2126,6 +2451,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy); sequencer_imbuf_assign_spaces(scene, i); + IMB_metadata_copy(i, ibuf); IMB_freeImBuf(ibuf); ibuf = i; @@ -2179,6 +2505,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra); if (ibuf_new != ibuf) { + IMB_metadata_copy(ibuf_new, ibuf); IMB_freeImBuf(ibuf); ibuf = ibuf_new; } @@ -2201,6 +2528,7 @@ static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq, if (ibuf) { rval = IMB_dupImBuf(ibuf); + IMB_metadata_copy(rval, ibuf); IMB_freeImBuf(ibuf); } @@ -2214,9 +2542,11 @@ static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, floa /* we have to store a copy, since the passed ibuf * could be preprocessed afterwards (thereby silently * changing the cached image... */ - ibuf = IMB_dupImBuf(ibuf); + ImBuf *oibuf = ibuf; + ibuf = IMB_dupImBuf(oibuf); if (ibuf) { + IMB_metadata_copy(ibuf, oibuf); sequencer_imbuf_assign_spaces(context->scene, ibuf); } @@ -2412,6 +2742,237 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc return out; } +static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra) +{ + ImBuf *ibuf = NULL; + char name[FILE_MAX]; + bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && + (context->scene->r.scemode & R_MULTIVIEW) != 0; + StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra); + int flag; + + if (s_elem) { + BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); + BLI_path_abs(name, G.main->name); + } + + flag = IB_rect | IB_metadata; + if (seq->alpha_mode == SEQ_ALPHA_PREMUL) + flag |= IB_alphamode_premul; + + if (!s_elem) { + /* don't do anything */ + } + else if (is_multiview) { + size_t totfiles = seq_num_files(context->scene, seq->views_format, true); + size_t totviews; + struct ImBuf **ibufs_arr; + char prefix[FILE_MAX]; + char *ext = NULL; + int i; + + if (totfiles > 1) { + BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext); + if (prefix[0] == '\0') { + goto monoview_image; + } + } + else { + prefix[0] = '\0'; + } + + totviews = BKE_scene_multiview_num_views_get(&context->scene->r); + ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"); + + for (i = 0; i < totfiles; i++) { + + if (prefix[0] == '\0') { + ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name); + } + else { + char str[FILE_MAX]; + seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX); + ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name); + } + + if (ibufs_arr[i]) { + /* we don't need both (speed reasons)! */ + if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect) + imb_freerectImBuf(ibufs_arr[i]); + } + } + + if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0]) + IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]); + + for (i = 0; i < totviews; i++) { + if (ibufs_arr[i]) { + SeqRenderData localcontext = *context; + localcontext.view_id = i; + + /* all sequencer color is done in SRGB space, linear gives odd crossfades */ + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false); + + if (i != context->view_id) { + copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]); + BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]); + } + } + } + + /* return the original requested ImBuf */ + ibuf = ibufs_arr[context->view_id]; + if (ibuf) { + s_elem->orig_width = ibufs_arr[0]->x; + s_elem->orig_height = ibufs_arr[0]->y; + } + + /* "remove" the others (decrease their refcount) */ + for (i = 0; i < totviews; i++) { + if (ibufs_arr[i] != ibuf) { + IMB_freeImBuf(ibufs_arr[i]); + } + } + + MEM_freeN(ibufs_arr); + } + else { +monoview_image: + if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) { + /* we don't need both (speed reasons)! */ + if (ibuf->rect_float && ibuf->rect) + imb_freerectImBuf(ibuf); + + /* all sequencer color is done in SRGB space, linear gives odd crossfades */ + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); + + s_elem->orig_width = ibuf->x; + s_elem->orig_height = ibuf->y; + } + } + + return ibuf; +} + +static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra) +{ + ImBuf *ibuf = NULL; + StripAnim *sanim; + bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && + (context->scene->r.scemode & R_MULTIVIEW) != 0; + + /* load all the videos */ + seq_open_anim_file(context->scene, seq, false); + + if (is_multiview) { + ImBuf **ibuf_arr; + size_t totviews; + size_t totfiles = seq_num_files(context->scene, seq->views_format, true); + int i; + + if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1)) + goto monoview_movie; + + totviews = BKE_scene_multiview_num_views_get(&context->scene->r); + ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"); + + for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) { + if (sanim->anim) { + IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size); + IMB_anim_set_preseek(sanim->anim, seq->anim_preseek); + + ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, + seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + proxy_size); + + /* fetching for requested proxy size failed, try fetching the original instead */ + if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) { + ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, + seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + IMB_PROXY_NONE); + } + if (ibuf_arr[i]) { + /* we don't need both (speed reasons)! */ + if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect) + imb_freerectImBuf(ibuf_arr[i]); + } + } + } + + if (seq->views_format == R_IMF_VIEWS_STEREO_3D) { + if (ibuf_arr[0]) { + IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]); + } + else { + /* probably proxy hasn't been created yet */ + MEM_freeN(ibuf_arr); + return NULL; + } + } + + for (i = 0; i < totviews; i++) { + SeqRenderData localcontext = *context; + localcontext.view_id = i; + + if (ibuf_arr[i]) { + /* all sequencer color is done in SRGB space, linear gives odd crossfades */ + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false); + } + if (i != context->view_id) { + copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]); + BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]); + } + } + + /* return the original requested ImBuf */ + ibuf = ibuf_arr[context->view_id]; + if (ibuf) { + seq->strip->stripdata->orig_width = ibuf->x; + seq->strip->stripdata->orig_height = ibuf->y; + } + + /* "remove" the others (decrease their refcount) */ + for (i = 0; i < totviews; i++) { + if (ibuf_arr[i] != ibuf) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + + MEM_freeN(ibuf_arr); + } + else { +monoview_movie: + sanim = seq->anims.first; + if (sanim && sanim->anim) { + IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size); + IMB_anim_set_preseek(sanim->anim, seq->anim_preseek); + + ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, + seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + proxy_size); + + /* fetching for requested proxy size failed, try fetching the original instead */ + if (!ibuf && proxy_size != IMB_PROXY_NONE) { + ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs, + seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + IMB_PROXY_NONE); + } + if (ibuf) { + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); + + /* we don't need both (speed reasons)! */ + if (ibuf->rect_float && ibuf->rect) { + imb_freerectImBuf(ibuf); + } + + seq->strip->stripdata->orig_width = ibuf->x; + seq->strip->stripdata->orig_height = ibuf->y; + } + } + } + return ibuf; +} + static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr) { ImBuf *ibuf = NULL; @@ -2543,7 +3104,7 @@ static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq, return seq_render_mask(context, seq->mask, nr, make_float); } -static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr) +static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra) { ImBuf *ibuf = NULL; float frame; @@ -2641,6 +3202,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq char err_out[256] = "unknown"; int width = (scene->r.xsch * scene->r.size) / 100; int height = (scene->r.ysch * scene->r.size) / 100; + const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id); /* for old scened this can be uninitialized, * should probably be added to do_versions at some point if the functionality stays */ @@ -2652,14 +3214,18 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect, context->scene->r.seq_prev_type, (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0, - use_gpencil, true, scene->r.alphamode, err_out); + use_gpencil, true, scene->r.alphamode, viewname, err_out); if (ibuf == NULL) { fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out); } } else { Render *re = RE_GetRender(scene->id.name); - RenderResult rres; + size_t totviews = BKE_scene_multiview_num_views_get(&scene->r); + int i; + ImBuf **ibufs_arr; + + ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"); /* XXX: this if can be removed when sequence preview rendering uses the job system * @@ -2679,27 +3245,51 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq /* restore previous state after it was toggled on & off by RE_BlenderFrame */ G.is_rendering = is_rendering; } - - RE_AcquireResultImage(re, &rres); - - if (rres.rectf) { - ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat); - memcpy(ibuf->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty); - if (rres.rectz) { - addzbuffloatImBuf(ibuf); - memcpy(ibuf->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty); + + for (i = 0; i < totviews; i++) { + SeqRenderData localcontext = *context; + RenderResult rres; + + localcontext.view_id = i; + + RE_AcquireResultImage(re, &rres, i); + + if (rres.rectf) { + ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat); + memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty); + + if (rres.rectz) { + addzbuffloatImBuf(ibufs_arr[i]); + memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty); + } + + /* float buffers in the sequencer are not linear */ + BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false); + } + else if (rres.rect32) { + ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect); + memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty); } - /* float buffers in the sequencer are not linear */ - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); + if (i != context->view_id) { + copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]); + BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]); + } + + RE_ReleaseResultImage(re); } - else if (rres.rect32) { - ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect); - memcpy(ibuf->rect, rres.rect32, 4 * rres.rectx * rres.recty); + + /* return the original requested ImBuf */ + ibuf = ibufs_arr[context->view_id]; + + /* "remove" the others (decrease their refcount) */ + for (i = 0; i < totviews; i++) { + if (ibufs_arr[i] != ibuf) { + IMB_freeImBuf(ibufs_arr[i]); + } } - - RE_ReleaseResultImage(re); - + MEM_freeN(ibufs_arr); + // BIF_end_render_callbacks(); } @@ -2760,7 +3350,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s float nr = give_stripelem_index(seq, cfra); int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type; bool use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); - char name[FILE_MAX]; switch (type) { case SEQ_TYPE_META: @@ -2779,7 +3368,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s } else { /* scene can be NULL after deletions */ - ibuf = seq_render_scene_strip(context, seq, nr); + ibuf = seq_render_scene_strip(context, seq, nr, cfra); /* Scene strips update all animation, so we need to restore original state.*/ BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra); @@ -2824,68 +3413,14 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s case SEQ_TYPE_IMAGE: { - StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra); - int flag; - - if (s_elem) { - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); - BLI_path_abs(name, G.main->name); - } - - flag = IB_rect; - if (seq->alpha_mode == SEQ_ALPHA_PREMUL) - flag |= IB_alphamode_premul; - - if (s_elem && (ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) { - /* we don't need both (speed reasons)! */ - if (ibuf->rect_float && ibuf->rect) - imb_freerectImBuf(ibuf); - - /* all sequencer color is done in SRGB space, linear gives odd crossfades */ - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); - - copy_to_ibuf_still(context, seq, nr, ibuf); - - s_elem->orig_width = ibuf->x; - s_elem->orig_height = ibuf->y; - } + ibuf = seq_render_image_strip(context, seq, nr, cfra); + copy_to_ibuf_still(context, seq, nr, ibuf); break; } case SEQ_TYPE_MOVIE: { - seq_open_anim_file(seq, false); - - if (seq->anim) { - IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size); - IMB_anim_set_preseek(seq->anim, seq->anim_preseek); - - ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, - proxy_size); - - /* fetching for requested proxy size failed, try fetching the original instead - if (!ibuf && proxy_size != IMB_PROXY_NONE) { - IMB_Proxy_Size proxy_sizes = IMB_anim_proxy_get_existing(seq->anim); - while (!(proxy_size & proxy_sizes) && proxy_size > 0) { - proxy_size >>= 1; - } - ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, - proxy_size); - }*/ - if (ibuf) { - BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false); - - /* we don't need both (speed reasons)! */ - if (ibuf->rect_float && ibuf->rect) { - imb_freerectImBuf(ibuf); - } - - seq->strip->stripdata->orig_width = ibuf->x; - seq->strip->stripdata->orig_height = ibuf->y; - } - } + ibuf = seq_render_movie_strip(context, seq, nr, cfra); copy_to_ibuf_still(context, seq, nr, ibuf); break; } @@ -3111,6 +3646,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2); + IMB_metadata_copy(out, ibuf2); + IMB_freeImBuf(ibuf1); IMB_freeImBuf(ibuf2); } @@ -3381,16 +3918,6 @@ ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context, float cfra return e ? e->ibuf : NULL; } -/* Functions to free imbuf and anim data on changes */ - -static void free_anim_seq(Sequence *seq) -{ - if (seq->anim) { - IMB_free_anim(seq->anim); - seq->anim = NULL; - } -} - /* check whether sequence cur depends on seq */ bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur) { @@ -3442,15 +3969,11 @@ static void sequence_invalidate_cache(Scene *scene, Sequence *seq, bool invalida /* invalidate cache for current sequence */ if (invalidate_self) { - if (seq->anim) { - /* Animation structure holds some buffers inside, - * so for proper cache invalidation we need to - * re-open the animation. - */ - IMB_free_anim(seq->anim); - seq->anim = NULL; - } - + /* Animation structure holds some buffers inside, + * so for proper cache invalidation we need to + * re-open the animation. + */ + BKE_sequence_free_anim(seq); BKE_sequencer_cache_cleanup_sequence(seq); } @@ -3497,7 +4020,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) if (seq->strip) { if (seq->type == SEQ_TYPE_MOVIE) { - free_anim_seq(seq); + BKE_sequence_free_anim(seq); } if (seq->type == SEQ_TYPE_SPEED) { BKE_sequence_effect_speed_rebuild_map(scene, seq, true); @@ -3544,7 +4067,7 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha if (free_imbuf) { if (ibuf_change) { if (seq->type == SEQ_TYPE_MOVIE) - free_anim_seq(seq); + BKE_sequence_free_anim(seq); if (seq->type == SEQ_TYPE_SPEED) { BKE_sequence_effect_speed_rebuild_map(scene, seq, true); } @@ -3796,10 +4319,10 @@ void BKE_sequence_sound_init(Scene *scene, Sequence *seq) } else { if (seq->sound) { - seq->scene_sound = sound_add_scene_sound_defaults(scene, seq); + seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq); } if (seq->scene) { - seq->scene_sound = sound_scene_add_scene_sound_defaults(scene, seq); + seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq); } } } @@ -4011,11 +4534,11 @@ void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq) /* We have to take into account start frame of the sequence's scene! */ int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra; - sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs); + BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs); } } else { - sound_move_scene_sound_defaults(scene, seq); + BKE_sound_move_scene_sound_defaults(scene, seq); } /* mute is set in seq_update_muting_recursive */ } @@ -4040,7 +4563,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { if (seq->scene_sound) { - sound_mute_scene_sound(seq->scene_sound, seqmute); + BKE_sound_mute_scene_sound(seq->scene_sound, seqmute); } } } @@ -4069,7 +4592,7 @@ static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound } else if (seq->type == SEQ_TYPE_SOUND_RAM) { if (seq->scene_sound && sound == seq->sound) { - sound_update_scene_sound(seq->scene_sound, sound); + BKE_sound_update_scene_sound(seq->scene_sound, sound); } } } @@ -4184,7 +4707,7 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char char name_esc[SEQ_NAME_MAXSTR * 2]; BLI_strescape(name_esc, name, sizeof(name_esc)); - return BLI_snprintf(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); + return BLI_snprintf_rlen(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); } /* XXX - hackish function needed for transforming strips! TODO - have some better solution */ @@ -4402,7 +4925,7 @@ static void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load) if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) { if (seq->sound) - sound_cache(seq->sound); + BKE_sound_cache(seq->sound); } seq_load->tot_success++; @@ -4432,6 +4955,8 @@ Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine) seq->pitch = 1.0f; seq->scene_sound = NULL; + seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format"); + return seq; } @@ -4489,6 +5014,12 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem"); BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir)); + if (seq_load->stereo3d_format) + *seq->stereo3d_format = *seq_load->stereo3d_format; + + seq->views_format = seq_load->views_format; + seq->flag |= seq_load->flag & SEQ_USE_VIEWS; + seq_load_apply(scene, seq, seq_load); return seq; @@ -4508,9 +5039,9 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad AUD_SoundInfo info; - sound = sound_new_file(bmain, seq_load->path); /* handles relative paths */ + sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */ - if (sound == NULL || sound->playback_handle == NULL) { + if (sound->playback_handle == NULL) { #if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); @@ -4522,7 +5053,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - sound_delete(bmain, sound); + BKE_sound_delete(bmain, sound); #if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); @@ -4547,7 +5078,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); - seq->scene_sound = sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0); + seq->scene_sound = BKE_sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0); BKE_sequence_calc_disp(scene, seq); @@ -4568,6 +5099,12 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad } #endif // WITH_AUDASPACE +static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id) +{ + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); + IMB_suffix_anim(anim, suffix); +} + Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { Scene *scene = CTX_data_scene(C); /* only for sound */ @@ -4577,29 +5114,84 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad Strip *strip; StripElem *se; char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */ - - struct anim *an; + bool is_multiview_loaded = false; + const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0; + size_t totfiles = seq_num_files(scene, seq_load->views_format, is_multiview); + struct anim **anim_arr; + int i; BLI_strncpy(path, seq_load->path, sizeof(path)); BLI_path_abs(path, G.main->name); - an = openanim(path, IB_rect, 0, colorspace); + anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files"); - if (an == NULL) - return NULL; + if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) { + char prefix[FILE_MAX]; + char *ext = NULL; + size_t j = 0; + + BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext); + + if (prefix[0] != '\0') { + for (i = 0; i < totfiles; i++) { + char str[FILE_MAX]; + + seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX); + anim_arr[j] = openanim(str, IB_rect, 0, colorspace); + + if (anim_arr[j]) { + seq_anim_add_suffix(scene, anim_arr[j], i); + j++; + } + } + + if (j == 0) { + MEM_freeN(anim_arr); + return NULL; + } + is_multiview_loaded = true; + } + } + + if (is_multiview_loaded == false) { + anim_arr[0] = openanim(path, IB_rect, 0, colorspace); + + if (anim_arr[0] == NULL) { + MEM_freeN(anim_arr); + return NULL; + } + } seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel); + + /* multiview settings */ + if (seq_load->stereo3d_format) { + *seq->stereo3d_format = *seq_load->stereo3d_format; + seq->views_format = seq_load->views_format; + } + seq->flag |= seq_load->flag & SEQ_USE_VIEWS; + seq->type = SEQ_TYPE_MOVIE; seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ - seq->anim = an; - seq->anim_preseek = IMB_anim_get_preseek(an); + for (i = 0; i < totfiles; i++) { + if (anim_arr[i]) { + StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim"); + BLI_addtail(&seq->anims, sanim); + sanim->anim = anim_arr[i]; + } + else { + break; + } + } + + seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* basic defaults */ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip"); - seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN); + seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); strip->us = 1; BLI_strncpy(seq->strip->colorspace_settings.name, colorspace, sizeof(seq->strip->colorspace_settings.name)); @@ -4627,6 +5219,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad /* can be NULL */ seq_load_apply(scene, seq, seq_load); + MEM_freeN(anim_arr); return seq; } @@ -4638,6 +5231,8 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup seq->tmp = seqn; seqn->strip = MEM_dupallocN(seq->strip); + seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format); + /* XXX: add F-Curve duplication stuff? */ if (seq->strip->crop) { @@ -4653,6 +5248,10 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup seqn->strip->proxy->anim = NULL; } + if (seq->prop) { + seqn->prop = IDP_CopyProperty(seq->prop); + } + if (seqn->modifiers.first) { BLI_listbase_clear(&seqn->modifiers); @@ -4669,7 +5268,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; if (seq->scene_sound) - seqn->scene_sound = sound_scene_add_scene_sound_defaults(sce_audio, seqn); + seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce_audio, seqn); } else if (seq->type == SEQ_TYPE_MOVIECLIP) { /* avoid assert */ @@ -4680,13 +5279,13 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup else if (seq->type == SEQ_TYPE_MOVIE) { seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); - seqn->anim = NULL; + BLI_listbase_clear(&seqn->anims); } else if (seq->type == SEQ_TYPE_SOUND_RAM) { seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); if (seq->scene_sound) - seqn->scene_sound = sound_add_scene_sound_defaults(sce_audio, seqn); + seqn->scene_sound = BKE_sound_add_scene_sound_defaults(sce_audio, seqn); id_us_plus((ID *)seqn->sound); } @@ -4695,10 +5294,6 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup MEM_dupallocN(seq->strip->stripdata); } else if (seq->type >= SEQ_TYPE_EFFECT) { - if (seq->seq1 && seq->seq1->tmp) seqn->seq1 = seq->seq1->tmp; - if (seq->seq2 && seq->seq2->tmp) seqn->seq2 = seq->seq2->tmp; - if (seq->seq3 && seq->seq3->tmp) seqn->seq3 = seq->seq3->tmp; - if (seq->type & SEQ_TYPE_EFFECT) { struct SeqEffectHandle sh; sh = BKE_sequence_get_effect(seq); @@ -4723,6 +5318,28 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup return seqn; } +static void seq_new_fix_links_recursive(Sequence *seq) +{ + SequenceModifierData *smd; + + if (seq->type >= SEQ_TYPE_EFFECT) { + if (seq->seq1 && seq->seq1->tmp) seq->seq1 = seq->seq1->tmp; + if (seq->seq2 && seq->seq2->tmp) seq->seq2 = seq->seq2->tmp; + if (seq->seq3 && seq->seq3->tmp) seq->seq3 = seq->seq3->tmp; + } + else if (seq->type == SEQ_TYPE_META) { + Sequence *seqn; + for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) { + seq_new_fix_links_recursive(seqn); + } + } + + for (smd = seq->modifiers.first; smd; smd = smd->next) { + if (smd->mask_sequence && smd->mask_sequence->tmp) + smd->mask_sequence = smd->mask_sequence->tmp; + } +} + Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag) { Sequence *seqn = seq_dupli(scene, scene_to, seq, dupe_flag); @@ -4735,6 +5352,9 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence * } } } + + seq_new_fix_links_recursive(seqn); + return seqn; } @@ -4773,6 +5393,11 @@ void BKE_sequence_base_dupli_recursive( } } } + + /* fix modifier linking */ + for (seq = nseqbase->first; seq; seq = seq->next) { + seq_new_fix_links_recursive(seq); + } } /* called on draw, needs to be fast, diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index a34aa5009e6..6a0af3ed118 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -66,6 +66,7 @@ #include "BKE_bvhutils.h" #include "BKE_cdderivedmesh.h" #include "BKE_collision.h" +#include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_customdata.h" #include "BKE_deform.h" @@ -152,7 +153,7 @@ struct SmokeModifierData; #else /* WITH_SMOKE */ /* Stubs to use when smoke is disabled */ -struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; } +struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors), int UNUSED(use_sim)) { return NULL; } //struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; } void smoke_free(struct FLUID_3D *UNUSED(fluid)) {} float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; } @@ -195,6 +196,8 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[ { int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE)); int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); + int use_sim = !((sds->point_cache[0] != NULL) && + (sds->point_cache[0]->flag & (PTCACHE_BAKED|PTCACHE_DISK_CACHE)) == (PTCACHE_BAKED|PTCACHE_DISK_CACHE)); if (free_old && sds->wt) smoke_turbulence_free(sds->wt); @@ -206,7 +209,7 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[ /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */ BLI_lock_thread(LOCK_FFTW); - sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors); + sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors, use_sim); BLI_unlock_thread(LOCK_FFTW); @@ -266,7 +269,7 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object * } /* apply object scale */ for (i = 0; i < 3; i++) { - size[i] = fabs(size[i] * ob->size[i]); + size[i] = fabsf(size[i] * ob->size[i]); } copy_v3_v3(sds->global_size, size); copy_v3_v3(sds->dp0, min); @@ -563,6 +566,8 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG; smd->domain->effector_weights = BKE_add_effector_weights(NULL); + + smd->domain->display_thickness = 1.0f; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -730,7 +735,8 @@ static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds BVHTreeFromMesh treeData = {NULL}; int numverts, i, z; - float surface_distance = 0.6; + /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */ + const float surface_distance = 0.867f; float *vert_vel = NULL; int has_velocity = 0; @@ -970,7 +976,7 @@ static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int /* also update constraint targets */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { @@ -1025,6 +1031,7 @@ typedef struct EmissionMap { float *velocity; int min[3], max[3], res[3]; int hmin[3], hmax[3], hres[3]; + float *color; int total_cells, valid; } EmissionMap; @@ -1069,7 +1076,7 @@ static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3] } } -static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) +static void em_allocateData(EmissionMap *em, bool use_velocity, bool use_color, int hires_mul) { int i, res[3]; @@ -1085,6 +1092,8 @@ static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence"); if (use_velocity) em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity"); + if (use_color) + em->color = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_color"); /* allocate high resolution map if required */ if (hires_mul > 1) { @@ -1109,6 +1118,8 @@ static void em_freeData(EmissionMap *em) MEM_freeN(em->influence_high); if (em->velocity) MEM_freeN(em->velocity); + if (em->color) + MEM_freeN(em->color); } static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size) @@ -1131,7 +1142,7 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult } } /* allocate output map */ - em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier); + em_allocateData(output, (em1.velocity || em2->velocity), (em1.color || em2->color), hires_multiplier); /* base resolution inputs */ for (x = output->min[0]; x < output->max[0]; x++) @@ -1150,6 +1161,9 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult if (output->velocity && em1.velocity) { copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]); } + if (output->color && em1.color) { + copy_v3_v3(&output->color[index_out * 3], &em1.color[index_in * 3]); + } } /* apply second input if in range */ @@ -1171,6 +1185,13 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], em2->velocity[index_in * 3 + 1]); output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], em2->velocity[index_in * 3 + 2]); } + if (output->color && em2->color) { + /* mix by influence */ + float f1 = output->influence[index_out]; + float f2 = em2->influence[index_in]; + float f = f1 + f2 > 0.0f ? f1 / (f1 + f2) : 0.5f; + interp_v3_v3v3(&output->color[index_out * 3], &output->color[index_out * 3], &em2->color[index_in * 3], f); + } } } // low res loop @@ -1222,6 +1243,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke ParticleSystem *psys = sfs->psys; float *particle_pos; float *particle_vel; + float *particle_texcol; int totpart = psys->totpart, totchild; int p = 0; int valid_particles = 0; @@ -1238,6 +1260,12 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke sim.ob = flow_ob; sim.psys = psys; + /* prepare curvemapping tables */ + if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) + curvemapping_changed_all(psys->part->clumpcurve); + if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) + curvemapping_changed_all(psys->part->roughcurve); + /* initialize particle cache */ if (psys->part->type == PART_HAIR) { // TODO: PART_HAIR not supported whatsoever @@ -1262,6 +1290,11 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke bounds_margin = (int)ceil(solid + smooth); } + if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR) + particle_texcol = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); + else + particle_texcol = NULL; + /* calculate local position for each particle */ for (p = 0; p < totpart + totchild; p++) { @@ -1295,6 +1328,16 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke BLI_kdtree_insert(tree, valid_particles, pos); } + if (particle_texcol) { + if (p < totpart) { + ParticleTexture ptex; + psys_get_texture(&sim, &psys->particles[p], &ptex, PAMAP_COLOR, state.time); + copy_v3_v3(&particle_texcol[valid_particles * 3], ptex.color); + } + else + zero_v3(&particle_texcol[valid_particles * 3]); + } + /* calculate emission map bounds */ em_boundInsert(em, pos); valid_particles++; @@ -1302,7 +1345,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke /* set emission map */ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt); - em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); + em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR, hires_multiplier); if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { for (p = 0; p < valid_particles; p++) @@ -1334,6 +1377,9 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke { VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi); } + if (particle_texcol && em->color) { + copy_v3_v3(&em->color[index * 3], &particle_texcol[p * 3]); + } } // particles loop } else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE @@ -1383,6 +1429,9 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke { VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[nearest.index * 3], sfs->vel_multi); } + if (particle_texcol && em->color) { + copy_v3_v3(&em->color[index * 3], &particle_texcol[nearest.index * 3]); + } } } @@ -1420,6 +1469,8 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke MEM_freeN(particle_pos); if (particle_vel) MEM_freeN(particle_vel); + if (particle_texcol) + MEM_freeN(particle_texcol); } } @@ -1633,7 +1684,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo /* set emission map */ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt); - em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); + em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, false, hires_multiplier); /* setup loop bounds */ for (i = 0; i < 3; i++) { @@ -1975,7 +2026,7 @@ BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, flo } } -BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b) +BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, const float *color_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b) { int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); float dens_old = density[index]; @@ -2012,9 +2063,10 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value /* set color */ if (color_r && dens_flow) { float total_dens = density[index] / (dens_old + dens_flow); - color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens; - color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens; - color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens; + const float *color = (color_value ? color_value : sfs->color); + color_r[index] = (color_r[index] + color[0] * dens_flow) * total_dens; + color_g[index] = (color_g[index] + color[1] * dens_flow) * total_dens; + color_b[index] = (color_b[index] + color[2] * dens_flow) * total_dens; } /* set fire reaction coordinate */ @@ -2161,7 +2213,10 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd } /* activate color field if flows add smoke with varying colors */ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) { - if (!(active_fields & SM_ACTIVE_COLOR_SET)) { + if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR) { + active_fields |= SM_ACTIVE_COLORS; + } + else if (!(active_fields & SM_ACTIVE_COLOR_SET)) { copy_v3_v3(sds->active_color, sfs->color); active_fields |= SM_ACTIVE_COLOR_SET; } @@ -2242,6 +2297,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd float *velocity_map = em->velocity; float *emission_map = em->influence; float *emission_map_high = em->influence_high; + float *color_map = em->color; int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size; size_t e_index, d_index, index_big; @@ -2269,7 +2325,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b); } else { // inflow - apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b); + apply_inflow_fields(sfs, emission_map[e_index], color_map ? &color_map[e_index * 3] : NULL, d_index, density, heat, fuel, react, color_r, color_g, color_b); /* initial velocity */ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { @@ -2283,6 +2339,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd if (bigdensity) { // neighbor cell emission densities (for high resolution smoke smooth interpolation) float c000, c001, c010, c011, c100, c101, c110, c111; + float col000[3], col001[3], col010[3], col011[3], col100[3], col101[3], col110[3], col111[3]; smoke_turbulence_get_res(sds->wt, bigres); block_size = sds->amplify + 1; // high res block size @@ -2297,14 +2354,67 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd c110 = (ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : 0; c111 = emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez)]; // this cell + if (color_map) { + static const float Z[3] = {0.0f, 0.0f, 0.0f}; + + copy_v3_v3(col000, (ex > 0 && ey > 0 && ez > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez - 1) * 3] : Z); + copy_v3_v3(col001, (ex > 0 && ey > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez) * 3] : Z); + copy_v3_v3(col010, (ex > 0 && ez > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1) * 3] : Z); + copy_v3_v3(col011, (ex > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez) * 3] : Z); + + copy_v3_v3(col100, (ey > 0 && ez > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1) * 3] : Z); + copy_v3_v3(col101, (ey > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez) * 3] : Z); + copy_v3_v3(col110, (ez > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1) * 3] : Z); + copy_v3_v3(col111, &color_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez) * 3]); // this cell + } + else { + zero_v3(col000); + zero_v3(col001); + zero_v3(col010); + zero_v3(col011); + zero_v3(col100); + zero_v3(col101); + zero_v3(col110); + zero_v3(col111); + } + for (ii = 0; ii < block_size; ii++) for (jj = 0; jj < block_size; jj++) for (kk = 0; kk < block_size; kk++) { - float fx, fy, fz, interpolated_value; + float col[3], interpolated_value, *interpolated_color; int shift_x = 0, shift_y = 0, shift_z = 0; + float w[2][2][2]; + bool do_interpolation = ((!((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) && + !(sds->highres_sampling == SM_HRES_NEAREST)) || + color_map); + + /* weights are used for both density and color, + * so calculate them once in advance + */ + if (do_interpolation) { + /* get relative block position + * for interpolation smoothing */ + float fx = (float)ii / block_size + 0.5f / block_size; + float fy = (float)jj / block_size + 0.5f / block_size; + float fz = (float)kk / block_size + 0.5f / block_size; + float mx = 1.0f - fx; + float my = 1.0f - fy; + float mz = 1.0f - fz; + + w[0][0][0] = mx * my * mz; + w[1][0][0] = fx * my * mz; + w[0][1][0] = mx * fy * mz; + w[1][1][0] = fx * fy * mz; + w[0][0][1] = mx * my * fz; + w[1][0][1] = fx * my * fz; + w[0][1][1] = mx * fy * fz; + w[1][1][1] = fx * fy * fz; + } + else + memset(w, 0, sizeof(float) * 8); /* Use full sample emission map if enabled and available */ if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) { @@ -2318,22 +2428,17 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd /* Fall back to interpolated */ else { - /* get relative block position - * for interpolation smoothing */ - fx = (float)ii / block_size + 0.5f / block_size; - fy = (float)jj / block_size + 0.5f / block_size; - fz = (float)kk / block_size + 0.5f / block_size; /* calculate trilinear interpolation */ - interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) + - c100 * fx * (1 - fy) * (1 - fz) + - c010 * (1 - fx) * fy * (1 - fz) + - c001 * (1 - fx) * (1 - fy) * fz + - c101 * fx * (1 - fy) * fz + - c011 * (1 - fx) * fy * fz + - c110 * fx * fy * (1 - fz) + - c111 * fx * fy * fz; - + interpolated_value = 0.0f; + interpolated_value += c000 * w[0][0][0]; + interpolated_value += c100 * w[1][0][0]; + interpolated_value += c010 * w[0][1][0]; + interpolated_value += c110 * w[1][1][0]; + interpolated_value += c001 * w[0][0][1]; + interpolated_value += c101 * w[1][0][1]; + interpolated_value += c011 * w[0][1][1]; + interpolated_value += c111 * w[1][1][1]; /* add some contrast / sharpness * depending on hi-res block size */ @@ -2347,6 +2452,48 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd shift_y = (dy < 1) ? 0 : block_size / 2; shift_z = (dz < 1) ? 0 : block_size / 2; } + + if (color_map) { + float wcol[2][2][2], totw, invtotw; + + /* colors are zero (black) in zero-emission cells, + * so use weighted average based on density to avoid artifacts! + */ + wcol[0][0][0] = w[0][0][0] * c000; + wcol[1][0][0] = w[1][0][0] * c100; + wcol[0][1][0] = w[0][1][0] * c010; + wcol[1][1][0] = w[1][1][0] * c110; + wcol[0][0][1] = w[0][0][1] * c001; + wcol[1][0][1] = w[1][0][1] * c101; + wcol[0][1][1] = w[0][1][1] * c011; + wcol[1][1][1] = w[1][1][1] * c111; + + totw = wcol[0][0][0] + wcol[1][0][0] + wcol[0][1][0] + wcol[1][1][0] + + wcol[0][0][1] + wcol[1][0][1] + wcol[0][1][1] + wcol[1][1][1]; + invtotw = totw > 0.0f ? 1.0f/totw : 0.0f; + wcol[0][0][0] *= invtotw; + wcol[1][0][0] *= invtotw; + wcol[0][1][0] *= invtotw; + wcol[1][1][0] *= invtotw; + wcol[0][0][1] *= invtotw; + wcol[1][0][1] *= invtotw; + wcol[0][1][1] *= invtotw; + wcol[1][1][1] *= invtotw; + + zero_v3(col); + madd_v3_v3fl(col, col000, wcol[0][0][0]); + madd_v3_v3fl(col, col100, wcol[1][0][0]); + madd_v3_v3fl(col, col010, wcol[0][1][0]); + madd_v3_v3fl(col, col110, wcol[1][1][0]); + madd_v3_v3fl(col, col001, wcol[0][0][1]); + madd_v3_v3fl(col, col101, wcol[1][0][1]); + madd_v3_v3fl(col, col011, wcol[0][1][1]); + madd_v3_v3fl(col, col111, wcol[1][1][1]); + + interpolated_color = col; + } + else + interpolated_color = NULL; /* get shifted index for current high resolution block */ index_big = smoke_get_index(block_size * dx + ii - shift_x, bigres[0], block_size * dy + jj - shift_y, bigres[1], block_size * dz + kk - shift_z); @@ -2357,7 +2504,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd } } else { // inflow - apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b); + apply_inflow_fields(sfs, interpolated_value, interpolated_color, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b); } } // hires loop } // bigdensity @@ -2381,7 +2528,7 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, ListBase *effectors; /* make sure smoke flow influence is 0.0f */ sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; - effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true); + effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); if (effectors) { @@ -2663,7 +2810,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * int startframe, endframe, framenr; float timescale; - framenr = scene->r.cfra; + framenr = scene->r.cfra - sds->point_cache_offset; //printf("time: %d\n", scene->r.cfra); @@ -2744,6 +2891,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * if (sds->wt) { + smoke_ensure_simulation(sds->fluid, sds->wt); smoke_turbulence_step(sds->wt, sds->fluid); } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 06d0627fd2c..dc5b77a1bf4 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -522,10 +522,8 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M) mima->maxz = max_ff(mima->maxz, v[2] + hull); } - - mima++; - mface++; - + mima++; + mface++; } return; } @@ -707,7 +705,7 @@ static void add_2nd_order_roller(Object *ob, float UNUSED(stiffness), int *count } } if ((bs2->v2 !=notthis)&&(bs2->v2 > v0)) { - (*counter)++;/*hit */ + (*counter)++; /* hit */ if (addsprings) { bs3->v1= v0; bs3->v2= bs2->v2; @@ -1037,6 +1035,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { #if 0 /* UNUSED */ @@ -1078,6 +1077,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U } } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1116,6 +1116,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MVert *mvert= NULL; @@ -1179,6 +1180,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float } /* if (mvert) */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1208,6 +1210,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MFace *mface= NULL; @@ -1317,6 +1320,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl }/* while a */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1436,6 +1440,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MFace *mface= NULL; @@ -1557,6 +1562,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl }/* while a */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ BLI_ghashIterator_free(ihash); return deflected; @@ -1641,7 +1647,7 @@ static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow) SoftBody *sb = ob->soft; ListBase *do_effector = NULL; - do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true); + do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights); _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector); pdEndEffectors(&do_effector); } @@ -1661,7 +1667,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, int i, totthread, left, dec; int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ - do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true); + do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights); /* figure the number of threads while preventing pretty pointless threading overhead */ totthread= BKE_scene_num_threads(scene); @@ -1764,6 +1770,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); ob = BLI_ghashIterator_getKey (ihash); + { /* only with deflecting set */ if (ob->pd && ob->pd->deflect) { MFace *mface= NULL; @@ -1801,7 +1808,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], else { /*aye that should be cached*/ printf("missing cache error\n"); - BLI_ghashIterator_step(ihash); + BLI_ghashIterator_step(ihash); continue; } @@ -1919,16 +1926,16 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], if (facedist > outerfacethickness*ff) force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); *damp=ob->pd->pdef_sbdamp; - if (facedist > 0.0f) { - *damp *= (1.0f - facedist/outerfacethickness); - Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect); - deflected = 3; + if (facedist > 0.0f) { + *damp *= (1.0f - facedist/outerfacethickness); + Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect); + deflected = 3; - } - else { - Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect); - if (deflected < 2) deflected = 2; - } + } + else { + Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect); + if (deflected < 2) deflected = 2; + } if ((mprevvert) && (*damp > 0.0f)) { choose_winner(ve, opco, nv1, nv3, nv4, vv1, vv3, vv4); @@ -1999,6 +2006,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], }/* while a */ } /* if (ob->pd && ob->pd->deflect) */ BLI_ghashIterator_step(ihash); + } } /* while () */ if (deflected == 1) { // no face but 'outer' edge cylinder sees vert @@ -2337,14 +2345,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo float kd = 1.0f; if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) { - if (intrusion < 0.0f) { - sb->scratch->flag |= SBF_DOFUZZY; - bp->loc_flag |= SBF_DOFUZZY; - bp->choke = sb->choke*0.01f; - } + if (intrusion < 0.0f) { + sb->scratch->flag |= SBF_DOFUZZY; + bp->loc_flag |= SBF_DOFUZZY; + bp->choke = sb->choke*0.01f; + } - sub_v3_v3v3(cfforce, bp->vec, vel); - Vec3PlusStVec(bp->force, -cf*50.0f, cfforce); + sub_v3_v3v3(cfforce, bp->vec, vel); + Vec3PlusStVec(bp->force, -cf*50.0f, cfforce); Vec3PlusStVec(bp->force, kd, defforce); } @@ -2467,7 +2475,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL); /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true); + do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights); if (do_deflector) { float defforce[3]; @@ -2542,7 +2550,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow); /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true); + do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights); if (do_deflector) { float defforce[3]; @@ -3486,7 +3494,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object bs->v1 = bpc; bs->v2 = bpc+dw+dv-1; bs->springtype=SB_BEND; - bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob); + bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob); bs++; } } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 6acd7276a33..81cc55f754d 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -64,9 +64,9 @@ static int sound_cfra; #endif -bSound *sound_new_file(struct Main *bmain, const char *filename) +bSound *BKE_sound_new_file(struct Main *bmain, const char *filename) { - bSound *sound = NULL; + bSound *sound; char str[FILE_MAX]; const char *path; @@ -87,12 +87,7 @@ bSound *sound_new_file(struct Main *bmain, const char *filename) BLI_strncpy(sound->name, filename, FILE_MAX); /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */ - sound_load(bmain, sound); - - if (!sound->playback_handle) { - BKE_libblock_free(bmain, sound); - sound = NULL; - } + BKE_sound_load(bmain, sound); return sound; } @@ -116,7 +111,7 @@ void BKE_sound_free(bSound *sound) sound->cache = NULL; } - sound_free_waveform(sound); + BKE_sound_free_waveform(sound); if (sound->spinlock) { BLI_spin_end(sound->spinlock); @@ -141,18 +136,18 @@ static void sound_sync_callback(void *data, int mode, float time) while (scene) { if (scene->audio.flag & AUDIO_SYNC) { if (mode) - sound_play_scene(scene); + BKE_sound_play_scene(scene); else - sound_stop_scene(scene); - if (scene->sound_scene_handle) - AUD_seek(scene->sound_scene_handle, time); + BKE_sound_stop_scene(scene); + if (scene->playback_handle) + AUD_seek(scene->playback_handle, time); } scene = scene->id.next; } } #endif -int sound_define_from_str(const char *str) +int BKE_sound_define_from_str(const char *str) { if (BLI_strcaseeq(str, "NULL")) return AUD_NULL_DEVICE; @@ -166,18 +161,18 @@ int sound_define_from_str(const char *str) return -1; } -void sound_force_device(int device) +void BKE_sound_force_device(int device) { force_device = device; } -void sound_init_once(void) +void BKE_sound_init_once(void) { AUD_initOnce(); - atexit(sound_exit_once); + atexit(BKE_sound_exit_once); } -void sound_init(struct Main *bmain) +void BKE_sound_init(struct Main *bmain) { AUD_DeviceSpecs specs; int device, buffersize; @@ -206,10 +201,10 @@ void sound_init(struct Main *bmain) if (!AUD_init(device, specs, buffersize)) AUD_init(AUD_NULL_DEVICE, specs, buffersize); - sound_init_main(bmain); + BKE_sound_init_main(bmain); } -void sound_init_main(struct Main *bmain) +void BKE_sound_init_main(struct Main *bmain) { #ifdef WITH_JACK AUD_setSyncCallback(sound_sync_callback, bmain); @@ -218,12 +213,12 @@ void sound_init_main(struct Main *bmain) #endif } -void sound_exit(void) +void BKE_sound_exit(void) { AUD_exit(); } -void sound_exit_once(void) +void BKE_sound_exit_once(void) { AUD_exit(); AUD_exitOnce(); @@ -231,7 +226,7 @@ void sound_exit_once(void) /* XXX unused currently */ #if 0 -bSound *sound_new_buffer(struct Main *bmain, bSound *source) +bSound *BKE_sound_new_buffer(struct Main *bmain, bSound *source) { bSound *sound = NULL; @@ -246,16 +241,10 @@ bSound *sound_new_buffer(struct Main *bmain, bSound *source) sound_load(bmain, sound); - if (!sound->playback_handle) - { - BKE_libblock_free(bmain, sound); - sound = NULL; - } - return sound; } -bSound *sound_new_limiter(struct Main *bmain, bSound *source, float start, float end) +bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, float end) { bSound *sound = NULL; @@ -272,17 +261,11 @@ bSound *sound_new_limiter(struct Main *bmain, bSound *source, float start, float sound_load(bmain, sound); - if (!sound->playback_handle) - { - BKE_libblock_free(bmain, sound); - sound = NULL; - } - return sound; } #endif -void sound_delete(struct Main *bmain, bSound *sound) +void BKE_sound_delete(struct Main *bmain, bSound *sound) { if (sound) { BKE_sound_free(sound); @@ -291,7 +274,7 @@ void sound_delete(struct Main *bmain, bSound *sound) } } -void sound_cache(bSound *sound) +void BKE_sound_cache(bSound *sound) { sound->flags |= SOUND_FLAGS_CACHING; if (sound->cache) @@ -304,7 +287,7 @@ void sound_cache(bSound *sound) sound->playback_handle = sound->handle; } -void sound_delete_cache(bSound *sound) +void BKE_sound_delete_cache(bSound *sound) { sound->flags &= ~SOUND_FLAGS_CACHING; if (sound->cache) { @@ -314,7 +297,7 @@ void sound_delete_cache(bSound *sound) } } -void sound_load(struct Main *bmain, bSound *sound) +void BKE_sound_load(struct Main *bmain, bSound *sound) { if (sound) { if (sound->cache) { @@ -328,7 +311,7 @@ void sound_load(struct Main *bmain, bSound *sound) sound->playback_handle = NULL; } - sound_free_waveform(sound); + BKE_sound_free_waveform(sound); /* XXX unused currently */ #if 0 @@ -382,16 +365,16 @@ void sound_load(struct Main *bmain, bSound *sound) else sound->playback_handle = sound->handle; - sound_update_sequencer(bmain, sound); + BKE_sound_update_sequencer(bmain, sound); } } -AUD_Device *sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume) +AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume) { return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS); } -void sound_create_scene(struct Scene *scene) +void BKE_sound_create_scene(struct Scene *scene) { /* should be done in version patch, but this gets called before */ if (scene->r.frs_sec_base == 0) @@ -400,15 +383,15 @@ void sound_create_scene(struct Scene *scene) scene->sound_scene = AUD_createSequencer(FPS, scene->audio.flag & AUDIO_MUTE); AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound, scene->audio.doppler_factor, scene->audio.distance_model); - scene->sound_scene_handle = NULL; + scene->playback_handle = NULL; scene->sound_scrub_handle = NULL; scene->speaker_handles = NULL; } -void sound_destroy_scene(struct Scene *scene) +void BKE_sound_destroy_scene(struct Scene *scene) { - if (scene->sound_scene_handle) - AUD_stop(scene->sound_scene_handle); + if (scene->playback_handle) + AUD_stop(scene->playback_handle); if (scene->sound_scrub_handle) AUD_stop(scene->sound_scrub_handle); if (scene->sound_scene) @@ -417,13 +400,13 @@ void sound_destroy_scene(struct Scene *scene) AUD_destroySet(scene->speaker_handles); } -void sound_mute_scene(struct Scene *scene, int muted) +void BKE_sound_mute_scene(struct Scene *scene, int muted) { if (scene->sound_scene) AUD_setSequencerMuted(scene->sound_scene, muted); } -void sound_update_fps(struct Scene *scene) +void BKE_sound_update_fps(struct Scene *scene) { if (scene->sound_scene) AUD_setSequencerFPS(scene->sound_scene, FPS); @@ -431,13 +414,13 @@ void sound_update_fps(struct Scene *scene) BKE_sequencer_refresh_sound_length(scene); } -void sound_update_scene_listener(struct Scene *scene) +void BKE_sound_update_scene_listener(struct Scene *scene) { AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound, scene->audio.doppler_factor, scene->audio.distance_model); } -void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, +void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip) { if (scene != sequence->scene) { @@ -448,14 +431,14 @@ void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence return NULL; } -void *sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence) +void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence) { - return sound_scene_add_scene_sound(scene, sequence, + return BKE_sound_scene_add_scene_sound(scene, sequence, sequence->startdisp, sequence->enddisp, sequence->startofs + sequence->anim_startofs); } -void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip) +void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip) { const double fps = FPS; void *handle = AUD_addSequence(scene->sound_scene, sequence->sound->playback_handle, @@ -467,70 +450,70 @@ void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int return handle; } -void *sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence) +void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence) { - return sound_add_scene_sound(scene, sequence, + return BKE_sound_add_scene_sound(scene, sequence, sequence->startdisp, sequence->enddisp, sequence->startofs + sequence->anim_startofs); } -void sound_remove_scene_sound(struct Scene *scene, void *handle) +void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle) { AUD_removeSequence(scene->sound_scene, handle); } -void sound_mute_scene_sound(void *handle, char mute) +void BKE_sound_mute_scene_sound(void *handle, char mute) { AUD_muteSequence(handle, mute); } -void sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip) +void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip) { const double fps = FPS; AUD_moveSequence(handle, startframe / fps, endframe / fps, frameskip / fps); } -void sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence) +void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence) { if (sequence->scene_sound) { - sound_move_scene_sound(scene, sequence->scene_sound, + BKE_sound_move_scene_sound(scene, sequence->scene_sound, sequence->startdisp, sequence->enddisp, sequence->startofs + sequence->anim_startofs); } } -void sound_update_scene_sound(void *handle, bSound *sound) +void BKE_sound_update_scene_sound(void *handle, bSound *sound) { AUD_updateSequenceSound(handle, sound->playback_handle); } -void sound_set_cfra(int cfra) +void BKE_sound_set_cfra(int cfra) { sound_cfra = cfra; } -void sound_set_scene_volume(struct Scene *scene, float volume) +void BKE_sound_set_scene_volume(struct Scene *scene, float volume) { AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_VOLUME, CFRA, &volume, (scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0); } -void sound_set_scene_sound_volume(void *handle, float volume, char animated) +void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated) { AUD_setSequenceAnimData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated); } -void sound_set_scene_sound_pitch(void *handle, float pitch, char animated) +void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated) { AUD_setSequenceAnimData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated); } -void sound_set_scene_sound_pan(void *handle, float pan, char animated) +void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated) { AUD_setSequenceAnimData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated); } -void sound_update_sequencer(struct Main *main, bSound *sound) +void BKE_sound_update_sequencer(struct Main *main, bSound *sound) { struct Scene *scene; @@ -541,36 +524,36 @@ void sound_update_sequencer(struct Main *main, bSound *sound) static void sound_start_play_scene(struct Scene *scene) { - if (scene->sound_scene_handle) - AUD_stop(scene->sound_scene_handle); + if (scene->playback_handle) + AUD_stop(scene->playback_handle); AUD_setSequencerDeviceSpecs(scene->sound_scene); - if ((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1))) - AUD_setLoop(scene->sound_scene_handle, -1); + if ((scene->playback_handle = AUD_play(scene->sound_scene, 1))) + AUD_setLoop(scene->playback_handle, -1); } -void sound_play_scene(struct Scene *scene) +void BKE_sound_play_scene(struct Scene *scene) { AUD_Status status; const float cur_time = (float)((double)CFRA / FPS); AUD_lock(); - status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID; + status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID; if (status == AUD_STATUS_INVALID) { sound_start_play_scene(scene); - if (!scene->sound_scene_handle) { + if (!scene->playback_handle) { AUD_unlock(); return; } } if (status != AUD_STATUS_PLAYING) { - AUD_seek(scene->sound_scene_handle, cur_time); - AUD_resume(scene->sound_scene_handle); + AUD_seek(scene->playback_handle, cur_time); + AUD_resume(scene->playback_handle); } if (scene->audio.flag & AUDIO_SYNC) @@ -579,17 +562,17 @@ void sound_play_scene(struct Scene *scene) AUD_unlock(); } -void sound_stop_scene(struct Scene *scene) +void BKE_sound_stop_scene(struct Scene *scene) { - if (scene->sound_scene_handle) { - AUD_pause(scene->sound_scene_handle); + if (scene->playback_handle) { + AUD_pause(scene->playback_handle); if (scene->audio.flag & AUDIO_SYNC) AUD_stopPlayback(); } } -void sound_seek_scene(struct Main *bmain, struct Scene *scene) +void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) { AUD_Status status; bScreen *screen; @@ -600,17 +583,17 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene) AUD_lock(); - status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID; + status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID; if (status == AUD_STATUS_INVALID) { sound_start_play_scene(scene); - if (!scene->sound_scene_handle) { + if (!scene->playback_handle) { AUD_unlock(); return; } - AUD_pause(scene->sound_scene_handle); + AUD_pause(scene->playback_handle); } animation_playing = 0; @@ -623,13 +606,13 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene) if ((scene->audio.flag & AUDIO_SCRUB) && !animation_playing) { if (scene->audio.flag & AUDIO_SYNC) { - AUD_seek(scene->sound_scene_handle, cur_time); - AUD_seekSequencer(scene->sound_scene_handle, cur_time); + AUD_seek(scene->playback_handle, cur_time); + AUD_seekSequencer(scene->playback_handle, cur_time); } else { - AUD_seek(scene->sound_scene_handle, cur_time); + AUD_seek(scene->playback_handle, cur_time); } - AUD_resume(scene->sound_scene_handle); + AUD_resume(scene->playback_handle); if (scene->sound_scrub_handle && AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) { AUD_seek(scene->sound_scrub_handle, 0); } @@ -637,16 +620,16 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene) if (scene->sound_scrub_handle) { AUD_stop(scene->sound_scrub_handle); } - scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, one_frame); + scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame); } } else { if (scene->audio.flag & AUDIO_SYNC) { - AUD_seekSequencer(scene->sound_scene_handle, cur_time); + AUD_seekSequencer(scene->playback_handle, cur_time); } else { if (status == AUD_STATUS_PLAYING) { - AUD_seek(scene->sound_scene_handle, cur_time); + AUD_seek(scene->playback_handle, cur_time); } } } @@ -654,18 +637,18 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene) AUD_unlock(); } -float sound_sync_scene(struct Scene *scene) +float BKE_sound_sync_scene(struct Scene *scene) { - if (scene->sound_scene_handle) { + if (scene->playback_handle) { if (scene->audio.flag & AUDIO_SYNC) - return AUD_getSequencerPosition(scene->sound_scene_handle); + return AUD_getSequencerPosition(scene->playback_handle); else - return AUD_getPosition(scene->sound_scene_handle); + return AUD_getPosition(scene->playback_handle); } return NAN_FLT; } -int sound_scene_playing(struct Scene *scene) +int BKE_sound_scene_playing(struct Scene *scene) { if (scene->audio.flag & AUDIO_SYNC) return AUD_doesPlayback(); @@ -673,7 +656,7 @@ int sound_scene_playing(struct Scene *scene) return -1; } -void sound_free_waveform(bSound *sound) +void BKE_sound_free_waveform(bSound *sound) { SoundWaveform *waveform = sound->waveform; if (waveform) { @@ -686,7 +669,7 @@ void sound_free_waveform(bSound *sound) sound->waveform = NULL; } -void sound_read_waveform(bSound *sound, short *stop) +void BKE_sound_read_waveform(bSound *sound, short *stop) { AUD_SoundInfo info = AUD_getInfo(sound->playback_handle); SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform"); @@ -717,7 +700,7 @@ void sound_read_waveform(bSound *sound, short *stop) return; } - sound_free_waveform(sound); + BKE_sound_free_waveform(sound); BLI_spin_lock(sound->spinlock); sound->waveform = waveform; @@ -725,7 +708,7 @@ void sound_read_waveform(bSound *sound, short *stop) BLI_spin_unlock(sound->spinlock); } -void sound_update_scene(Main *bmain, struct Scene *scene) +void BKE_sound_update_scene(Main *bmain, struct Scene *scene) { Object *ob; Base *base; @@ -806,20 +789,20 @@ void sound_update_scene(Main *bmain, struct Scene *scene) scene->speaker_handles = new_set; } -void *sound_get_factory(void *sound) +void *BKE_sound_get_factory(void *sound) { return ((bSound *)sound)->playback_handle; } /* stupid wrapper because AUD_C-API.h includes Python.h which makesrna doesn't like */ -float sound_get_length(bSound *sound) +float BKE_sound_get_length(bSound *sound) { AUD_SoundInfo info = AUD_getInfo(sound->playback_handle); return info.length; } -bool sound_is_jack_supported(void) +bool BKE_sound_is_jack_supported(void) { return (bool)AUD_isJackSupported(); } @@ -828,47 +811,47 @@ bool sound_is_jack_supported(void) #include "BLI_utildefines.h" -int sound_define_from_str(const char *UNUSED(str)) { return -1; } -void sound_force_device(int UNUSED(device)) {} -void sound_init_once(void) {} -void sound_init(struct Main *UNUSED(bmain)) {} -void sound_exit(void) {} -void sound_exit_once(void) {} -void sound_cache(struct bSound *UNUSED(sound)) {} -void sound_delete_cache(struct bSound *UNUSED(sound)) {} -void sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {} -void sound_create_scene(struct Scene *UNUSED(scene)) {} -void sound_destroy_scene(struct Scene *UNUSED(scene)) {} -void sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {} -void *sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), - int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } -void *sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene), - struct Sequence *UNUSED(sequence)) { return NULL; } -void *sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe), - int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } -void *sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; } -void sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {} -void sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {} -void sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe), - int UNUSED(endframe), int UNUSED(frameskip)) {} -void sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {} -void sound_play_scene(struct Scene *UNUSED(scene)) {} -void sound_stop_scene(struct Scene *UNUSED(scene)) {} -void sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {} -float sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; } -int sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; } -void sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); } -void sound_init_main(struct Main *UNUSED(bmain)) {} -void sound_set_cfra(int UNUSED(cfra)) {} -void sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {} -void sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {} -void sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {} -void sound_update_scene_listener(struct Scene *UNUSED(scene)) {} -void sound_update_fps(struct Scene *UNUSED(scene)) {} -void sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {} -void sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {} -void sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {} -void sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {} -float sound_get_length(struct bSound *UNUSED(sound)) { return 0; } -bool sound_is_jack_supported(void) { return false; } +int BKE_sound_define_from_str(const char *UNUSED(str)) { return -1; } +void BKE_sound_force_device(int UNUSED(device)) {} +void BKE_sound_init_once(void) {} +void BKE_sound_init(struct Main *UNUSED(bmain)) {} +void BKE_sound_exit(void) {} +void BKE_sound_exit_once(void) {} +void BKE_sound_cache(struct bSound *UNUSED(sound)) {} +void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {} +void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {} +void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {} +void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {} +void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {} +void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), + int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } +void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene), + struct Sequence *UNUSED(sequence)) { return NULL; } +void *BKE_sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe), + int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } +void *BKE_sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; } +void BKE_sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {} +void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {} +void BKE_sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe), + int UNUSED(endframe), int UNUSED(frameskip)) {} +void BKE_sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {} +void BKE_sound_play_scene(struct Scene *UNUSED(scene)) {} +void BKE_sound_stop_scene(struct Scene *UNUSED(scene)) {} +void BKE_sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {} +float BKE_sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; } +int BKE_sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; } +void BKE_sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); } +void BKE_sound_init_main(struct Main *UNUSED(bmain)) {} +void BKE_sound_set_cfra(int UNUSED(cfra)) {} +void BKE_sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {} +void BKE_sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {} +void BKE_sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {} +void BKE_sound_update_scene_listener(struct Scene *UNUSED(scene)) {} +void BKE_sound_update_fps(struct Scene *UNUSED(scene)) {} +void BKE_sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {} +void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {} +void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {} +void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {} +float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; } +bool BKE_sound_is_jack_supported(void) { return false; } #endif /* WITH_AUDASPACE */ diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index b11d0ae03b0..7a800555144 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -130,5 +130,5 @@ void BKE_speaker_free(Speaker *spk) if (spk->sound) spk->sound->id.us--; - BKE_free_animdata((ID *)spk); + BKE_animdata_free((ID *)spk); } diff --git a/source/blender/blenkernel/intern/strands.c b/source/blender/blenkernel/intern/strands.c new file mode 100644 index 00000000000..38d35a7309e --- /dev/null +++ b/source/blender/blenkernel/intern/strands.c @@ -0,0 +1,407 @@ +/* + * Copyright 2015, Blender Foundation. + * + * 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. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_strands.h" + +Strands *BKE_strands_new(int curves, int verts) +{ + Strands *strands = MEM_mallocN(sizeof(Strands), "strands"); + + strands->totcurves = curves; + strands->curves = MEM_mallocN(sizeof(StrandsCurve) * curves, "strand curves"); + + strands->totverts = verts; + strands->verts = MEM_mallocN(sizeof(StrandsVertex) * verts, "strand vertices"); + + /* must be added explicitly */ + strands->state = NULL; + + return strands; +} + +Strands *BKE_strands_copy(Strands *strands) +{ + Strands *new_strands = MEM_dupallocN(strands); + if (new_strands->curves) + new_strands->curves = MEM_dupallocN(new_strands->curves); + if (new_strands->verts) + new_strands->verts = MEM_dupallocN(new_strands->verts); + if (new_strands->state) + new_strands->state = MEM_dupallocN(new_strands->state); + return new_strands; +} + +void BKE_strands_free(Strands *strands) +{ + if (strands) { + if (strands->curves) + MEM_freeN(strands->curves); + if (strands->verts) + MEM_freeN(strands->verts); + if (strands->state) + MEM_freeN(strands->state); + MEM_freeN(strands); + } +} + +/* copy the rest positions to initialize the motion state */ +void BKE_strands_state_copy_rest_positions(Strands *strands) +{ + if (strands->state) { + int i; + for (i = 0; i < strands->totverts; ++i) { + copy_v3_v3(strands->state[i].co, strands->verts[i].co); + } + } +} + +/* copy the rest positions to initialize the motion state */ +void BKE_strands_state_clear_velocities(Strands *strands) +{ + if (strands->state) { + int i; + + for (i = 0; i < strands->totverts; ++i) { + zero_v3(strands->state[i].vel); + } + } +} + +void BKE_strands_add_motion_state(Strands *strands) +{ + if (!strands->state) { + int i; + + strands->state = MEM_mallocN(sizeof(StrandsMotionState) * strands->totverts, "strand motion states"); + + BKE_strands_state_copy_rest_positions(strands); + BKE_strands_state_clear_velocities(strands); + + /* initialize normals */ + for (i = 0; i < strands->totverts; ++i) { + copy_v3_v3(strands->state[i].nor, strands->verts[i].nor); + } + } +} + +void BKE_strands_remove_motion_state(Strands *strands) +{ + if (strands) { + if (strands->state) { + MEM_freeN(strands->state); + strands->state = NULL; + } + } +} + +static void calc_normals(Strands *strands, bool use_motion_state) +{ + StrandIterator it_strand; + for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) { + StrandEdgeIterator it_edge; + int numverts = it_strand.curve->numverts; + if (use_motion_state) { + for (BKE_strand_edge_iter_init(&it_edge, &it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) { + sub_v3_v3v3(it_edge.state0->nor, it_edge.state1->co, it_edge.state0->co); + normalize_v3(it_edge.state0->nor); + } + if (numverts > 1) + copy_v3_v3(it_strand.state[numverts-1].nor, it_strand.state[numverts-2].nor); + } + else { + for (BKE_strand_edge_iter_init(&it_edge, &it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) { + sub_v3_v3v3(it_edge.vertex0->nor, it_edge.vertex1->co, it_edge.vertex0->co); + normalize_v3(it_edge.vertex0->nor); + } + if (numverts > 1) + copy_v3_v3(it_strand.verts[numverts-1].nor, it_strand.verts[numverts-2].nor); + } + } +} + +void BKE_strands_ensure_normals(Strands *strands) +{ + const bool use_motion_state = (strands->state); + + calc_normals(strands, false); + + if (use_motion_state) + calc_normals(strands, true); +} + +void BKE_strands_get_minmax(Strands *strands, float min[3], float max[3], bool use_motion_state) +{ + int numverts = strands->totverts; + int i; + + if (use_motion_state && strands->state) { + for (i = 0; i < numverts; ++i) { + minmax_v3v3_v3(min, max, strands->state[i].co); + } + } + else { + for (i = 0; i < numverts; ++i) { + minmax_v3v3_v3(min, max, strands->verts[i].co); + } + } +} + +/* ------------------------------------------------------------------------- */ + +StrandsChildren *BKE_strands_children_new(int curves, int verts) +{ + StrandsChildren *strands = MEM_mallocN(sizeof(StrandsChildren), "strands children"); + + strands->totcurves = curves; + strands->curves = MEM_mallocN(sizeof(StrandsChildCurve) * curves, "strand children curves"); + + strands->totverts = verts; + strands->verts = MEM_mallocN(sizeof(StrandsChildVertex) * verts, "strand children vertices"); + + /* must be added explicitly */ + strands->curve_uvs = NULL; + strands->numuv = 0; + strands->curve_vcols = NULL; + strands->numvcol = 0; + + return strands; +} + +StrandsChildren *BKE_strands_children_copy(StrandsChildren *strands) +{ + StrandsChildren *new_strands = MEM_dupallocN(strands); + if (new_strands->curves) + new_strands->curves = MEM_dupallocN(new_strands->curves); + if (new_strands->curve_uvs) + new_strands->curve_uvs = MEM_dupallocN(new_strands->curve_uvs); + if (new_strands->curve_vcols) + new_strands->curve_vcols = MEM_dupallocN(new_strands->curve_vcols); + if (new_strands->verts) + new_strands->verts = MEM_dupallocN(new_strands->verts); + return new_strands; +} + +void BKE_strands_children_free(StrandsChildren *strands) +{ + if (strands) { + if (strands->curves) + MEM_freeN(strands->curves); + if (strands->curve_uvs) + MEM_freeN(strands->curve_uvs); + if (strands->curve_vcols) + MEM_freeN(strands->curve_vcols); + if (strands->verts) + MEM_freeN(strands->verts); + MEM_freeN(strands); + } +} + +void BKE_strands_children_add_uvs(StrandsChildren *strands, int num_layers) +{ + if (strands->curve_uvs && strands->numuv != num_layers) { + MEM_freeN(strands->curve_uvs); + strands->curve_uvs = NULL; + strands->numuv = 0; + } + + if (!strands->curve_uvs) { + strands->curve_uvs = MEM_callocN(sizeof(StrandsChildCurveUV) * strands->totcurves * num_layers, "strands children uv layers"); + strands->numuv = num_layers; + } +} + +void BKE_strands_children_add_vcols(StrandsChildren *strands, int num_layers) +{ + if (strands->curve_vcols && strands->numvcol != num_layers) { + MEM_freeN(strands->curve_vcols); + strands->curve_vcols = NULL; + strands->numvcol = 0; + } + + if (!strands->curve_vcols) { + strands->curve_vcols = MEM_callocN(sizeof(StrandsChildCurveVCol) * strands->totcurves * num_layers, "strands children vcol layers"); + strands->numvcol = num_layers; + } +} + +static int *strands_calc_vertex_start(Strands *strands) +{ + int *vertstart = MEM_mallocN(sizeof(int) * strands->totcurves, "strand curves vertex start"); + StrandIterator it_strand; + int start; + + start = 0; + for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) { + vertstart[it_strand.index] = start; + start += it_strand.curve->numverts; + } + + return vertstart; +} + + +/* 'out' is an optional array to write final positions to, instead of writing back to vertex locations. + * It must be at least as large as the number of vertices. + */ +static void strands_children_strand_deform(StrandChildIterator *it_strand, Strands *parents, int *vertstart, bool use_motion, float (*out)[3]) +{ + int i; + + if (!parents || !vertstart) + return; + + if (!parents->state) + use_motion = false; + + for (i = 0; i < 4; ++i) { + int p = it_strand->curve->parents[i]; + float w = it_strand->curve->parent_weights[i]; + if (p >= 0 && w > 0.0f) { + StrandsCurve *parent = &parents->curves[p]; + StrandsVertex *pverts; + StrandsMotionState *pstate; + int pv0, pv1; + StrandChildVertexIterator it_vert; + + if (parent->numverts <= 0) + continue; + + pverts = &parents->verts[vertstart[p]]; + pstate = &parents->state[vertstart[p]]; + pv0 = 0; + for (BKE_strand_child_vertex_iter_init(&it_vert, it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) { + float time = it_vert.vertex->time; + float dt, x; + float poffset0[3], poffset1[3], offset[3]; + + /* advance to the matching parent edge for interpolation */ + while (pv0 < parent->numverts-1 && pverts[pv0+1].time < time) + ++pv0; + pv1 = (pv0 < parent->numverts-1)? pv0+1 : pv0; + + if (use_motion) { + sub_v3_v3v3(poffset0, pstate[pv0].co, pverts[pv0].base); + sub_v3_v3v3(poffset1, pstate[pv1].co, pverts[pv1].base); + } + else { + sub_v3_v3v3(poffset0, pverts[pv0].co, pverts[pv0].base); + sub_v3_v3v3(poffset1, pverts[pv1].co, pverts[pv1].base); + } + + dt = pverts[pv1].time - pverts[pv0].time; + x = dt > 0.0f ? (time - pverts[pv0].time) / dt : 0.0f; + CLAMP(x, 0.0f, 1.0f); + interp_v3_v3v3(offset, poffset0, poffset1, x); + + if (out) + madd_v3_v3fl(out[it_vert.index], offset, w); + else + madd_v3_v3fl(it_vert.vertex->co, offset, w); + } + } + } +} + +void BKE_strands_children_deform(StrandsChildren *strands, Strands *parents, bool use_motion) +{ + int *vertstart = NULL; + StrandChildIterator it_strand; + + if (parents) + vertstart = strands_calc_vertex_start(parents); + + for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) { + /* move child strands from their local root space to object space */ + StrandChildVertexIterator it_vert; + for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) { + mul_v3_m4v3(it_vert.vertex->co, it_strand.curve->root_matrix, it_vert.vertex->base); + } + + strands_children_strand_deform(&it_strand, parents, vertstart, use_motion, NULL); + } + + if (vertstart) + MEM_freeN(vertstart); +} + +static void calc_child_normals(StrandsChildren *strands) +{ + StrandChildIterator it_strand; + for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) { + StrandChildEdgeIterator it_edge; + int numverts = it_strand.curve->numverts; + for (BKE_strand_child_edge_iter_init(&it_edge, &it_strand); BKE_strand_child_edge_iter_valid(&it_edge); BKE_strand_child_edge_iter_next(&it_edge)) { + sub_v3_v3v3(it_edge.vertex0->nor, it_edge.vertex1->co, it_edge.vertex0->co); + normalize_v3(it_edge.vertex0->nor); + } + if (numverts > 1) + copy_v3_v3(it_strand.verts[numverts-1].nor, it_strand.verts[numverts-2].nor); + } +} + +void BKE_strands_children_ensure_normals(StrandsChildren *strands) +{ + calc_child_normals(strands); +} + +void BKE_strands_children_get_minmax(StrandsChildren *strands, float min[3], float max[3]) +{ + int numverts = strands->totverts; + int i; + + for (i = 0; i < numverts; ++i) { + minmax_v3v3_v3(min, max, strands->verts[i].co); + } +} + +/* ------------------------------------------------------------------------- */ + +void BKE_strand_bend_iter_transform_rest(StrandBendIterator *iter, float mat[3][3]) +{ + float dir0[3], dir1[3]; + + sub_v3_v3v3(dir0, iter->vertex1->co, iter->vertex0->co); + sub_v3_v3v3(dir1, iter->vertex2->co, iter->vertex1->co); + normalize_v3(dir0); + normalize_v3(dir1); + + /* rotation between segments */ + rotation_between_vecs_to_mat3(mat, dir0, dir1); +} + +void BKE_strand_bend_iter_transform_state(StrandBendIterator *iter, float mat[3][3]) +{ + if (iter->state0) { + float dir0[3], dir1[3]; + + sub_v3_v3v3(dir0, iter->state1->co, iter->state0->co); + sub_v3_v3v3(dir1, iter->state2->co, iter->state1->co); + normalize_v3(dir0); + normalize_v3(dir1); + + /* rotation between segments */ + rotation_between_vecs_to_mat3(mat, dir0, dir1); + } + else + unit_m3(mat); +} diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index fc97d156852..16f218d5fb6 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -301,7 +301,11 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */ limit[0] = limit[1] = STD_UV_CONNECT_LIMIT; - vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, 0, limit); + /* previous behavior here is without accounting for winding, however this causes stretching in + * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially + * intention is to treat merged vertices from mirror modifier as seams, see code below with ME_VERT_MERGED + * This fixes a very old regression (2.49 was correct here) */ + vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true); if (!vmap) return 0; @@ -2041,7 +2045,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) ccgdm_pbvh_update(ccgdm); if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) { - if (dm->numTessFaceData) { + if (BKE_pbvh_has_faces(ccgdm->pbvh)) { BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, setMaterial, false); glShadeModel(GL_FLAT); @@ -3105,7 +3109,6 @@ static void ccgDM_release(DerivedMesh *dm) if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap); if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces); if (ccgdm->gridData) MEM_freeN(ccgdm->gridData); - if (ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency); if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset); if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats); if (ccgdm->gridHidden) { @@ -3416,46 +3419,11 @@ static int ccgDM_getGridSize(DerivedMesh *dm) return ccgSubSurf_getGridSize(ccgdm->ss); } -static int ccgdm_adjacent_grid(int *gridOffset, CCGFace *f, int S, int offset) -{ - CCGFace *adjf; - CCGEdge *e; - int i, j = 0, numFaces, fIndex, numEdges = 0; - - e = ccgSubSurf_getFaceEdge(f, S); - numFaces = ccgSubSurf_getEdgeNumFaces(e); - - if (numFaces != 2) - return -1; - - for (i = 0; i < numFaces; i++) { - adjf = ccgSubSurf_getEdgeFace(e, i); - - if (adjf != f) { - numEdges = ccgSubSurf_getFaceNumVerts(adjf); - for (j = 0; j < numEdges; j++) - if (ccgSubSurf_getFaceEdge(adjf, j) == e) - break; - - if (j != numEdges) - break; - } - } - - if (numEdges == 0) - return -1; - - fIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(adjf)); - - return gridOffset[fIndex] + (j + offset) % numEdges; -} - static void ccgdm_create_grids(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; CCGElem **gridData; - DMGridAdjacency *gridAdjacency, *adj; DMFlagMat *gridFlagMats; CCGFace **gridFaces; int *gridOffset; @@ -3481,7 +3449,6 @@ static void ccgdm_create_grids(DerivedMesh *dm) /* compute grid data */ gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData"); - gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency) * numGrids, "ccgdm.gridAdjacency"); gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces"); gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats"); @@ -3492,29 +3459,14 @@ static void ccgdm_create_grids(DerivedMesh *dm) int numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++, gIndex++) { - int prevS = (S - 1 + numVerts) % numVerts; - int nextS = (S + 1 + numVerts) % numVerts; - gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S); gridFaces[gIndex] = f; gridFlagMats[gIndex] = ccgdm->faceFlags[index]; - - adj = &gridAdjacency[gIndex]; - - adj->index[0] = gIndex - S + nextS; - adj->rotation[0] = 3; - adj->index[1] = ccgdm_adjacent_grid(gridOffset, f, prevS, 0); - adj->rotation[1] = 1; - adj->index[2] = ccgdm_adjacent_grid(gridOffset, f, S, 1); - adj->rotation[2] = 3; - adj->index[3] = gIndex - S + prevS; - adj->rotation[3] = 1; } } ccgdm->gridData = gridData; ccgdm->gridFaces = gridFaces; - ccgdm->gridAdjacency = gridAdjacency; ccgdm->gridOffset = gridOffset; ccgdm->gridFlagMats = gridFlagMats; } @@ -3527,14 +3479,6 @@ static CCGElem **ccgDM_getGridData(DerivedMesh *dm) return ccgdm->gridData; } -static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - ccgdm_create_grids(dm); - return ccgdm->gridAdjacency; -} - static int *ccgDM_getGridOffset(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; @@ -3617,7 +3561,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) * when the ccgdm gets remade, the assumption is that the topology * does not change. */ ccgdm_create_grids(dm); - BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, + BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } @@ -3636,7 +3580,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) numGrids = ccgDM_getNumGrids(dm); ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); - BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, + BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } else if (ob->type == OB_MESH) { @@ -3764,7 +3708,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.getNumGrids = ccgDM_getNumGrids; ccgdm->dm.getGridSize = ccgDM_getGridSize; ccgdm->dm.getGridData = ccgDM_getGridData; - ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency; ccgdm->dm.getGridOffset = ccgDM_getGridOffset; ccgdm->dm.getGridKey = ccgDM_getGridKey; ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats; @@ -4131,7 +4074,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( SubsurfFlags flags) { int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0; - CCGFlags useAging = smd->flags & eSubsurfModifierFlag_DebugIncr ? CCG_USE_AGING : 0; + CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); CCGDerivedMesh *result; @@ -4139,7 +4082,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( /* note: editmode calculation can only run once per * modifier stack evaluation (uses freed cache) [#36299] */ if (flags & SUBSURF_FOR_EDIT_MODE) { - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels; + int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); @@ -4151,7 +4094,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ CCGSubSurf *ss; - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels) : smd->renderLevels; + int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels; if (levels == 0) return dm; @@ -4167,7 +4110,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( } else { int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels; + int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; CCGSubSurf *ss; /* It is quite possible there is a much better place to do this. It diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 9f441b45db9..89456763b95 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -330,7 +330,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len text->curc = text->selc = 0; } -int BKE_text_reload(Text *text) +bool BKE_text_reload(Text *text) { FILE *fp; int len; @@ -339,13 +339,24 @@ int BKE_text_reload(Text *text) char str[FILE_MAX]; BLI_stat_t st; - if (!text->name) return 0; - + if (!text->name) { + return false; + } + BLI_strncpy(str, text->name, FILE_MAX); BLI_path_abs(str, G.main->name); fp = BLI_fopen(str, "r"); - if (fp == NULL) return 0; + if (fp == NULL) { + return false; + } + fseek(fp, 0L, SEEK_END); + len = ftell(fp); + fseek(fp, 0L, SEEK_SET); + if (UNLIKELY(len == -1)) { + fclose(fp); + return false; + } /* free memory: */ @@ -363,11 +374,6 @@ int BKE_text_reload(Text *text) MEM_freeN(text->undo_buf); init_undo_text(text); - fseek(fp, 0L, SEEK_END); - len = ftell(fp); - fseek(fp, 0L, SEEK_SET); - - buffer = MEM_mallocN(len, "text_buffer"); /* under windows fread can return less than len bytes because * of CR stripping */ @@ -385,7 +391,7 @@ int BKE_text_reload(Text *text) text_from_buf(text, buffer, len); MEM_freeN(buffer); - return 1; + return true; } Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal) @@ -402,8 +408,18 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const BLI_path_abs(str, relpath); fp = BLI_fopen(str, "r"); - if (fp == NULL) return NULL; - + if (fp == NULL) { + return NULL; + } + + fseek(fp, 0L, SEEK_END); + len = ftell(fp); + fseek(fp, 0L, SEEK_SET); + if (UNLIKELY(len == -1)) { + fclose(fp); + return NULL; + } + ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str)); ta->id.us = 1; @@ -423,10 +439,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const /* clear undo buffer */ init_undo_text(ta); - - fseek(fp, 0L, SEEK_END); - len = ftell(fp); - fseek(fp, 0L, SEEK_SET); buffer = MEM_mallocN(len, "text_buffer"); /* under windows fread can return less than len bytes because @@ -473,6 +485,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta) BLI_listbase_clear(&tan->lines); tan->curl = tan->sell = NULL; + tan->compiled = NULL; tan->nlines = ta->nlines; @@ -651,7 +664,7 @@ void BKE_text_unlink(Main *bmain, Text *text) } } - /* Freestyle (while looping oer the scene) */ + /* Freestyle (while looping over the scene) */ for (srl = sce->r.layers.first; srl; srl = srl->next) { for (module = srl->freestyleConfig.modules.first; module; module = module->next) { if (module->script == text) @@ -1895,6 +1908,47 @@ static void txt_undo_add_charop(Text *text, int op_start, unsigned int c) text->undo_buf[text->undo_pos + 1] = 0; } +/* extends Link */ +struct LinkInt { + struct LinkInt *next, *prev; + int value; +}; + +/* unindentLines points to a ListBase composed of LinkInt elements, listing the numbers + * of the lines that should not be indented back. */ +static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask, const int line_index_mask_len) +{ + struct LinkInt *idata; + + BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len); + + /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */ + if (!max_undo_test(text, 1 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) { + return; + } + + /* Opening buffer sequence with OP */ + text->undo_pos++; + text->undo_buf[text->undo_pos] = UNDO_UNINDENT; + text->undo_pos++; + /* Adding number of line numbers to read */ + txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + + /* Adding linenumbers of lines that shall not be indented if undoing */ + for (idata = line_index_mask->first; idata; idata = idata->next) { + txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value); + } + + /* Adding number of line numbers to read again */ + txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len); + /* Adding current selection */ + txt_undo_store_cursors(text); + /* Closing with OP (same as above) */ + text->undo_buf[text->undo_pos] = UNDO_UNINDENT; + /* Marking as last undo operation */ + text->undo_buf[text->undo_pos + 1] = 0; +} + static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos) { unsigned short val; @@ -2189,7 +2243,6 @@ void txt_do_undo(Text *text) text->undo_pos--; break; case UNDO_INDENT: - case UNDO_UNINDENT: case UNDO_COMMENT: case UNDO_UNCOMMENT: case UNDO_DUPLICATE: @@ -2203,9 +2256,6 @@ void txt_do_undo(Text *text) if (op == UNDO_INDENT) { txt_unindent(text); } - else if (op == UNDO_UNINDENT) { - txt_indent(text); - } else if (op == UNDO_COMMENT) { txt_uncomment(text); } @@ -2224,6 +2274,37 @@ void txt_do_undo(Text *text) text->undo_pos--; break; + case UNDO_UNINDENT: + { + int count; + int i; + /* Get and restore the cursors */ + txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_move_to(text, curln, curc, 0); + txt_move_to(text, selln, selc, 1); + + /* Un-unindent */ + txt_indent(text); + + /* Get the count */ + count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + /* Iterate! */ + txt_pop_sel(text); + + for (i = 0; i < count; i++) { + txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0); + /* Un-un-unindent */ + txt_unindent(text); + } + /* Restore selection */ + txt_move_to(text, curln, curc, 0); + txt_move_to(text, selln, selc, 1); + /* Jumo over count */ + txt_undo_read_uint32(text->undo_buf, &text->undo_pos); + /* Jump over closing OP byte */ + text->undo_pos--; + break; + } default: //XXX error("Undo buffer error - resetting"); text->undo_pos = -1; @@ -2353,7 +2434,6 @@ void txt_do_redo(Text *text) break; case UNDO_INDENT: - case UNDO_UNINDENT: case UNDO_COMMENT: case UNDO_UNCOMMENT: case UNDO_DUPLICATE: @@ -2369,9 +2449,6 @@ void txt_do_redo(Text *text) if (op == UNDO_INDENT) { txt_indent(text); } - else if (op == UNDO_UNINDENT) { - txt_unindent(text); - } else if (op == UNDO_COMMENT) { txt_comment(text); } @@ -2401,6 +2478,26 @@ void txt_do_redo(Text *text) txt_move_to(text, selln, selc, 1); break; + case UNDO_UNINDENT: + { + int count; + int i; + + text->undo_pos++; + /* Scan all the stuff described in txt_undo_add_unindent_op */ + count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + for (i = 0; i < count; i++) { + txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + } + /* Count again */ + txt_redo_read_uint32(text->undo_buf, &text->undo_pos); + /* Get the selection and re-unindent */ + txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc); + txt_move_to(text, curln, curc, 0); + txt_move_to(text, selln, selc, 1); + txt_unindent(text); + break; + } default: //XXX error("Undo buffer error - resetting"); text->undo_pos = -1; @@ -2801,6 +2898,12 @@ void txt_unindent(Text *text) int indentlen = 1; bool unindented_first = false; + /* List of lines that are already at indent level 0, to store them later into the undo buffer */ + ListBase line_index_mask = {NULL, NULL}; + int line_index_mask_len = 0; + int curl_span_init = 0; + + /* hardcoded: TXT_TABSIZE = 4 spaces: */ int spaceslen = TXT_TABSIZE; @@ -2814,6 +2917,10 @@ void txt_unindent(Text *text) indentlen = spaceslen; } + if (!undoing) { + curl_span_init = txt_get_span(text->lines.first, text->curl); + } + while (true) { bool changed = false; if (STREQLEN(text->curl->line, remove, indentlen)) { @@ -2823,6 +2930,16 @@ void txt_unindent(Text *text) memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1); changed = true; } + else { + if (!undoing) { + /* Create list element for 0 indent line */ + struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__); + idata->value = curl_span_init + num; + BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl)); + BLI_addtail(&line_index_mask, idata); + line_index_mask_len += 1; + } + } txt_make_dirty(text); txt_clean_text(text); @@ -2835,6 +2952,7 @@ void txt_unindent(Text *text) else { text->curl = text->curl->next; num++; + } } @@ -2848,8 +2966,10 @@ void txt_unindent(Text *text) } if (!undoing) { - txt_undo_add_op(text, UNDO_UNINDENT); + txt_undo_add_unindent_op(text, &line_index_mask, line_index_mask_len); } + + BLI_freelistN(&line_index_mask); } void txt_comment(Text *text) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 3293cca76fe..88a412d5e95 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -73,16 +73,16 @@ /* ****************** Mapping ******************* */ -TexMapping *add_tex_mapping(int type) +TexMapping *BKE_texture_mapping_add(int type) { TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping"); - default_tex_mapping(texmap, type); + BKE_texture_mapping_default(texmap, type); return texmap; } -void default_tex_mapping(TexMapping *texmap, int type) +void BKE_texture_mapping_default(TexMapping *texmap, int type) { memset(texmap, 0, sizeof(TexMapping)); @@ -97,7 +97,7 @@ void default_tex_mapping(TexMapping *texmap, int type) texmap->type = type; } -void init_tex_mapping(TexMapping *texmap) +void BKE_texture_mapping_init(TexMapping *texmap) { float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3]; @@ -170,16 +170,16 @@ void init_tex_mapping(TexMapping *texmap) } } -ColorMapping *add_color_mapping(void) +ColorMapping *BKE_texture_colormapping_add(void) { ColorMapping *colormap = MEM_callocN(sizeof(ColorMapping), "ColorMapping"); - default_color_mapping(colormap); + BKE_texture_colormapping_default(colormap); return colormap; } -void default_color_mapping(ColorMapping *colormap) +void BKE_texture_colormapping_default(ColorMapping *colormap) { memset(colormap, 0, sizeof(ColorMapping)); @@ -560,14 +560,14 @@ int colorband_element_remove(struct ColorBand *coba, int index) void BKE_texture_free(Tex *tex) { if (tex->coba) MEM_freeN(tex->coba); - if (tex->env) BKE_free_envmap(tex->env); - if (tex->pd) BKE_free_pointdensity(tex->pd); - if (tex->vd) BKE_free_voxeldata(tex->vd); - if (tex->ot) BKE_free_oceantex(tex->ot); - BKE_free_animdata((struct ID *)tex); + if (tex->env) BKE_texture_envmap_free(tex->env); + if (tex->pd) BKE_texture_pointdensity_free(tex->pd); + if (tex->vd) BKE_texture_voxeldata_free(tex->vd); + if (tex->ot) BKE_texture_ocean_free(tex->ot); + BKE_animdata_free((struct ID *)tex); BKE_previewimg_free(&tex->preview); - BKE_icon_delete((struct ID *)tex); + BKE_icon_id_delete((struct ID *)tex); tex->id.icon_id = 0; if (tex->nodetree) { @@ -578,7 +578,7 @@ void BKE_texture_free(Tex *tex) /* ------------------------------------------------------------------------- */ -void default_tex(Tex *tex) +void BKE_texture_default(Tex *tex) { tex->type = TEX_IMAGE; tex->ima = NULL; @@ -629,7 +629,7 @@ void default_tex(Tex *tex) tex->env->stype = ENV_ANIM; tex->env->clipsta = 0.1; tex->env->clipend = 100; - tex->env->cuberes = 600; + tex->env->cuberes = 512; tex->env->depth = 0; } @@ -657,25 +657,25 @@ void default_tex(Tex *tex) tex->preview = NULL; } -void tex_set_type(Tex *tex, int type) +void BKE_texture_type_set(Tex *tex, int type) { switch (type) { case TEX_VOXELDATA: if (tex->vd == NULL) - tex->vd = BKE_add_voxeldata(); + tex->vd = BKE_texture_voxeldata_add(); break; case TEX_POINTDENSITY: if (tex->pd == NULL) - tex->pd = BKE_add_pointdensity(); + tex->pd = BKE_texture_pointdensity_add(); break; case TEX_ENVMAP: if (tex->env == NULL) - tex->env = BKE_add_envmap(); + tex->env = BKE_texture_envmap_add(); break; case TEX_OCEAN: if (tex->ot == NULL) - tex->ot = BKE_add_oceantex(); + tex->ot = BKE_texture_ocean_add(); break; } @@ -684,20 +684,20 @@ void tex_set_type(Tex *tex, int type) /* ------------------------------------------------------------------------- */ -Tex *add_texture(Main *bmain, const char *name) +Tex *BKE_texture_add(Main *bmain, const char *name) { Tex *tex; tex = BKE_libblock_alloc(bmain, ID_TE, name); - default_tex(tex); + BKE_texture_default(tex); return tex; } /* ------------------------------------------------------------------------- */ -void default_mtex(MTex *mtex) +void BKE_texture_mtex_default(MTex *mtex) { mtex->texco = TEXCO_UV; mtex->mapto = MAP_COL; @@ -767,19 +767,19 @@ void default_mtex(MTex *mtex) /* ------------------------------------------------------------------------- */ -MTex *add_mtex(void) +MTex *BKE_texture_mtex_add(void) { MTex *mtex; - mtex = MEM_callocN(sizeof(MTex), "add_mtex"); + mtex = MEM_callocN(sizeof(MTex), "BKE_texture_mtex_add"); - default_mtex(mtex); + BKE_texture_mtex_default(mtex); return mtex; } /* slot -1 for first free ID */ -MTex *add_mtex_id(ID *id, int slot) +MTex *BKE_texture_mtex_add_id(ID *id, int slot) { MTex **mtex_ar; short act; @@ -820,7 +820,7 @@ MTex *add_mtex_id(ID *id, int slot) ((Material *)id)->septex &= ~(1 << slot); } - mtex_ar[slot] = add_mtex(); + mtex_ar[slot] = BKE_texture_mtex_add(); return mtex_ar[slot]; } @@ -840,10 +840,10 @@ Tex *BKE_texture_copy(Tex *tex) } if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); - if (texn->env) texn->env = BKE_copy_envmap(texn->env); - if (texn->pd) texn->pd = BKE_copy_pointdensity(texn->pd); + if (texn->env) texn->env = BKE_texture_envmap_copy(texn->env); + if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); if (texn->vd) texn->vd = MEM_dupallocN(texn->vd); - if (texn->ot) texn->ot = BKE_copy_oceantex(texn->ot); + if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot); if (tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); if (tex->nodetree) { @@ -861,7 +861,7 @@ Tex *BKE_texture_copy(Tex *tex) } /* texture copy without adding to main dbase */ -Tex *localize_texture(Tex *tex) +Tex *BKE_texture_localize(Tex *tex) { Tex *texn; @@ -871,17 +871,17 @@ Tex *localize_texture(Tex *tex) if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); if (texn->env) { - texn->env = BKE_copy_envmap(texn->env); + texn->env = BKE_texture_envmap_copy(texn->env); id_us_min(&texn->env->ima->id); } - if (texn->pd) texn->pd = BKE_copy_pointdensity(texn->pd); + if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); if (texn->vd) { texn->vd = MEM_dupallocN(texn->vd); if (texn->vd->dataset) texn->vd->dataset = MEM_dupallocN(texn->vd->dataset); } if (texn->ot) { - texn->ot = BKE_copy_oceantex(tex->ot); + texn->ot = BKE_texture_ocean_copy(tex->ot); } texn->preview = NULL; @@ -1132,7 +1132,7 @@ void set_current_lamp_texture(Lamp *la, Tex *newtex) if (newtex) { if (!la->mtex[act]) { - la->mtex[act] = add_mtex(); + la->mtex[act] = BKE_texture_mtex_add(); la->mtex[act]->texco = TEXCO_GLOB; } @@ -1167,7 +1167,7 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex) if (newtex) { if (!linestyle->mtex[act]) { - linestyle->mtex[act] = add_mtex(); + linestyle->mtex[act] = BKE_texture_mtex_add(); linestyle->mtex[act]->texco = TEXCO_STROKE; } @@ -1296,7 +1296,7 @@ void set_current_material_texture(Material *ma, Tex *newtex) if (newtex) { if (!ma->mtex[act]) { - ma->mtex[act] = add_mtex(); + ma->mtex[act] = BKE_texture_mtex_add(); /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */ ma->septex &= ~(1 << act); } @@ -1347,7 +1347,7 @@ void set_current_world_texture(World *wo, Tex *newtex) if (newtex) { if (!wo->mtex[act]) { - wo->mtex[act] = add_mtex(); + wo->mtex[act] = BKE_texture_mtex_add(); wo->mtex[act]->texco = TEXCO_VIEW; } @@ -1398,7 +1398,7 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex) if (newtex) { if (!part->mtex[act]) { - part->mtex[act] = add_mtex(); + part->mtex[act] = BKE_texture_mtex_add(); part->mtex[act]->texco = TEXCO_ORCO; part->mtex[act]->blendtype = MTEX_MUL; } @@ -1414,7 +1414,7 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex) /* ------------------------------------------------------------------------- */ -EnvMap *BKE_add_envmap(void) +EnvMap *BKE_texture_envmap_add(void) { EnvMap *env; @@ -1423,7 +1423,7 @@ EnvMap *BKE_add_envmap(void) env->stype = ENV_ANIM; env->clipsta = 0.1; env->clipend = 100.0; - env->cuberes = 600; + env->cuberes = 512; env->viewscale = 0.5; return env; @@ -1431,7 +1431,7 @@ EnvMap *BKE_add_envmap(void) /* ------------------------------------------------------------------------- */ -EnvMap *BKE_copy_envmap(EnvMap *env) +EnvMap *BKE_texture_envmap_copy(EnvMap *env) { EnvMap *envn; int a; @@ -1446,7 +1446,7 @@ EnvMap *BKE_copy_envmap(EnvMap *env) /* ------------------------------------------------------------------------- */ -void BKE_free_envmapdata(EnvMap *env) +void BKE_texture_envmap_free_data(EnvMap *env) { unsigned int part; @@ -1460,21 +1460,18 @@ void BKE_free_envmapdata(EnvMap *env) /* ------------------------------------------------------------------------- */ -void BKE_free_envmap(EnvMap *env) +void BKE_texture_envmap_free(EnvMap *env) { - BKE_free_envmapdata(env); + BKE_texture_envmap_free_data(env); MEM_freeN(env); } /* ------------------------------------------------------------------------- */ -PointDensity *BKE_add_pointdensity(void) +void BKE_texture_pointdensity_init_data(PointDensity *pd) { - PointDensity *pd; - - pd = MEM_callocN(sizeof(PointDensity), "pointdensity"); pd->flag = 0; pd->radius = 0.3f; pd->falloff_type = TEX_PD_FALLOFF_STD; @@ -1498,11 +1495,16 @@ PointDensity *BKE_add_pointdensity(void) pd->falloff_curve->cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE; curvemap_reset(pd->falloff_curve->cm, &pd->falloff_curve->clipr, pd->falloff_curve->preset, CURVEMAP_SLOPE_POSITIVE); curvemapping_changed(pd->falloff_curve, false); +} +PointDensity *BKE_texture_pointdensity_add(void) +{ + PointDensity *pd = MEM_callocN(sizeof(PointDensity), "pointdensity"); + BKE_texture_pointdensity_init_data(pd); return pd; } -PointDensity *BKE_copy_pointdensity(PointDensity *pd) +PointDensity *BKE_texture_pointdensity_copy(PointDensity *pd) { PointDensity *pdn; @@ -1514,7 +1516,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd) return pdn; } -void BKE_free_pointdensitydata(PointDensity *pd) +void BKE_texture_pointdensity_free_data(PointDensity *pd) { if (pd->point_tree) { BLI_bvhtree_free(pd->point_tree); @@ -1532,15 +1534,15 @@ void BKE_free_pointdensitydata(PointDensity *pd) curvemapping_free(pd->falloff_curve); /* can be NULL */ } -void BKE_free_pointdensity(PointDensity *pd) +void BKE_texture_pointdensity_free(PointDensity *pd) { - BKE_free_pointdensitydata(pd); + BKE_texture_pointdensity_free_data(pd); MEM_freeN(pd); } /* ------------------------------------------------------------------------- */ -void BKE_free_voxeldatadata(VoxelData *vd) +void BKE_texture_voxeldata_free_data(VoxelData *vd) { if (vd->dataset) { MEM_freeN(vd->dataset); @@ -1549,13 +1551,13 @@ void BKE_free_voxeldatadata(VoxelData *vd) } -void BKE_free_voxeldata(VoxelData *vd) +void BKE_texture_voxeldata_free(VoxelData *vd) { - BKE_free_voxeldatadata(vd); + BKE_texture_voxeldata_free_data(vd); MEM_freeN(vd); } -VoxelData *BKE_add_voxeldata(void) +VoxelData *BKE_texture_voxeldata_add(void) { VoxelData *vd; @@ -1573,7 +1575,7 @@ VoxelData *BKE_add_voxeldata(void) return vd; } -VoxelData *BKE_copy_voxeldata(VoxelData *vd) +VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd) { VoxelData *vdn; @@ -1585,7 +1587,7 @@ VoxelData *BKE_copy_voxeldata(VoxelData *vd) /* ------------------------------------------------------------------------- */ -OceanTex *BKE_add_oceantex(void) +OceanTex *BKE_texture_ocean_add(void) { OceanTex *ot; @@ -1596,14 +1598,14 @@ OceanTex *BKE_add_oceantex(void) return ot; } -OceanTex *BKE_copy_oceantex(struct OceanTex *ot) +OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot) { OceanTex *otn = MEM_dupallocN(ot); return otn; } -void BKE_free_oceantex(struct OceanTex *ot) +void BKE_texture_ocean_free(struct OceanTex *ot) { MEM_freeN(ot); } @@ -1651,7 +1653,9 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture) /* ------------------------------------------------------------------------- */ -void BKE_texture_get_value(Scene *scene, Tex *texture, float *tex_co, TexResult *texres, bool use_color_management) +void BKE_texture_get_value( + const Scene *scene, Tex *texture, + float *tex_co, TexResult *texres, bool use_color_management) { int result_type; bool do_color_manage = false; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 0037002f6d8..f9ae987db70 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -547,7 +547,7 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i * - If action is TRACK_CLEAR_UPTO path from the beginning up to * ref_frame-1 will be clear. * - * - If action is TRACK_CLEAR_ALL only mareker at frame ref_frame will remain. + * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain. * * NOTE: frame number should be in clip space, not scene space */ @@ -730,7 +730,7 @@ MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieT return NULL; } -MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r) +MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **r_tracksbase) { MovieTrackingObject *object; int cur = 1; @@ -743,7 +743,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int while (track) { if (track->flag & TRACK_HAS_BUNDLE) { if (cur == tracknr) { - *tracksbase_r = tracksbase; + *r_tracksbase = tracksbase; return track; } @@ -756,7 +756,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int object = object->next; } - *tracksbase_r = NULL; + *r_tracksbase = NULL; return NULL; } @@ -1302,6 +1302,95 @@ void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base) } } +bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track, + MovieTrackingTrack *track) +{ + int i; + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == track) { + return true; + } + } + return false; +} + +bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track, + MovieTrackingTrack *track) +{ + int i, track_index; + MovieTrackingTrack **new_point_tracks; + + if (plane_track->point_tracksnr <= 4) { + return false; + } + + new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1), + "new point tracks array"); + + for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] != track) { + new_point_tracks[track_index++] = plane_track->point_tracks[i]; + } + } + + MEM_freeN(plane_track->point_tracks); + plane_track->point_tracks = new_point_tracks; + plane_track->point_tracksnr--; + + return true; +} + +void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking, + MovieTrackingTrack *track) +{ + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + next_plane_track = plane_track->next; + if (BKE_tracking_plane_track_has_point_track(plane_track, track)) { + if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) { + /* Delete planes with less than 3 point tracks in it. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + } + } +} + +void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track, + MovieTrackingTrack *old_track, + MovieTrackingTrack *new_track) +{ + int i; + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == old_track) { + plane_track->point_tracks[i] = new_track; + break; + } + } +} + +void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking, + MovieTrackingTrack *old_track, + MovieTrackingTrack *new_track) +{ + MovieTrackingPlaneTrack *plane_track; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) { + BKE_tracking_plane_track_replace_point_track(plane_track, + old_track, + new_track); + } + } +} + /*********************** Plane Marker *************************/ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track, diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 4cb3f2ca493..76261bddfbc 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -534,19 +534,9 @@ void BKE_autotrack_context_finish(AutoTrackContext *context) if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { int track; for (track = 0; track < context->num_tracks; ++track) { - MovieTrackingTrack *old_track; - bool do_update = false; - int j; - - old_track = context->options[track].track; - for (j = 0; j < plane_track->point_tracksnr; j++) { - if (plane_track->point_tracks[j] == old_track) { - do_update = true; - break; - } - } - - if (do_update) { + if (BKE_tracking_plane_track_has_point_track(plane_track, + context->options[track].track)) + { BKE_tracking_track_plane_from_existing_motion( plane_track, context->first_frame); diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 882a6fabef1..56119b732fc 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -423,6 +423,7 @@ void tracking_cameraIntrinscisOptionsFromTracking(MovieTracking *tracking, break; default: BLI_assert(!"Unknown distortion model"); + break; } camera_intrinsics_options->image_width = calibration_width; @@ -454,6 +455,7 @@ void tracking_trackingCameraFromIntrinscisOptions(MovieTracking *tracking, break; default: BLI_assert(!"Unknown distortion model"); + break; } } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 5a2c77b5619..0d83695d2f1 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -370,12 +370,7 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn value_conv = value / unit->scalar; /* Convert to a string */ - { - len = BLI_snprintf(str, len_max, "%.*f", prec, value_conv); - - if (len >= len_max) - len = len_max; - } + len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv); /* Add unit prefix and strip zeros */ diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 699e0d34161..e4736b1f54c 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -63,7 +63,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user) } BKE_previewimg_free(&wrld->preview); - BKE_free_animdata((ID *)wrld); + BKE_animdata_free((ID *)wrld); /* is no lib link block, but world extension */ if (wrld->nodetree) { @@ -74,7 +74,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user) if (wrld->gpumaterial.first) GPU_material_free(&wrld->gpumaterial); - BKE_icon_delete((struct ID *)wrld); + BKE_icon_id_delete((struct ID *)wrld); wrld->id.icon_id = 0; } diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index 85eac1f21ed..cec455e01b9 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -50,26 +50,34 @@ /* ********************** general blender movie support ***************************** */ -static int start_stub(Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty), - ReportList *UNUSED(reports)) +static int start_stub(void *UNUSED(context_v), Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty), + ReportList *UNUSED(reports), bool UNUSED(preview), const char *UNUSED(suffix)) { return 0; } -static void end_stub(void) +static void end_stub(void *UNUSED(context_v)) {} -static int append_stub(RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels), - int UNUSED(rectx), int UNUSED(recty), ReportList *UNUSED(reports)) +static int append_stub(void *UNUSED(context_v), RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels), + int UNUSED(rectx), int UNUSED(recty), const char *UNUSED(suffix), ReportList *UNUSED(reports)) { return 0; } +static void *context_create_stub(void) +{ return NULL; } + +static void context_free_stub(void *UNUSED(context_v)) +{} + #ifdef WITH_AVI # include "AVI_avi.h" /* callbacks */ -static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports); -static void end_avi(void); -static int append_avi(RenderData *rd, int start_frame, int frame, int *pixels, - int rectx, int recty, ReportList *reports); -static void filepath_avi(char *string, RenderData *rd); +static int start_avi(void *context_v, Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix); +static void end_avi(void *context_v); +static int append_avi(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels, + int rectx, int recty, const char *suffix, ReportList *reports); +static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix); +static void *context_create_avi(void); +static void context_free_avi(void *context_v); #endif /* WITH_AVI */ #ifdef WITH_QUICKTIME @@ -93,13 +101,17 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) mh.end_movie = end_stub; mh.get_next_frame = NULL; mh.get_movie_path = NULL; - + mh.context_create = context_create_stub; + mh.context_free = context_free_stub; + /* set the default handle, as builtin */ #ifdef WITH_AVI mh.start_movie = start_avi; mh.append_movie = append_avi; mh.end_movie = end_avi; mh.get_movie_path = filepath_avi; + mh.context_create = context_create_avi; + mh.context_free = context_free_avi; #endif /* do the platform specific handles */ @@ -109,6 +121,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) mh.append_movie = append_qt; mh.end_movie = end_qt; mh.get_movie_path = filepath_qt; + mh.context_create = context_create_qt; + mh.context_free = context_free_qt; } #endif #ifdef WITH_FFMPEG @@ -117,6 +131,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) mh.append_movie = BKE_ffmpeg_append; mh.end_movie = BKE_ffmpeg_end; mh.get_movie_path = BKE_ffmpeg_filepath_get; + mh.context_create = BKE_ffmpeg_context_create; + mh.context_free = BKE_ffmpeg_context_free; } #endif #ifdef WITH_FRAMESERVER @@ -125,13 +141,13 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) mh.append_movie = BKE_frameserver_append; mh.end_movie = BKE_frameserver_end; mh.get_next_frame = BKE_frameserver_loop; + mh.context_create = BKE_frameserver_context_create; + mh.context_free = BKE_frameserver_context_free; } #endif /* in case all above are disabled */ - (void)imtype; - - return &mh; + (void)imtype;return &mh; } /* ****************************************************************** */ @@ -139,12 +155,21 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) #ifdef WITH_AVI -static AviMovie *avi = NULL; - -static void filepath_avi(char *string, RenderData *rd) +static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix) { + int sfra, efra; + if (string == NULL) return; + if (preview) { + sfra = rd->psfra; + efra = rd->pefra; + } + else { + sfra = rd->sfra; + efra = rd->efra; + } + strcpy(string, rd->pic); BLI_path_abs(string, G.main->name); @@ -152,36 +177,36 @@ static void filepath_avi(char *string, RenderData *rd) if (rd->scemode & R_EXTENSION) { if (!BLI_testextensie(string, ".avi")) { - BLI_path_frame_range(string, rd->sfra, rd->efra, 4); + BLI_path_frame_range(string, sfra, efra, 4); strcat(string, ".avi"); } } else { if (BLI_path_frame_check_chars(string)) { - BLI_path_frame_range(string, rd->sfra, rd->efra, 4); + BLI_path_frame_range(string, sfra, efra, 4); } } + + BLI_path_suffix(string, FILE_MAX, suffix, ""); } -static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports) +static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int rectx, int recty, + ReportList *reports, bool preview, const char *suffix) { int x, y; char name[256]; AviFormat format; int quality; double framerate; - - (void)scene; /* unused */ - - filepath_avi(name, rd); + AviMovie *avi = context_v; + + filepath_avi(name, rd, preview, suffix); x = rectx; y = recty; quality = rd->im_format.quality; framerate = (double) rd->frs_sec / (double) rd->frs_sec_base; - - avi = MEM_mallocN(sizeof(AviMovie), "avimovie"); if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) format = AVI_FORMAT_AVI_RGB; else format = AVI_FORMAT_MJPEG; @@ -207,12 +232,13 @@ static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportL return 1; } -static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *pixels, - int rectx, int recty, ReportList *UNUSED(reports)) +static int append_avi(void *context_v, RenderData *UNUSED(rd), int start_frame, int frame, int *pixels, + int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports)) { unsigned int *rt1, *rt2, *rectot; int x, y; char *cp, rt; + AviMovie *avi = context_v; if (avi == NULL) return 0; @@ -243,22 +269,37 @@ static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *p return 1; } -static void end_avi(void) +static void end_avi(void *context_v) { + AviMovie *avi = context_v; + if (avi == NULL) return; AVI_close_compress(avi); - MEM_freeN(avi); - avi = NULL; } + +static void *context_create_avi(void) +{ + AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie"); + return avi; +} + +static void context_free_avi(void *context_v) +{ + AviMovie *avi = context_v; + if (avi) { + MEM_freeN(avi); + } +} + #endif /* WITH_AVI */ /* similar to BKE_image_path_from_imformat() */ -void BKE_movie_filepath_get(char *string, RenderData *rd) +void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix) { bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype); if (mh->get_movie_path) - mh->get_movie_path(string, rd); + mh->get_movie_path(string, rd, preview, suffix); else string[0] = '\0'; } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 128a5da9b68..af71f19c226 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -61,35 +61,38 @@ #include "ffmpeg_compat.h" -static int ffmpeg_type = 0; -static int ffmpeg_codec = AV_CODEC_ID_MPEG4; -static int ffmpeg_audio_codec = AV_CODEC_ID_NONE; -static int ffmpeg_video_bitrate = 1150; -static int ffmpeg_audio_bitrate = 128; -static int ffmpeg_gop_size = 12; -static int ffmpeg_autosplit = 0; -static int ffmpeg_autosplit_count = 0; - -static AVFormatContext *outfile = 0; -static AVStream *video_stream = 0; -static AVStream *audio_stream = 0; -static AVFrame *current_frame = 0; -static struct SwsContext *img_convert_ctx = 0; - -static uint8_t *audio_input_buffer = 0; -static uint8_t *audio_deinterleave_buffer = 0; -static int audio_input_samples = 0; +typedef struct FFMpegContext { + int ffmpeg_type; + int ffmpeg_codec; + int ffmpeg_audio_codec; + int ffmpeg_video_bitrate; + int ffmpeg_audio_bitrate; + int ffmpeg_gop_size; + int ffmpeg_autosplit; + int ffmpeg_autosplit_count; + bool ffmpeg_preview; + + AVFormatContext *outfile; + AVStream *video_stream; + AVStream *audio_stream; + AVFrame *current_frame; + struct SwsContext *img_convert_ctx; + + uint8_t *audio_input_buffer; + uint8_t *audio_deinterleave_buffer; + int audio_input_samples; #ifndef FFMPEG_HAVE_ENCODE_AUDIO2 -static uint8_t *audio_output_buffer = 0; -static int audio_outbuf_size = 0; + uint8_t *audio_output_buffer; + int audio_outbuf_size; #endif -static double audio_time = 0.0f; -static bool audio_deinterleave = false; -static int audio_sample_size = 0; + double audio_time; + bool audio_deinterleave; + int audio_sample_size; #ifdef WITH_AUDASPACE -static AUD_Device *audio_mixdown_device = 0; + AUD_Device *audio_mixdown_device; #endif +} FFMpegContext; #define FFMPEG_AUTOSPLIT_SIZE 2000000000 @@ -98,6 +101,7 @@ static AUD_Device *audio_mixdown_device = 0; static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value); static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value); static void ffmpeg_set_expert_options(RenderData *rd); +static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix); /* Delete a picture buffer */ @@ -116,50 +120,50 @@ static int request_float_audio_buffer(int codec_id) } #ifdef WITH_AUDASPACE -static int write_audio_frame(void) +static int write_audio_frame(FFMpegContext *context) { AVCodecContext *c = NULL; AVPacket pkt; AVFrame *frame = NULL; int got_output = 0; - c = audio_stream->codec; + c = context->audio_stream->codec; av_init_packet(&pkt); pkt.size = 0; pkt.data = NULL; - AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples); - audio_time += (double) audio_input_samples / (double) c->sample_rate; + AUD_readDevice(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples); + context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate; #ifdef FFMPEG_HAVE_ENCODE_AUDIO2 frame = avcodec_alloc_frame(); avcodec_get_frame_defaults(frame); - frame->pts = audio_time / av_q2d(c->time_base); - frame->nb_samples = audio_input_samples; + frame->pts = context->audio_time / av_q2d(c->time_base); + frame->nb_samples = context->audio_input_samples; frame->format = c->sample_fmt; #ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT frame->channel_layout = c->channel_layout; #endif - if (audio_deinterleave) { + if (context->audio_deinterleave) { int channel, i; uint8_t *temp; for (channel = 0; channel < c->channels; channel++) { for (i = 0; i < frame->nb_samples; i++) { - memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size, - audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size); + memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size, + context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size); } } - temp = audio_deinterleave_buffer; - audio_deinterleave_buffer = audio_input_buffer; - audio_input_buffer = temp; + temp = context->audio_deinterleave_buffer; + context->audio_deinterleave_buffer = context->audio_input_buffer; + context->audio_input_buffer = temp; } - avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer, - audio_input_samples * c->channels * audio_sample_size, 1); + avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer, + context->audio_input_samples * c->channels * context->audio_sample_size, 1); if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) { // XXX error("Error writing audio packet"); @@ -171,30 +175,30 @@ static int write_audio_frame(void) return 0; } #else - pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer); + pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer); if (pkt.size < 0) { // XXX error("Error writing audio packet"); return -1; } - pkt.data = audio_output_buffer; + pkt.data = context->audio_output_buffer; got_output = 1; #endif if (got_output) { if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, c->time_base, audio_stream->time_base); + pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base); if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, c->time_base, audio_stream->time_base); + pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base); if (pkt.duration > 0) - pkt.duration = av_rescale_q(pkt.duration, c->time_base, audio_stream->time_base); + pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base); - pkt.stream_index = audio_stream->index; + pkt.stream_index = context->audio_stream->index; pkt.flags |= AV_PKT_FLAG_KEY; - if (av_interleaved_write_frame(outfile, &pkt) != 0) { + if (av_interleaved_write_frame(context->outfile, &pkt) != 0) { fprintf(stderr, "Error writing audio packet!\n"); if (frame) avcodec_free_frame(&frame); @@ -301,11 +305,11 @@ static const char **get_file_extensions(int format) } /* Write a frame to the output file */ -static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportList *reports) +static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports) { int got_output; int ret, success = 1; - AVCodecContext *c = video_stream->codec; + AVCodecContext *c = context->video_stream->codec; AVPacket packet = { 0 }; av_init_packet(&packet); @@ -320,22 +324,22 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis if (ret >= 0 && got_output) { if (packet.pts != AV_NOPTS_VALUE) { - packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base); + packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base); PRINT("Video Frame PTS: %d\n", (int)packet.pts); } else { PRINT("Video Frame PTS: not set\n"); } if (packet.dts != AV_NOPTS_VALUE) { - packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base); + packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base); PRINT("Video Frame DTS: %d\n", (int)packet.dts); } else { PRINT("Video Frame DTS: not set\n"); } - packet.stream_index = video_stream->index; - ret = av_interleaved_write_frame(outfile, &packet); + packet.stream_index = context->video_stream->index; + ret = av_interleaved_write_frame(context->outfile, &packet); success = (ret == 0); } else if (ret < 0) { @@ -349,11 +353,11 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis } /* read and encode a frame of audio from the buffer */ -static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports) +static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports) { uint8_t *rendered_frame; - AVCodecContext *c = video_stream->codec; + AVCodecContext *c = context->video_stream->codec; int width = c->width; int height = c->height; AVFrame *rgb_frame; @@ -366,7 +370,7 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports) } } else { - rgb_frame = current_frame; + rgb_frame = context->current_frame; } rendered_frame = pixels; @@ -410,17 +414,17 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports) } if (c->pix_fmt != PIX_FMT_BGR32) { - sws_scale(img_convert_ctx, (const uint8_t *const *) rgb_frame->data, + sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data, rgb_frame->linesize, 0, c->height, - current_frame->data, current_frame->linesize); + context->current_frame->data, context->current_frame->linesize); delete_picture(rgb_frame); } - current_frame->format = PIX_FMT_BGR32; - current_frame->width = width; - current_frame->height = height; + context->current_frame->format = PIX_FMT_BGR32; + context->current_frame->width = width; + context->current_frame->height = height; - return current_frame; + return context->current_frame; } static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary) @@ -515,7 +519,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char /* prepare a video stream for the output file */ -static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext *of, +static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, int rectx, int recty, char *error, int error_size) { AVStream *st; @@ -541,7 +545,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex c->height = recty; /* FIXME: Really bad hack (tm) for NTSC support */ - if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) { + if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) { c->time_base.den = 2997; c->time_base.num = 100; } @@ -554,8 +558,8 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex c->time_base.num = ((double) rd->frs_sec_base) * 100000; } - c->gop_size = ffmpeg_gop_size; - c->bit_rate = ffmpeg_video_bitrate * 1000; + c->gop_size = context->ffmpeg_gop_size; + c->bit_rate = context->ffmpeg_video_bitrate * 1000; c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000; c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000; c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024; @@ -584,7 +588,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex c->pix_fmt = PIX_FMT_YUV422P; } - if (ffmpeg_type == FFMPEG_XVID) { + if (context->ffmpeg_type == FFMPEG_XVID) { /* arghhhh ... */ c->pix_fmt = PIX_FMT_YUV420P; c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X'); @@ -654,14 +658,14 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex } av_dict_free(&opts); - current_frame = alloc_picture(c->pix_fmt, c->width, c->height); + context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height); - img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC, + context->img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); return st; } -static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size) +static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size) { AVStream *st; AVCodecContext *c; @@ -679,7 +683,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex c->codec_type = AVMEDIA_TYPE_AUDIO; c->sample_rate = rd->ffcodecdata.audio_mixrate; - c->bit_rate = ffmpeg_audio_bitrate * 1000; + c->bit_rate = context->ffmpeg_audio_bitrate * 1000; c->sample_fmt = AV_SAMPLE_FMT_S16; c->channels = rd->ffcodecdata.audio_channels; @@ -746,35 +750,35 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex st->codec->time_base.den = st->codec->sample_rate; #ifndef FFMPEG_HAVE_ENCODE_AUDIO2 - audio_outbuf_size = FF_MIN_BUFFER_SIZE; + context->audio_outbuf_size = FF_MIN_BUFFER_SIZE; #endif if (c->frame_size == 0) // used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD)) // not sure if that is needed anymore, so let's try out if there are any // complaints regarding some ffmpeg versions users might have - audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels; + context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels; else { - audio_input_samples = c->frame_size; + context->audio_input_samples = c->frame_size; #ifndef FFMPEG_HAVE_ENCODE_AUDIO2 - if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size) - audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4; + if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size) + context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4; #endif } - audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt); + context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt); - audio_sample_size = av_get_bytes_per_sample(c->sample_fmt); + context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt); - audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size); + context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size); #ifndef FFMPEG_HAVE_ENCODE_AUDIO2 - audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size); + context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size); #endif - if (audio_deinterleave) - audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size); + if (context->audio_deinterleave) + context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size); - audio_time = 0.0f; + context->audio_time = 0.0f; return st; } @@ -798,7 +802,7 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va av_dict_set(dict, key, buffer, 0); } -static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports) +static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports) { /* Handle to the output file */ AVFormatContext *of; @@ -807,26 +811,26 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report char name[256], error[1024]; const char **exts; - ffmpeg_type = rd->ffcodecdata.type; - ffmpeg_codec = rd->ffcodecdata.codec; - ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; - ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; - ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; - ffmpeg_gop_size = rd->ffcodecdata.gop_size; - ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT; - + context->ffmpeg_type = rd->ffcodecdata.type; + context->ffmpeg_codec = rd->ffcodecdata.codec; + context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; + context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; + context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; + context->ffmpeg_gop_size = rd->ffcodecdata.gop_size; + context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT; + /* Determine the correct filename */ - BKE_ffmpeg_filepath_get(name, rd); + ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix); PRINT("Starting output to %s(ffmpeg)...\n" " Using type=%d, codec=%d, audio_codec=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n" " gop_size=%d, autosplit=%d\n" " render width=%d, render height=%d\n", - name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec, - ffmpeg_video_bitrate, ffmpeg_audio_bitrate, - ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty); + name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec, + context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate, + context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty); - exts = get_file_extensions(ffmpeg_type); + exts = get_file_extensions(context->ffmpeg_type); if (!exts) { BKE_report(reports, RPT_ERROR, "No valid formats found"); return 0; @@ -845,7 +849,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report of->oformat = fmt; of->packet_size = rd->ffcodecdata.mux_packet_size; - if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) { + if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) { ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate); } else { @@ -856,15 +860,15 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report of->max_delay = (int)(0.7 * AV_TIME_BASE); - fmt->audio_codec = ffmpeg_audio_codec; + fmt->audio_codec = context->ffmpeg_audio_codec; BLI_strncpy(of->filename, name, sizeof(of->filename)); /* set the codec to the user's selection */ - switch (ffmpeg_type) { + switch (context->ffmpeg_type) { case FFMPEG_AVI: case FFMPEG_MOV: case FFMPEG_MKV: - fmt->video_codec = ffmpeg_codec; + fmt->video_codec = context->ffmpeg_codec; break; case FFMPEG_OGG: fmt->video_codec = AV_CODEC_ID_THEORA; @@ -907,9 +911,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report } } - if (ffmpeg_type == FFMPEG_DV) { + if (context->ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = AV_CODEC_ID_PCM_S16LE; - if (ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { + if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); av_dict_free(&opts); return 0; @@ -917,9 +921,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report } if (fmt->video_codec != AV_CODEC_ID_NONE) { - video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty, error, sizeof(error)); - PRINT("alloc video stream %p\n", video_stream); - if (!video_stream) { + context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error)); + PRINT("alloc video stream %p\n", context->video_stream); + if (!context->video_stream) { if (error[0]) BKE_report(reports, RPT_ERROR, error); else @@ -930,9 +934,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report } } - if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) { - audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of, error, sizeof(error)); - if (!audio_stream) { + if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) { + context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error)); + if (!context->audio_stream) { if (error[0]) BKE_report(reports, RPT_ERROR, error); else @@ -955,7 +959,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report return 0; } - outfile = of; + context->outfile = of; av_dump_format(of, 0, name, 1); av_dict_free(&opts); @@ -979,11 +983,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report * parameter. * </p> */ -static void flush_ffmpeg(void) +static void flush_ffmpeg(FFMpegContext *context) { int ret = 0; - AVCodecContext *c = video_stream->codec; + AVCodecContext *c = context->video_stream->codec; /* get the delayed frames */ while (1) { int got_output; @@ -999,28 +1003,28 @@ static void flush_ffmpeg(void) break; } if (packet.pts != AV_NOPTS_VALUE) { - packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base); + packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base); PRINT("Video Frame PTS: %d\n", (int) packet.pts); } else { PRINT("Video Frame PTS: not set\n"); } if (packet.dts != AV_NOPTS_VALUE) { - packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base); + packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base); PRINT("Video Frame DTS: %d\n", (int) packet.dts); } else { PRINT("Video Frame DTS: not set\n"); } - packet.stream_index = video_stream->index; - ret = av_interleaved_write_frame(outfile, &packet); + packet.stream_index = context->video_stream->index; + ret = av_interleaved_write_frame(context->outfile, &packet); if (ret != 0) { fprintf(stderr, "Error writing delayed frame %d\n", ret); break; } } - avcodec_flush_buffers(video_stream->codec); + avcodec_flush_buffers(context->video_stream->codec); } /* ********************************************************************** @@ -1028,15 +1032,25 @@ static void flush_ffmpeg(void) * ********************************************************************** */ /* Get the output filename-- similar to the other output formats */ -void BKE_ffmpeg_filepath_get(char *string, RenderData *rd) +static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix) { char autosplit[20]; const char **exts = get_file_extensions(rd->ffcodecdata.type); const char **fe = exts; + int sfra, efra; if (!string || !exts) return; + if (preview) { + sfra = rd->psfra; + efra = rd->pefra; + } + else { + sfra = rd->sfra; + efra = rd->efra; + } + strcpy(string, rd->pic); BLI_path_abs(string, G.main->name); @@ -1045,7 +1059,9 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd) autosplit[0] = 0; if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { - sprintf(autosplit, "_%03d", ffmpeg_autosplit_count); + if (context) { + sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count); + } } if (rd->scemode & R_EXTENSION) { @@ -1059,7 +1075,7 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd) if (*fe == NULL) { strcat(string, autosplit); - BLI_path_frame_range(string, rd->sfra, rd->efra, 4); + BLI_path_frame_range(string, sfra, efra, 4); strcat(string, *exts); } else { @@ -1070,23 +1086,33 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd) } else { if (BLI_path_frame_check_chars(string)) { - BLI_path_frame_range(string, rd->sfra, rd->efra, 4); + BLI_path_frame_range(string, sfra, efra, 4); } strcat(string, autosplit); } + + BLI_path_suffix(string, FILE_MAX, suffix, ""); +} + +void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix) +{ + ffmpeg_filepath_get(NULL, string, rd, preview, suffix); } -int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports) +int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int rectx, int recty, + ReportList *reports, bool preview, const char *suffix) { int success; + FFMpegContext *context = context_v; - ffmpeg_autosplit_count = 0; + context->ffmpeg_autosplit_count = 0; + context->ffmpeg_preview = preview; - success = start_ffmpeg_impl(rd, rectx, recty, reports); + success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports); #ifdef WITH_AUDASPACE - if (audio_stream) { - AVCodecContext *c = audio_stream->codec; + if (context->audio_stream) { + AVCodecContext *c = context->audio_stream->codec; AUD_DeviceSpecs specs; specs.channels = c->channels; @@ -1111,7 +1137,7 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, } specs.rate = rd->ffcodecdata.audio_mixrate; - audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume); + context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume); #ifdef FFMPEG_CODEC_TIME_BASE c->time_base.den = specs.rate; c->time_base.num = 1; @@ -1121,16 +1147,16 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, return success; } -static void end_ffmpeg_impl(int is_autosplit); +static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit); #ifdef WITH_AUDASPACE -static void write_audio_frames(double to_pts) +static void write_audio_frames(FFMpegContext *context, double to_pts) { int finished = 0; - while (audio_stream && !finished) { - if ((audio_time >= to_pts) || - (write_audio_frame())) + while (context->audio_stream && !finished) { + if ((context->audio_time >= to_pts) || + (write_audio_frame(context))) { finished = 1; } @@ -1138,8 +1164,10 @@ static void write_audio_frames(double to_pts) } #endif -int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports) +int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels, + int rectx, int recty, const char *suffix, ReportList *reports) { + FFMpegContext *context = context_v; AVFrame *avframe; int success = 1; @@ -1148,111 +1176,112 @@ int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, i /* why is this done before writing the video frame and again at end_ffmpeg? */ // write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base)); - if (video_stream) { - avframe = generate_video_frame((unsigned char *) pixels, reports); - success = (avframe && write_video_frame(rd, frame - start_frame, avframe, reports)); + if (context->video_stream) { + avframe = generate_video_frame(context, (unsigned char *) pixels, reports); + success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports)); - if (ffmpeg_autosplit) { - if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) { - end_ffmpeg_impl(true); - ffmpeg_autosplit_count++; - success &= start_ffmpeg_impl(rd, rectx, recty, reports); + if (context->ffmpeg_autosplit) { + if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) { + end_ffmpeg_impl(context, true); + context->ffmpeg_autosplit_count++; + success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports); } } } #ifdef WITH_AUDASPACE - write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / (double)rd->frs_sec_base)); + write_audio_frames(context, (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base)); #endif return success; } -static void end_ffmpeg_impl(int is_autosplit) +static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) { unsigned int i; PRINT("Closing ffmpeg...\n"); #if 0 - if (audio_stream) { /* SEE UPPER */ - write_audio_frames(); + if (context->audio_stream) { /* SEE UPPER */ + write_audio_frames(context); } #endif #ifdef WITH_AUDASPACE if (is_autosplit == false) { - if (audio_mixdown_device) { - AUD_closeReadDevice(audio_mixdown_device); - audio_mixdown_device = 0; + if (context->audio_mixdown_device) { + AUD_closeReadDevice(context->audio_mixdown_device); + context->audio_mixdown_device = 0; } } #endif - if (video_stream && video_stream->codec) { + if (context->video_stream && context->video_stream->codec) { PRINT("Flushing delayed frames...\n"); - flush_ffmpeg(); + flush_ffmpeg(context); } - if (outfile) { - av_write_trailer(outfile); + if (context->outfile) { + av_write_trailer(context->outfile); } /* Close the video codec */ - if (video_stream && video_stream->codec) { - avcodec_close(video_stream->codec); - PRINT("zero video stream %p\n", video_stream); - video_stream = 0; + if (context->video_stream && context->video_stream->codec) { + avcodec_close(context->video_stream->codec); + PRINT("zero video stream %p\n", context->video_stream); + context->video_stream = 0; } /* Close the output file */ - if (outfile) { - for (i = 0; i < outfile->nb_streams; i++) { - if (&outfile->streams[i]) { - av_freep(&outfile->streams[i]); + if (context->outfile) { + for (i = 0; i < context->outfile->nb_streams; i++) { + if (&context->outfile->streams[i]) { + av_freep(&context->outfile->streams[i]); } } } /* free the temp buffer */ - if (current_frame) { - delete_picture(current_frame); - current_frame = 0; + if (context->current_frame) { + delete_picture(context->current_frame); + context->current_frame = 0; } - if (outfile && outfile->oformat) { - if (!(outfile->oformat->flags & AVFMT_NOFILE)) { - avio_close(outfile->pb); + if (context->outfile && context->outfile->oformat) { + if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) { + avio_close(context->outfile->pb); } } - if (outfile) { - av_free(outfile); - outfile = 0; + if (context->outfile) { + av_free(context->outfile); + context->outfile = 0; } - if (audio_input_buffer) { - av_free(audio_input_buffer); - audio_input_buffer = 0; + if (context->audio_input_buffer) { + av_free(context->audio_input_buffer); + context->audio_input_buffer = 0; } #ifndef FFMPEG_HAVE_ENCODE_AUDIO2 - if (audio_output_buffer) { - av_free(audio_output_buffer); - audio_output_buffer = 0; + if (context->audio_output_buffer) { + av_free(context->audio_output_buffer); + context->audio_output_buffer = 0; } #endif - if (audio_deinterleave_buffer) { - av_free(audio_deinterleave_buffer); - audio_deinterleave_buffer = 0; + if (context->audio_deinterleave_buffer) { + av_free(context->audio_deinterleave_buffer); + context->audio_deinterleave_buffer = 0; } - if (img_convert_ctx) { - sws_freeContext(img_convert_ctx); - img_convert_ctx = 0; + if (context->img_convert_ctx) { + sws_freeContext(context->img_convert_ctx); + context->img_convert_ctx = 0; } } -void BKE_ffmpeg_end(void) +void BKE_ffmpeg_end(void *context_v) { - end_ffmpeg_impl(false); + FFMpegContext *context = context_v; + end_ffmpeg_impl(context, false); } /* properties */ @@ -1646,4 +1675,31 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd) return false; } -#endif +void *BKE_ffmpeg_context_create(void) +{ + FFMpegContext *context; + + /* new ffmpeg data struct */ + context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context"); + + context->ffmpeg_codec = AV_CODEC_ID_MPEG4; + context->ffmpeg_audio_codec = AV_CODEC_ID_NONE; + context->ffmpeg_video_bitrate = 1150; + context->ffmpeg_audio_bitrate = 128; + context->ffmpeg_gop_size = 12; + context->ffmpeg_autosplit = 0; + context->ffmpeg_autosplit_count = 0; + context->ffmpeg_preview = false; + + return context; +} + +void BKE_ffmpeg_context_free(void *context_v) +{ + FFMpegContext *context = context_v; + if (context) { + MEM_freeN(context); + } +} + +#endif /* WITH_FFMPEG */ diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c index ae6b19fb019..ba58038bbd8 100644 --- a/source/blender/blenkernel/intern/writeframeserver.c +++ b/source/blender/blenkernel/intern/writeframeserver.c @@ -66,12 +66,15 @@ #include "BKE_report.h" #include "DNA_scene_types.h" +#include "MEM_guardedalloc.h" -static int sock; -static int connsock; -static int write_ppm; -static int render_width; -static int render_height; +typedef struct FrameserverContext { + int sock; + int connsock; + int write_ppm; + int render_width; + int render_height; +} FrameserverContext; #if defined(_WIN32) @@ -110,10 +113,11 @@ static int closesocket(int fd) } #endif -int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports) +int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix)) { struct sockaddr_in addr; int arg = 1; + FrameserverContext *context = context_v; (void)scene; /* unused */ @@ -122,33 +126,33 @@ int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx return 0; } - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { shutdown_socket_system(); BKE_report(reports, RPT_ERROR, "Cannot open socket"); return 0; } - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg)); + setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg)); addr.sin_family = AF_INET; addr.sin_port = htons(U.frameserverport); addr.sin_addr.s_addr = INADDR_ANY; - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { shutdown_socket_system(); BKE_report(reports, RPT_ERROR, "Cannot bind to socket"); return 0; } - if (listen(sock, SOMAXCONN) < 0) { + if (listen(context->sock, SOMAXCONN) < 0) { shutdown_socket_system(); BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog"); return 0; } - connsock = -1; + context->connsock = -1; - render_width = rectx; - render_height = recty; + context->render_width = rectx; + context->render_height = recty; return 1; } @@ -177,7 +181,7 @@ static char good_bye[] = "<body><pre>\n" "Render stopped. Goodbye</pre></body></html>"; -static int safe_write(char *s, int tosend) +static int safe_write(const int connsock, char *s, int tosend) { int total = tosend; do { @@ -192,12 +196,12 @@ static int safe_write(char *s, int tosend) return total; } -static int safe_puts(char *s) +static int safe_puts(const int connsock, char *s) { - return safe_write(s, strlen(s)); + return safe_write(connsock, s, strlen(s)); } -static int handle_request(RenderData *rd, char *req) +static int handle_request(FrameserverContext *context, RenderData *rd, char *req) { char *p; char *path; @@ -214,16 +218,16 @@ static int handle_request(RenderData *rd, char *req) *p = 0; - if (STREQ(path, "/index.html") || STREQ(path, "/")) { - safe_puts(index_page); + if (STREQ(path, "/index.html") || strcmp(path, "/")) { + safe_puts(context->connsock, index_page); return -1; } - write_ppm = 0; + context->write_ppm = 0; pathlen = strlen(path); if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) { - write_ppm = 1; + context->write_ppm = 1; return atoi(path + 12); } if (STREQ(path, "/info.txt")) { @@ -241,24 +245,24 @@ static int handle_request(RenderData *rd, char *req) "ratescale %d\n", rd->sfra, rd->efra, - render_width, - render_height, + context->render_width, + context->render_height, rd->frs_sec, 1 ); - safe_puts(buf); + safe_puts(context->connsock, buf); return -1; } if (STREQ(path, "/close.txt")) { - safe_puts(good_bye); + safe_puts(context->connsock, good_bye); G.is_break = true; /* Abort render */ return -1; } return -1; } -int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports)) +int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports)) { fd_set readfds; struct timeval tv; @@ -271,18 +275,20 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports)) #endif char buf[4096]; - if (connsock != -1) { - closesocket(connsock); - connsock = -1; + FrameserverContext *context = context_v; + + if (context->connsock != -1) { + closesocket(context->connsock); + context->connsock = -1; } tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&readfds); - FD_SET(sock, &readfds); + FD_SET(context->sock, &readfds); - rval = select(sock + 1, &readfds, NULL, NULL, &tv); + rval = select(context->sock + 1, &readfds, NULL, NULL, &tv); if (rval < 0) { return -1; } @@ -293,19 +299,19 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports)) socklen = sizeof(addr); - if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) { + if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) { return -1; } FD_ZERO(&readfds); - FD_SET(connsock, &readfds); + FD_SET(context->connsock, &readfds); for (;;) { /* give 10 seconds for telnet testing... */ tv.tv_sec = 10; tv.tv_usec = 0; - rval = select(connsock + 1, &readfds, NULL, NULL, &tv); + rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv); if (rval > 0) { break; } @@ -319,7 +325,7 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports)) } } - len = recv(connsock, buf, sizeof(buf) - 1, 0); + len = recv(context->connsock, buf, sizeof(buf) - 1, 0); if (len < 0) { return -1; @@ -327,13 +333,13 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports)) buf[len] = 0; - return handle_request(rd, buf); + return handle_request(context, rd, buf); } -static void serve_ppm(int *pixels, int rectx, int recty) +static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty) { unsigned char *rendered_frame; - unsigned char *row = (unsigned char *) malloc(render_width * 3); + unsigned char *row = (unsigned char *) malloc(context->render_width * 3); int y; char header[1024]; @@ -348,7 +354,7 @@ static void serve_ppm(int *pixels, int rectx, int recty) "255\n", rectx, recty); - safe_puts(header); + safe_puts(context->connsock, header); rendered_frame = (unsigned char *)pixels; @@ -364,36 +370,54 @@ static void serve_ppm(int *pixels, int rectx, int recty) target += 3; src += 4; } - safe_write((char *)row, 3 * rectx); + safe_write(context->connsock, (char *)row, 3 * rectx); } free(row); - closesocket(connsock); - connsock = -1; + closesocket(context->connsock); + context->connsock = -1; } -int BKE_frameserver_append(RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels, - int rectx, int recty, ReportList *UNUSED(reports)) +int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels, + int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports)) { + FrameserverContext *context = context_v; + fprintf(stderr, "Serving frame: %d\n", frame); - if (write_ppm) { - serve_ppm(pixels, rectx, recty); + if (context->write_ppm) { + serve_ppm(context, pixels, rectx, recty); } - if (connsock != -1) { - closesocket(connsock); - connsock = -1; + if (context->connsock != -1) { + closesocket(context->connsock); + context->connsock = -1; } return 1; } -void BKE_frameserver_end(void) +void BKE_frameserver_end(void *context_v) { - if (connsock != -1) { - closesocket(connsock); - connsock = -1; + FrameserverContext *context = context_v; + + if (context->connsock != -1) { + closesocket(context->connsock); + context->connsock = -1; } - closesocket(sock); + closesocket(context->sock); shutdown_socket_system(); } +void *BKE_frameserver_context_create(void) +{ + FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context"); + return context; +} + +void BKE_frameserver_context_free(void *context_v) +{ + FrameserverContext *context = context_v; + if (context) { + MEM_freeN(context); + } +} + #endif /* WITH_FRAMESERVER */ |