diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2012-12-19 05:49:58 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2012-12-19 05:49:58 +0400 |
commit | d433cd65f7127d60e17d05a824290423ad226eae (patch) | |
tree | f0a9c821f6046e97b74c6969d41269b558fd52ab /source/blender/blenkernel | |
parent | 10f0f66560234a04aed3295c74fff20adacbc57f (diff) | |
parent | f10dea7e3b9b431edae9c787fa1a9e09cd567ed7 (diff) |
Merged changes in the trunk up to revision 53146.
Conflicts resolved:
release/datafiles/startup.blend
source/blender/blenkernel/CMakeLists.txt
source/blender/blenlib/intern/bpath.c
source/blender/blenloader/intern/readfile.c
Diffstat (limited to 'source/blender/blenkernel')
64 files changed, 4079 insertions, 366 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 617c4cd2bc8..ed90c63d949 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -105,6 +105,11 @@ struct PBVH; * Also, the mface origindex layer indexes mpolys, not mfaces. */ +typedef struct DMCoNo { + float co[3]; + float no[3]; +} DMCoNo; + typedef struct DMGridAdjacency { int index[4]; int rotation[4]; @@ -603,7 +608,7 @@ void vDM_ColorBand_store(struct ColorBand *coba); /** Simple function to get me->totvert amount of vertices/normals, * correctly deformed and subsurfered. Needed especially when vertexgroups are involved. * In use now by vertex/weight paint and particles */ -float *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob); +DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob); /* */ DerivedMesh *mesh_get_derived_final(struct Scene *scene, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index b0f372e0bac..765a00b8d4b 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -97,28 +97,28 @@ void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPose void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); /* get_objectspace_bone_matrix has to be removed still */ -void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[][4], int root, int posed); -void vec_roll_to_mat3(const float vec[3], const float roll, float mat[][3]); -void mat3_to_vec_roll(float mat[][3], float r_vec[3], float *r_roll); +void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int root, int posed); +void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]); +void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll); /* Common Conversions Between Co-ordinate Spaces */ -void BKE_armature_mat_world_to_pose(struct Object *ob, float inmat[][4], float outmat[][4]); +void BKE_armature_mat_world_to_pose(struct Object *ob, float inmat[4][4], float outmat[4][4]); void BKE_armature_loc_world_to_pose(struct Object *ob, const float inloc[3], float outloc[3]); -void BKE_armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]); +void BKE_armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]); void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan, const float inloc[3], float outloc[3]); -void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]); -void BKE_armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]); +void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]); +void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4]); -void BKE_armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]); +void BKE_armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]); -void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, float mat[][3], short use_compat); -void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, float mat[][4], short use_comat); +void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, float mat[3][3], short use_compat); +void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, float mat[4][4], short use_comat); void BKE_pchan_to_mat4(struct bPoseChannel *pchan, float chan_mat[4][4]); void BKE_pchan_calc_mat(struct bPoseChannel *pchan); /* Get the "pchan to pose" transform matrix. These matrices apply the effects of * HINGE/NO_SCALE/NO_LOCAL_LOCATION options over the pchan loc/rot/scale transformations. */ -void BKE_pchan_to_pose_mat(struct bPoseChannel *pchan, float rotscale_mat[][4], float loc_mat[][4]); +void BKE_pchan_to_pose_mat(struct bPoseChannel *pchan, float rotscale_mat[4][4], float loc_mat[4][4]); /* Rotation Mode Conversions - Used for PoseChannels + Objects... */ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index b624d0f9c3a..570086e9b69 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 265 -#define BLENDER_SUBVERSION 0 +#define BLENDER_SUBVERSION 3 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 262 @@ -52,7 +52,7 @@ extern "C" { /* can be left blank, otherwise a,b,c... etc with no quotes */ #define BLENDER_VERSION_CHAR /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE release +#define BLENDER_VERSION_CYCLE alpha extern char versionstr[]; /* from blender.c */ @@ -62,6 +62,7 @@ struct bContext; struct ReportList; struct Scene; struct Main; +struct ID; int BKE_read_file(struct bContext *C, const char *filepath, struct ReportList *reports); @@ -72,12 +73,17 @@ int BKE_read_file(struct bContext *C, const char *filepath, struct ReportList *r int BKE_read_file_from_memory(struct bContext *C, char *filebuf, int filelength, struct ReportList *reports); int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, struct ReportList *reports); +int BKE_read_file_userdef(const char *filepath, struct ReportList *reports); +int BKE_write_file_userdef(const char *filepath, struct ReportList *reports); + void free_blender(void); void initglobals(void); /* load new userdef from file, exit blender */ void BKE_userdef_free(void); - +/* handle changes in userdef */ +void BKE_userdef_state(void); + /* set this callback when a UI is running */ void set_blender_test_break_cb(void (*func)(void) ); int blender_test_break(void); @@ -93,9 +99,15 @@ extern void BKE_reset_undo(void); extern char *BKE_undo_menu_string(void); extern void BKE_undo_number(struct bContext *C, int nr); extern const char *BKE_undo_get_name(int nr, int *active); -extern void BKE_undo_save_quit(void); +extern int BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **scene); + /* copybuffer */ +void BKE_copybuffer_begin(void); +void BKE_copybuffer_tag_ID(struct ID *id); +int BKE_copybuffer_save(char *filename, struct ReportList *reports); + int BKE_copybuffer_paste(struct bContext *C, char *libname, struct ReportList *reports); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h new file mode 100644 index 00000000000..16a8b1be85b --- /dev/null +++ b/source/blender/blenkernel/BKE_bpath.h @@ -0,0 +1,72 @@ +/* + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_bpath.h + * \ingroup bke + * \attention Based on ghash, difference is ghash is not a fixed size, + * so for BPath we don't need to malloc + */ + +#ifndef __BKE_BPATH_H__ +#define __BKE_BPATH_H__ + +struct ID; +struct ListBase; +struct Main; +struct ReportList; + +/* Function that does something with an ID's file path. Should return 1 if the + * path has changed, and in that case, should write the result to pathOut. */ +typedef int (*BPathVisitor)(void *userdata, char *path_dst, const char *path_src); +/* Executes 'visit' for each path associated with 'id'. */ +void BKE_bpath_traverse_id(struct Main *bmain, struct ID *id, BPathVisitor visit_cb, const int flag, void *userdata); +void BKE_bpath_traverse_id_list(struct Main *bmain, struct ListBase *lb, BPathVisitor visit_cb, const int flag, void *userdata); +void BKE_bpath_traverse_main(struct Main *bmain, BPathVisitor visit_cb, const int flag, void *userdata); +int BKE_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src); + +/* Functions for temp backup/restore of paths, path count must NOT change */ +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 */ + +/* high level funcs */ + +/* creates a text file with missing files if there are any */ +void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports); +void BKE_bpath_missing_files_find(struct Main *bmain, const char *searchpath, struct ReportList *reports); +void BKE_bpath_relative_convert(struct Main *bmain, const char *basedir, struct ReportList *reports); +void BKE_bpath_absolute_convert(struct Main *bmain, const char *basedir, struct ReportList *reports); + +#endif /* __BKE_BPATH_H__ */ diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 686a60ab2c9..79e75127763 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -147,9 +147,9 @@ short proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pcha struct bConstraintOb *constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); void constraints_clear_evalob(struct bConstraintOb *cob); -void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to); +void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to); -void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime); +void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); void get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h index c3fa6621c98..433c10b82f1 100644 --- a/source/blender/blenkernel/BKE_fluidsim.h +++ b/source/blender/blenkernel/BKE_fluidsim.h @@ -47,7 +47,7 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob, int useGlobalCoords, int modifierIndex); /* bounding box & memory estimate */ -void fluid_get_bb(struct MVert *mvert, int totvert, float obmat[][4], +void fluid_get_bb(struct MVert *mvert, int totvert, float obmat[4][4], float start[3], float size[3]); void fluid_estimate_memory(struct Object *ob, struct FluidsimSettings *fss, char *value); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index f6276a69d57..38a88607119 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -149,7 +149,7 @@ enum { /* #define G_FILE_SHOW_PROFILE (1 << 6) */ /* deprecated */ #define G_FILE_LOCK (1 << 7) #define G_FILE_SIGN (1 << 8) -/* #define G_FILE_PUBLISH (1 << 9) */ /* deprecated */ +#define G_FILE_USERPREFS (1 << 9) #define G_FILE_NO_UI (1 << 10) /* #define G_FILE_GAME_TO_IPO (1 << 11) */ /* deprecated */ #define G_FILE_GAME_MAT (1 << 12) /* deprecated */ diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 34baa48dbe2..a0bebd752b5 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -59,7 +59,7 @@ void curve_deform_verts(struct Scene *scene, struct Object *cuOb, struct Object struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, short defaxis); void curve_deform_vector(struct Scene *scene, struct Object *cuOb, struct Object *target, - float orco[3], float vec[3], float mat[][3], int no_rot_axis); + float orco[3], float vec[3], float mat[3][3], int no_rot_axis); void lattice_deform_verts(struct Object *laOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index bc081b7f308..b9bb67fa509 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -62,6 +62,7 @@ void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const shor void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); void BKE_library_filepath_set(struct Library *lib, const char *filepath); +void id_us_ensure_real(struct ID *id); void id_us_plus(struct ID *id); void id_us_min(struct ID *id); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 06931662d3f..cb8f1a7d682 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -51,9 +51,10 @@ struct Library; typedef struct Main { struct Main *next, *prev; char name[1024]; /* 1024 = FILE_MAX */ - short versionfile, subversionfile; + short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION */ short minversionfile, minsubversionfile; - int revision; /* svn revision of binary that saved file */ + int revision; /* svn revision of binary that saved file */ + short recovered; /* indicate the main->name (file) is the recovered one */ struct Library *curlib; ListBase scene; @@ -92,6 +93,8 @@ typedef struct Main { char id_tag_update[256]; } Main; +#define MAIN_VERSION_ATLEAST(main, ver, subver) \ + ((main)->versionfile >= (ver) || (main->versionfile == (ver) && (main)->subversionfile >= (subver))) #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index e53d0efffbd..3fc1b7d6136 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -229,8 +229,6 @@ typedef struct UvElement { /* Next UvElement corresponding to same vertex */ struct UvElement *next; /* Face the element belongs to */ - struct BMFace *face; - /* Index in the editFace of the uv */ struct BMLoop *l; /* index in loop. */ unsigned short tfindex; diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 2fa78b30835..cc260b8f60c 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -358,8 +358,6 @@ int modifiers_isCorrectableDeformed(struct Object *ob); void modifier_freeTemporaryData(struct ModifierData *md); int modifiers_isPreview(struct Object *ob); -int modifiers_indexInObject(struct Object *ob, struct ModifierData *md); - typedef struct CDMaskLink { struct CDMaskLink *next; CustomDataMask mask; diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index ec0703248fd..bfae1bd2390 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -76,7 +76,8 @@ void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); void BKE_object_unlink(struct Object *ob); int BKE_object_exists_check(struct Object *obtest); - +int BKE_object_is_in_editmode(struct Object *ob); + struct Object *BKE_object_add_only_object(int type, const char *name); struct Object *BKE_object_add(struct Scene *scene, int type); void *BKE_object_obdata_add_from_type(int type); @@ -87,12 +88,12 @@ void BKE_object_make_local(struct Object *ob); int BKE_object_is_libdata(struct Object *ob); int BKE_object_obdata_is_libdata(struct Object *ob); -void BKE_object_scale_to_mat3(struct Object *ob, float mat[][3]); -void BKE_object_rot_to_mat3(struct Object *ob, float mat[][3]); -void BKE_object_mat3_to_rot(struct Object *ob, float mat[][3], short use_compat); -void BKE_object_to_mat3(struct Object *ob, float mat[][3]); -void BKE_object_to_mat4(struct Object *ob, float mat[][4]); -void BKE_object_apply_mat4(struct Object *ob, float mat[][4], const short use_compat, const short use_parent); +void BKE_object_scale_to_mat3(struct Object *ob, float mat[3][3]); +void BKE_object_rot_to_mat3(struct Object *ob, float mat[3][3], short use_drot); +void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], short use_compat); +void BKE_object_to_mat3(struct Object *ob, float mat[3][3]); +void BKE_object_to_mat4(struct Object *ob, float mat[4][4]); +void BKE_object_apply_mat4(struct Object *ob, float mat[4][4], const short use_compat, const short use_parent); int BKE_object_pose_context_check(struct Object *ob); struct Object *BKE_object_pose_armature_get(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index ec03f53dbdb..f15ad296e4a 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -20,7 +20,9 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Adaptive time step + * Classical SPH + * Copyright 2011-2012 AutoCRC * * ***** END GPL LICENSE BLOCK ***** */ @@ -58,6 +60,7 @@ struct RNG; struct SurfaceModifierData; struct BVHTreeRay; struct BVHTreeRayHit; +struct EdgeHash; #define PARTICLE_P ParticleData * pa; int p #define LOOP_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) @@ -85,6 +88,24 @@ typedef struct ParticleSimulationData { float courant_num; } ParticleSimulationData; +typedef struct SPHData { + ParticleSystem *psys[10]; + ParticleData *pa; + float mass; + struct EdgeHash *eh; + float *gravity; + float hfac; + /* Average distance to neighbours (other particles in the support domain), + for calculating the Courant number (adaptive time step). */ + int pass; + float element_size; + float flow[3]; + + /* Integrator callbacks. This allows different SPH implementations. */ + void (*force_cb) (void *sphdata_v, ParticleKey *state, float *force, float *impulse); + void (*density_cb) (void *rangedata_v, int index, float squared_dist); +} SPHData; + typedef struct ParticleTexture { float ivel; /* used in reset */ float time, life, exist, size; /* used in init */ @@ -247,7 +268,7 @@ void BKE_particlesettings_free(struct ParticleSettings *part); void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit); void psys_free(struct Object *ob, struct ParticleSystem *psys); -void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy, int timeoffset); +void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset); void psys_render_restore(struct Object *ob, struct ParticleSystem *psys); int psys_render_simplify_distribution(struct ParticleThreadContext *ctx, int tot); int psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params); @@ -283,12 +304,16 @@ float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, struct ParticleKey *state, int vel); int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, int always); +void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata); +void psys_sph_finalise(struct SPHData *sphdata); +void psys_sph_density(struct BVHTree *tree, struct SPHData* data, float co[3], float vars[2]); + /* for anim.c */ void psys_get_dupli_texture(struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, float uv[2], float orco[3]); void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ChildParticle *cpa, - struct ParticleCacheKey *cache, float mat[][4], float *scale); + struct ParticleCacheKey *cache, float mat[4][4], float *scale); ParticleThread *psys_threads_create(struct ParticleSimulationData *sim); void psys_threads_free(ParticleThread *threads); @@ -322,9 +347,9 @@ void psys_free_children(struct ParticleSystem *psys); void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, int velocity); void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float vec[3]); -void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); -void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); -void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); +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]); float psys_get_dietime_from_cache(struct PointCache *cache, int index); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h new file mode 100644 index 00000000000..302de593963 --- /dev/null +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -0,0 +1,270 @@ +/* + * ***** 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 __BLI_PBVH_H__ +#define __BLI_PBVH_H__ + +/** \file BKE_pbvh.h + * \ingroup bke + * \brief A BVH for high poly meshes. + */ + +#include "BLI_bitmap.h" + +struct CCGElem; +struct CCGKey; +struct CustomData; +struct DMFlagMat; +struct DMGridAdjacency; +struct ListBase; +struct MFace; +struct MVert; +struct PBVH; +struct PBVHNode; + +typedef struct PBVH PBVH; +typedef struct PBVHNode PBVHNode; + +typedef struct { + float (*co)[3]; +} PBVHProxyNode; + +/* Callbacks */ + +/* returns 1 if the search should continue from this node, 0 otherwise */ +typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data); + +typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data); +typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin); + +/* Building */ + +PBVH *BLI_pbvh_new(void); +void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, + int totface, int totvert, struct CustomData *vdata); +void BLI_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, + struct DMGridAdjacency *gridadj, int totgrid, + struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, + unsigned int **grid_hidden); +void BLI_pbvh_free(PBVH *bvh); + +/* Hierarchical Search in the BVH, two methods: + * - for each hit calling a callback + * - gather nodes in an array (easy to multithread) */ + +void BLI_pbvh_search_callback(PBVH *bvh, + BLI_pbvh_SearchCallback scb, void *search_data, + BLI_pbvh_HitCallback hcb, void *hit_data); + +void BLI_pbvh_search_gather(PBVH *bvh, + BLI_pbvh_SearchCallback scb, void *search_data, + PBVHNode ***array, int *tot); + +/* Raycast + * the hit callback is called for all leaf nodes intersecting the ray; + * it's up to the callback to find the primitive within the leaves that is + * hit first */ + +void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, + const float ray_start[3], const float ray_normal[3], + int original); + +int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], + const float ray_start[3], const float ray_normal[3], + float *dist); + +/* Drawing */ + +void BLI_pbvh_node_draw(PBVHNode *node, void *data); +void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], + int (*setMaterial)(int, void *attribs)); + +/* PBVH Access */ +typedef enum { + PBVH_FACES, + PBVH_GRIDS, +} PBVHType; + +PBVHType BLI_pbvh_type(const PBVH *bvh); + +/* multires hidden data, only valid for type == PBVH_GRIDS */ +unsigned int **BLI_pbvh_grid_hidden(const PBVH *bvh); + +/* multires level, only valid for type == PBVH_GRIDS */ +void BLI_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); + +/* Node Access */ + +typedef enum { + PBVH_Leaf = 1, + + PBVH_UpdateNormals = 2, + PBVH_UpdateBB = 4, + PBVH_UpdateOriginalBB = 8, + PBVH_UpdateDrawBuffers = 16, + PBVH_UpdateRedraw = 32, + + PBVH_RebuildDrawBuffers = 64, + PBVH_FullyHidden = 128 +} PBVHNodeFlags; + +void BLI_pbvh_node_mark_update(PBVHNode *node); +void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node); +void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); + +void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, + int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, + struct CCGElem ***grid_elems, struct DMGridAdjacency **gridadj); +void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, + int *uniquevert, int *totvert); +void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, + int **vert_indices, struct MVert **verts); + +void BLI_pbvh_node_get_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); +void BLI_pbvh_node_get_original_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); + +float BLI_pbvh_node_get_tmin(PBVHNode *node); + +/* test if AABB is at least partially inside the planes' volume */ +int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); +/* test if AABB is at least partially outside the planes' volume */ +int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); + +/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */ + +void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); +void BLI_pbvh_redraw_BB(PBVH * bvh, float bb_min[3], float bb_max[3]); +void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface); +void BLI_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, + struct DMGridAdjacency *gridadj, void **gridfaces, + struct DMFlagMat *flagmats, unsigned int **grid_hidden); + +/* vertex deformer */ +float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3]; +void BLI_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); +int BLI_pbvh_isDeformed(struct PBVH *pbvh); + + +/* Vertex Iterator */ + +/* this iterator has quite a lot of code, but it's designed to: + * - allow the compiler to eliminate dead code and variables + * - spend most of the time in the relatively simple inner loop */ + +/* note: PBVH_ITER_ALL does not skip hidden vertices, + * PBVH_ITER_UNIQUE does */ +#define PBVH_ITER_ALL 0 +#define PBVH_ITER_UNIQUE 1 + +typedef struct PBVHVertexIter { + /* iteration */ + int g; + int width; + int height; + int gx; + int gy; + int i; + + /* grid */ + struct CCGElem **grids; + struct CCGElem *grid; + struct CCGKey *key; + BLI_bitmap *grid_hidden, gh; + int *grid_indices; + int totgrid; + int gridsize; + + /* mesh */ + struct MVert *mverts; + int totvert; + int *vert_indices; + float *vmask; + + /* result: these are all computed in the macro, but we assume + * that compiler optimization's will skip the ones we don't use */ + struct MVert *mvert; + float *co; + short *no; + float *fno; + float *mask; +} PBVHVertexIter; + +#ifdef _MSC_VER +#pragma warning (disable:4127) // conditional expression is constant +#endif + +void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, + PBVHVertexIter *vi, int mode); + +#define BLI_pbvh_vertex_iter_begin(bvh, node, vi, mode) \ + pbvh_vertex_iter_init(bvh, node, &vi, mode); \ + \ + for (vi.i = 0, vi.g = 0; vi.g < vi.totgrid; vi.g++) { \ + if (vi.grids) { \ + vi.width = vi.gridsize; \ + vi.height = vi.gridsize; \ + vi.grid = vi.grids[vi.grid_indices[vi.g]]; \ + if (mode == PBVH_ITER_UNIQUE) \ + vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \ + } \ + else { \ + vi.width = vi.totvert; \ + vi.height = 1; \ + } \ + \ + for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \ + for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \ + if (vi.grid) { \ + vi.co = CCG_elem_co(vi.key, vi.grid); \ + vi.fno = CCG_elem_no(vi.key, vi.grid); \ + vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \ + vi.grid = CCG_elem_next(vi.key, vi.grid); \ + if (vi.gh) { \ + if (BLI_BITMAP_GET(vi.gh, vi.gy * vi.gridsize + vi.gx)) \ + continue; \ + } \ + } \ + else { \ + vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \ + if (mode == PBVH_ITER_UNIQUE && vi.mvert->flag & ME_HIDE) \ + continue; \ + vi.co = vi.mvert->co; \ + vi.no = vi.mvert->no; \ + if (vi.vmask) \ + vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \ + } \ + +#define BLI_pbvh_vertex_iter_end \ + } \ + } \ + } + +void BLI_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count); +void BLI_pbvh_node_free_proxies(PBVHNode *node); +PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node); +void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode); + +//void BLI_pbvh_node_BB_reset(PBVHNode *node); +//void BLI_pbvh_node_BB_expand(PBVHNode *node, float co[3]); + +void pbvh_show_diffuse_color_set(PBVH *bvh, int show_diffuse_color); + +#endif /* __BLI_PBVH_H__ */ + diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h index e0eb8c04b60..99e60757f15 100644 --- a/source/blender/blenkernel/BKE_property.h +++ b/source/blender/blenkernel/BKE_property.h @@ -47,6 +47,7 @@ void BKE_bproperty_object_set(struct Object *ob, struct bProperty * // int BKE_bproperty_cmp(struct bProperty *prop, const char *str); void BKE_bproperty_set(struct bProperty *prop, const char *str); void BKE_bproperty_add(struct bProperty *prop, const char *str); -void BKE_bproperty_set_valstr(struct bProperty *prop, char *str); +/* should really be called '_get_valstr()' or '_as_string()' */ +void BKE_bproperty_set_valstr(struct bProperty *prop, char str[MAX_PROPSTRING]); #endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 9927c7a42ed..6447b2a8dee 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -47,7 +47,7 @@ struct RenderData; struct SceneRenderLayer; struct Scene; struct Text; -struct Text; +struct Main; #define SCE_COPY_NEW 0 #define SCE_COPY_EMPTY 1 @@ -67,7 +67,7 @@ void free_avicodecdata(struct AviCodecData *acd); void free_qtcodecdata(struct QuicktimeCodecData *acd); void BKE_scene_free(struct Scene *sce); -struct Scene *BKE_scene_add(const char *name); +struct Scene *BKE_scene_add(struct Main *bmain, const char *name); /* base functions */ struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 88294cb30b6..e3d9c513c5c 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -363,7 +363,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, int, int, char[256]); +typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, int, int, int, char[256]); extern SequencerDrawView sequencer_view3d_cb; /* copy/paste */ diff --git a/source/blender/blenkernel/BKE_tessmesh.h b/source/blender/blenkernel/BKE_tessmesh.h index dea5e726671..9462822e25f 100644 --- a/source/blender/blenkernel/BKE_tessmesh.h +++ b/source/blender/blenkernel/BKE_tessmesh.h @@ -80,12 +80,11 @@ typedef struct BMEditMesh { /*temp variables for x-mirror editing*/ int mirror_cdlayer; /* -1 is invalid */ - int mirr_free_arrays; } BMEditMesh; -void BMEdit_RecalcTessellation(BMEditMesh *tm); +void BMEdit_RecalcTessellation(BMEditMesh *em); BMEditMesh *BMEdit_Create(BMesh *bm, int do_tessellate); -BMEditMesh *BMEdit_Copy(BMEditMesh *tm); +BMEditMesh *BMEdit_Copy(BMEditMesh *em); BMEditMesh *BMEdit_FromObject(struct Object *ob); void BMEdit_Free(BMEditMesh *em); void BMEdit_UpdateLinkedCustomData(BMEditMesh *em); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index e3b16fd92e2..70a3f927b23 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -66,6 +66,7 @@ set(SRC intern/bmfont.c intern/boids.c intern/booleanops_mesh.c + intern/bpath.c intern/brush.c intern/bullet.c intern/bvhutils.c @@ -103,9 +104,9 @@ set(SRC intern/lattice.c intern/library.c intern/linestyle.c + intern/mask.c intern/mask_evaluate.c intern/mask_rasterize.c - intern/mask.c intern/material.c intern/mball.c intern/mesh.c @@ -123,6 +124,7 @@ set(SRC intern/paint.c intern/particle.c intern/particle_system.c + intern/pbvh.c intern/pointcache.c intern/property.c intern/report.c @@ -161,6 +163,7 @@ set(SRC BKE_bmfont_types.h BKE_boids.h BKE_booleanops_mesh.h + BKE_bpath.h BKE_brush.h BKE_bullet.h BKE_bvhutils.h @@ -212,6 +215,7 @@ set(SRC BKE_packedFile.h BKE_paint.h BKE_particle.h + BKE_pbvh.h BKE_pointcache.h BKE_property.h BKE_report.h @@ -237,6 +241,7 @@ set(SRC BKE_world.h BKE_writeavi.h BKE_writeframeserver.h + depsgraph_private.h nla_private.h intern/CCGSubSurf.h diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index dc1c9b5a1a2..ccb21b209ea 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -1,4 +1,30 @@ -#!/usr/bin/python +#!/usr/bin/env python +# +# ***** 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) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Nathan Letwory. +# +# ***** END GPL LICENSE BLOCK ***** + Import ('env') import os diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index d09bea0f662..010839764b2 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -47,10 +47,10 @@ #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_array.h" -#include "BLI_pbvh.h" #include "BLI_utildefines.h" #include "BLI_linklist.h" +#include "BKE_pbvh.h" #include "BKE_cdderivedmesh.h" #include "BKE_displist.h" #include "BKE_key.h" @@ -1421,7 +1421,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos } /* grab modifiers until index i */ - if ((index >= 0) && (modifiers_indexInObject(ob, md) >= index)) + if ((index >= 0) && (BLI_findindex(&ob->modifiers, md) >= index)) break; } @@ -1666,7 +1666,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform); /* grab modifiers until index i */ - if ((index >= 0) && (modifiers_indexInObject(ob, md) >= index)) + if ((index >= 0) && (BLI_findindex(&ob->modifiers, md) >= index)) break; if (sculpt_mode && md->type == eModifierType_Multires) @@ -2334,29 +2334,29 @@ static void make_vertexcosnos__mapFunc(void *userData, int index, const float co /* it stores the normals as floats, but they can still be scaled as shorts (32767 = unit) */ /* in use now by vertex/weight paint and particle generating */ -float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) +DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) { Mesh *me = ob->data; DerivedMesh *dm; - float *vertexcosnos; + DMCoNo *vertexcosnos; /* lets prevent crashing... */ if (ob->type != OB_MESH || me->totvert == 0) return NULL; dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); - vertexcosnos = MEM_callocN(6 * sizeof(float) * me->totvert, "vertexcosnos map"); + vertexcosnos = MEM_callocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); if (dm->foreachMappedVert) { dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos); } else { - float *fp = vertexcosnos; + DMCoNo *v_co_no = vertexcosnos; int a; - for (a = 0; a < me->totvert; a++, fp += 6) { - dm->getVertCo(dm, a, fp); - dm->getVertNo(dm, a, fp + 3); + for (a = 0; a < me->totvert; a++, v_co_no++) { + dm->getVertCo(dm, a, v_co_no->co); + dm->getVertNo(dm, a, v_co_no->no); } } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index dd27cc70ba3..83d1538ecbe 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -43,7 +43,6 @@ #include "DNA_object_types.h" #include "BLI_blenlib.h" -#include "BLI_bpath.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 9a2462e9724..4058809c275 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -76,7 +76,7 @@ /* --------------------- */ /* forward declarations */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, int index, short flag); /* ******************************************************************** */ @@ -706,7 +706,7 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua #define DUPLILIST_FOR_RENDER 2 #define DUPLILIST_ANIMATED 4 -static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, +static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[4][4], int lay, int persistent_id[MAX_DUPLI_RECUR], int level, int index, int type, short flag) { DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject"); @@ -930,7 +930,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], } } -static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int persistent_id[MAX_DUPLI_RECUR], +static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { Object *ob, *ob_iter; @@ -1054,7 +1054,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl dm->release(dm); } -static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int persistent_id[MAX_DUPLI_RECUR], +static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { Object *ob, *ob_iter; @@ -1240,7 +1240,8 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa dm->release(dm); } -static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int persistent_id[MAX_DUPLI_RECUR], ParticleSystem *psys, +static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[4][4], + int persistent_id[MAX_DUPLI_RECUR], ParticleSystem *psys, int level, short flag) { GroupObject *go; @@ -1479,7 +1480,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p /* blender internal needs this to be set to dupligroup to render * groups correctly, but we don't want this hack for cycles */ - if(dupli_type_hack && GS(id->name) == ID_GR) + if (dupli_type_hack && GS(id->name) == ID_GR) dupli_type = OB_DUPLIGROUP; /* to give ipos in object correct offset */ @@ -1635,7 +1636,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int persiste /* ------------- */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[4][4], int persistent_id[MAX_DUPLI_RECUR], int level, int index, short flag) { if ((ob->transflag & OB_DUPLI) == 0) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 1970df54339..9155d67dc36 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -37,7 +37,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_bpath.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -640,7 +639,7 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info } } -static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], DualQuat *dq, float defmat[][3]) +static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], DualQuat *dq, float defmat[3][3]) { Mat4 *b_bone = pdef_info->b_bone_mats; float (*mat)[4] = b_bone[0].mat; @@ -722,7 +721,7 @@ float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3 } } -static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[][3], float mat[][3]) +static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[3][3], float mat[3][3]) { float wmat[3][3]; @@ -736,7 +735,7 @@ static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonem } static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, float vec[3], DualQuat *dq, - float mat[][3], const float co[3]) + float mat[3][3], const float co[3]) { Bone *bone = pchan->bone; float fac, contrib = 0.0; @@ -783,7 +782,7 @@ static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f } static void pchan_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, float weight, float vec[3], DualQuat *dq, - float mat[][3], const float co[3], float *contrib) + float mat[3][3], const float co[3], float *contrib) { float cop[3], bbonemat[3][3]; DualQuat bbonedq; @@ -1089,7 +1088,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float /* ************ END Armature Deform ******************* */ -void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[][4], int UNUSED(root), +void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int UNUSED(root), int UNUSED(posed)) { copy_m4_m4(M_accumulatedMatrix, bone->arm_mat); @@ -1098,7 +1097,7 @@ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[][ /* **************** Space to Space API ****************** */ /* Convert World-Space Matrix to Pose-Space Matrix */ -void BKE_armature_mat_world_to_pose(Object *ob, float inmat[][4], float outmat[][4]) +void BKE_armature_mat_world_to_pose(Object *ob, float inmat[4][4], float outmat[4][4]) { float obmat[4][4]; @@ -1132,7 +1131,7 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl /* Simple helper, computes the offset bone matrix. * offs_bone = yoffs(b-1) + root(b) + bonemat(b). * Not exported, as it is only used in this file currently... */ -static void get_offset_bone_mat(Bone *bone, float offs_bone[][4]) +static void get_offset_bone_mat(Bone *bone, float offs_bone[4][4]) { if (!bone->parent) return; @@ -1164,7 +1163,7 @@ static void get_offset_bone_mat(Bone *bone, float offs_bone[][4]) * pose-channel into its local space (i.e. 'visual'-keyframing). * (note: I don't understand that, so I keep it :p --mont29). */ -void BKE_pchan_to_pose_mat(bPoseChannel *pchan, float rotscale_mat[][4], float loc_mat[][4]) +void BKE_pchan_to_pose_mat(bPoseChannel *pchan, float rotscale_mat[4][4], float loc_mat[4][4]) { Bone *bone, *parbone; bPoseChannel *parchan; @@ -1253,7 +1252,7 @@ void BKE_pchan_to_pose_mat(bPoseChannel *pchan, float rotscale_mat[][4], float l /* Convert Pose-Space Matrix to Bone-Space Matrix. * NOTE: this cannot be used to convert to pose-space transforms of the supplied * pose-channel into its local space (i.e. 'visual'-keyframing) */ -void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outmat[][4]) +void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) { float rotscale_mat[4][4], loc_mat[4][4], inmat_[4][4]; @@ -1269,7 +1268,7 @@ void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float } /* Convert Bone-Space Matrix to Pose-Space Matrix. */ -void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[][4], float outmat[][4]) +void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) { float rotscale_mat[4][4], loc_mat[4][4], inmat_[4][4]; @@ -1298,7 +1297,7 @@ void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], fl copy_v3_v3(outloc, nLocMat[3]); } -void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[][4], float outmat[][4]) +void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) { bPoseChannel work_pchan = *pchan; @@ -1316,7 +1315,7 @@ void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inm } /* same as BKE_object_mat3_to_rot() */ -void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[][3], short use_compat) +void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[3][3], short use_compat) { switch (pchan->rotmode) { case ROT_MODE_QUAT: @@ -1335,7 +1334,7 @@ void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[][3], short use_compat /* Apply a 4x4 matrix to the pose bone, * similar to BKE_object_apply_mat4() */ -void BKE_pchan_apply_mat4(bPoseChannel *pchan, float mat[][4], short use_compat) +void BKE_pchan_apply_mat4(bPoseChannel *pchan, float mat[4][4], short use_compat) { float rot[3][3]; mat4_to_loc_rot_size(pchan->loc, rot, pchan->size, mat); @@ -1345,7 +1344,7 @@ void BKE_pchan_apply_mat4(bPoseChannel *pchan, float mat[][4], short use_compat) /* Remove rest-position effects from pose-transform for obtaining * 'visual' transformation of pose-channel. * (used by the Visual-Keyframing stuff) */ -void BKE_armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]) +void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4]) { float imat[4][4]; @@ -1425,7 +1424,7 @@ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float * *************************************************************************** */ /* Computes vector and roll based on a rotation. * "mat" must contain only a rotation, and no scaling. */ -void mat3_to_vec_roll(float mat[][3], float r_vec[3], float *r_roll) +void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll) { if (r_vec) { copy_v3_v3(r_vec, mat[1]); @@ -1444,7 +1443,7 @@ void mat3_to_vec_roll(float mat[][3], float r_vec[3], float *r_roll) /* Calculates the rest matrix of a bone based * On its vector and a roll around that vector */ -void vec_roll_to_mat3(const float vec[3], const float roll, float mat[][3]) +void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]) { float nor[3], axis[3], target[3] = {0, 1, 0}; float theta; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index f0d201ea3f7..5c0856bc95b 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -54,9 +54,9 @@ #include "DNA_screen_types.h" #include "DNA_sequence_types.h" #include "DNA_sound_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_blenlib.h" -#include "BLI_bpath.h" #include "BLI_dynstr.h" #include "BLI_utildefines.h" #include "BLI_callbacks.h" @@ -65,6 +65,7 @@ #include "IMB_moviecache.h" #include "BKE_blender.h" +#include "BKE_bpath.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_displist.h" @@ -80,8 +81,11 @@ #include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_sound.h" + #include "RE_pipeline.h" +#include "BLF_api.h" + #include "BLO_undofile.h" #include "BLO_readfile.h" #include "BLO_writefile.h" @@ -179,7 +183,7 @@ static void clean_paths(Main *main) { Scene *scene; - BLI_bpath_traverse_main(main, clean_paths_visit_cb, BLI_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL); + BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL); for (scene = main->scene.first; scene; scene = scene->id.next) { BLI_clean(scene->r.pic); @@ -230,6 +234,9 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath /* but use new Scene pointer */ curscene = bfd->curscene; if (curscene == NULL) curscene = bfd->main->scene.first; + /* empty file, we add a scene to make Blender work */ + if (curscene == NULL) curscene = BKE_scene_add(bfd->main, "Empty"); + /* and we enforce curscene to be in current screen */ if (curscreen) curscreen->scene = curscene; /* can run in bgmode */ @@ -270,7 +277,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath G.fileflags = bfd->fileflags; CTX_wm_manager_set(C, G.main->wm.first); CTX_wm_screen_set(C, bfd->curscreen); - CTX_data_scene_set(C, bfd->curscreen->scene); + CTX_data_scene_set(C, bfd->curscene); CTX_wm_area_set(C, NULL); CTX_wm_region_set(C, NULL); CTX_wm_menu_set(C, NULL); @@ -280,7 +287,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath if (CTX_data_scene(C) == NULL) { /* in case we don't even have a local scene, add one */ if (!G.main->scene.first) - BKE_scene_add("Scene"); + BKE_scene_add(G.main, "Scene"); CTX_data_scene_set(C, G.main->scene.first); CTX_wm_screen(C)->scene = CTX_data_scene(C); @@ -310,23 +317,38 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath if (G.main->versionfile < 250) do_versions_ipos_to_animato(G.main); - if (recover && bfd->filename[0] && G.relbase_valid) { + G.main->recovered = 0; + + /* startup.blend or recovered startup */ + if (bfd->filename[0] == 0) { + G.main->name[0] = 0; + } + else if (recover && G.relbase_valid) { /* in case of autosave or quit.blend, use original filename instead * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */ filepath = bfd->filename; + G.main->recovered = 1; + + /* these are the same at times, should never copy to the same location */ + if (G.main->name != filepath) + BLI_strncpy(G.main->name, filepath, FILE_MAX); } -#if 0 - else if (!G.relbase_valid) { - /* otherwise, use an empty string as filename, rather than <memory2> */ - filepath = ""; - } -#endif - /* these are the same at times, should never copy to the same location */ - if (G.main->name != filepath) - BLI_strncpy(G.main->name, filepath, FILE_MAX); - /* baseflags, groups, make depsgraph, etc */ + /* first handle case if other windows have different scenes visible */ + if (mode == 0) { + wmWindowManager *wm = G.main->wm.first; + + if (wm) { + wmWindow *win; + + for (win = wm->windows.first; win; win = win->next) { + if (win->screen && win->screen->scene) /* zealous check... */ + if (win->screen->scene != CTX_data_scene(C)) + BKE_scene_set_background(G.main, win->screen->scene); + } + } + } BKE_scene_set_background(G.main, CTX_data_scene(C)); if (mode != 'u') { @@ -335,7 +357,6 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath MEM_freeN(bfd); - (void)curscene; /* quiet warning */ } static int handle_subversion_warning(Main *main, ReportList *reports) @@ -393,6 +414,14 @@ void BKE_userdef_free(void) BLI_freelistN(&U.addons); } +/* handle changes in settings that need recalc */ +void BKE_userdef_state(void) +{ + BLF_default_dpi(U.pixelsize * U.dpi); + U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72; + +} + int BKE_read_file(bContext *C, const char *filepath, ReportList *reports) { BlendFileData *bfd; @@ -439,14 +468,57 @@ int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *report BlendFileData *bfd; bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports); - if (bfd) + if (bfd) { + /* remove the unused screens and wm */ + while (bfd->main->wm.first) + BKE_libblock_free(&bfd->main->wm, bfd->main->wm.first); + while (bfd->main->screen.first) + BKE_libblock_free(&bfd->main->screen, bfd->main->screen.first); + setup_app_data(C, bfd, "<memory1>"); + } else BKE_reports_prepend(reports, "Loading failed: "); return (bfd ? 1 : 0); } +/* only read the userdef from a .blend */ +int BKE_read_file_userdef(const char *filepath, ReportList *reports) +{ + BlendFileData *bfd; + int retval = 0; + + bfd = BLO_read_from_file(filepath, reports); + if (bfd->user) { + retval = BKE_READ_FILE_OK_USERPREFS; + + /* only here free userdef themes... */ + BKE_userdef_free(); + + U = *bfd->user; + MEM_freeN(bfd->user); + } + free_main(bfd->main); + MEM_freeN(bfd); + + return retval; +} + +/* only write the userdef in a .blend */ +int BKE_write_file_userdef(const char *filepath, ReportList *reports) +{ + Main *mainb = MEM_callocN(sizeof(Main), "empty main"); + int retval = 0; + + if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) { + retval = 1; + } + + MEM_freeN(mainb); + + return retval; +} /* ***************** testing for break ************* */ @@ -728,48 +800,39 @@ char *BKE_undo_menu_string(void) return menu; } -/* saves quit.blend */ -void BKE_undo_save_quit(void) +/* saves .blend using undo buffer, returns 1 == success */ +int BKE_undo_save_file(const char *filename) { UndoElem *uel; MemFileChunk *chunk; - char str[FILE_MAX]; const int flag = O_BINARY + O_WRONLY + O_CREAT + O_TRUNC + O_EXCL; int file; if ((U.uiflag & USER_GLOBALUNDO) == 0) { - return; + return 0; } uel = curundo; if (uel == NULL) { fprintf(stderr, "No undo buffer to save recovery file\n"); - return; - } - - /* no undo state to save */ - if (undobase.first == undobase.last) { - return; + return 0; } - /* save the undo state as quit.blend */ - BLI_make_file_string("/", str, BLI_temporary_dir(), "quit.blend"); - /* first try create the file, if it exists call without 'O_CREAT', * to avoid writing to a symlink - use 'O_EXCL' (CVE-2008-1103) */ errno = 0; - file = BLI_open(str, flag, 0666); + file = BLI_open(filename, flag, 0666); if (file == -1) { if (errno == EEXIST) { errno = 0; - file = BLI_open(str, flag & ~O_CREAT, 0666); + file = BLI_open(filename, flag & ~O_CREAT, 0666); } } if (file == -1) { fprintf(stderr, "Unable to save '%s': %s\n", - str, errno ? strerror(errno) : "Unknown error opening file"); - return; + filename, errno ? strerror(errno) : "Unknown error opening file"); + return 0; } for (chunk = uel->memfile.chunks.first; chunk; chunk = chunk->next) { @@ -777,16 +840,15 @@ void BKE_undo_save_quit(void) break; } } - + close(file); if (chunk) { fprintf(stderr, "Unable to save '%s': %s\n", - str, errno ? strerror(errno) : "Unknown error writing file"); - } - else { - printf("Saved session recovery to '%s'\n", str); + filename, errno ? strerror(errno) : "Unknown error writing file"); + return 0; } + return 1; } /* sets curscene */ @@ -806,3 +868,131 @@ Main *BKE_undo_get_main(Scene **scene) return mainp; } +/* ************** copy paste .blend, partial saves ********** */ + +/* assumes data is in G.main */ + +void BKE_copybuffer_begin(void) +{ + /* set all id flags to zero; */ + flag_all_listbases_ids(LIB_NEED_EXPAND | LIB_DOIT, 0); +} + +void BKE_copybuffer_tag_ID(ID *id) +{ + id->flag |= LIB_NEED_EXPAND | LIB_DOIT; +} + +static void copybuffer_doit(void *UNUSED(handle), Main *UNUSED(bmain), void *vid) +{ + if (vid) { + ID *id = vid; + id->flag |= LIB_NEED_EXPAND | LIB_DOIT; + } +} + +/* frees main in end */ +int BKE_copybuffer_save(char *filename, ReportList *reports) +{ + Main *mainb = MEM_callocN(sizeof(Main), "copybuffer"); + ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY]; + int a, retval; + + BLO_main_expander(copybuffer_doit); + BLO_expand_main(NULL, G.main); + + /* move over all tagged blocks */ + set_listbasepointers(G.main, fromarray); + a = set_listbasepointers(mainb, lbarray); + while (a--) { + ID *id, *nextid; + ListBase *lb1 = lbarray[a], *lb2 = fromarray[a]; + + for (id = lb2->first; id; id = nextid) { + nextid = id->next; + if (id->flag & LIB_DOIT) { + BLI_remlink(lb2, id); + BLI_addtail(lb1, id); + } + } + } + + + /* save the buffer */ + retval = BLO_write_file(mainb, filename, 0, reports, NULL); + + /* move back the main, now sorted again */ + set_listbasepointers(G.main, lbarray); + a = set_listbasepointers(mainb, fromarray); + while (a--) { + ID *id; + ListBase *lb1 = lbarray[a], *lb2 = fromarray[a]; + + while (lb2->first) { + id = lb2->first; + BLI_remlink(lb2, id); + BLI_addtail(lb1, id); + id_sort_by_name(lb1, id); + } + } + + MEM_freeN(mainb); + + /* set id flag to zero; */ + flag_all_listbases_ids(LIB_NEED_EXPAND | LIB_DOIT, 0); + + return retval; +} + +/* return success (1) */ +int BKE_copybuffer_paste(bContext *C, char *libname, ReportList *reports) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Main *mainl = NULL; + Library *lib; + BlendHandle *bh; + + bh = BLO_blendhandle_from_file(libname, reports); + + if (bh == NULL) { + /* error reports will have been made by BLO_blendhandle_from_file() */ + return 0; + } + + BKE_scene_base_deselect_all(scene); + + /* tag everything, all untagged data can be made local + * its also generally useful to know what is new + * + * take extra care flag_all_listbases_ids(LIB_LINK_TAG, 0) is called after! */ + flag_all_listbases_ids(LIB_PRE_EXISTING, 1); + + /* here appending/linking starts */ + mainl = BLO_library_append_begin(bmain, &bh, libname); + + BLO_library_append_all(mainl, bh); + + BLO_library_append_end(C, mainl, &bh, 0, 0); + + /* mark all library linked objects to be updated */ + recalc_all_library_objects(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* append, rather than linking */ + lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath)); + BKE_library_make_local(bmain, lib, 1); + + /* important we unset, otherwise these object wont + * link into other scenes from this blend file */ + flag_all_listbases_ids(LIB_PRE_EXISTING, 0); + + /* recreate dependency graph to include new objects */ + DAG_scene_sort(bmain, scene); + DAG_ids_flush_update(bmain, 0); + + BLO_blendhandle_close(bh); + /* remove library... */ + + return 1; +} diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c new file mode 100644 index 00000000000..24b13b062f3 --- /dev/null +++ b/source/blender/blenkernel/intern/bpath.c @@ -0,0 +1,726 @@ +/* + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell barton, Alex Fraser + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/bpath.c + * \ingroup bli + */ + +/* TODO, + * currently there are some cases we don't support. + * - passing output paths to the visitor?, like render out. + * - passing sequence strips with many images. + * - passing directory paths - visitors don't know which path is a dir or a file. + * */ + +#include <sys/stat.h> + +#include <string.h> +#include <assert.h> + +/* path/file handling stuff */ +#ifndef WIN32 +# include <dirent.h> +# include <unistd.h> +#else +# include <io.h> +# include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_image_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_object_fluidsim.h" +#include "DNA_object_force.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_sequence_types.h" +#include "DNA_sound_types.h" +#include "DNA_text_types.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_texture_types.h" +#include "DNA_vfont_types.h" +#include "DNA_scene_types.h" +#include "DNA_smoke_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_font.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_report.h" +#include "BKE_sequencer.h" +#include "BKE_image.h" /* so we can check the image's type */ + +#include "BKE_bpath.h" /* own include */ + +static int checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src) +{ + ReportList *reports = (ReportList *)userdata; + + if (!BLI_exists(path_src)) { + BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src); + } + + return FALSE; +} + +/* high level function */ +void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports) +{ + BKE_bpath_traverse_main(bmain, checkMissingFiles_visit_cb, BKE_BPATH_TRAVERSE_ABS, reports); +} + +typedef struct BPathRemap_Data { + const char *basedir; + ReportList *reports; + + int count_tot; + int count_changed; + int count_failed; +} BPathRemap_Data; + +static int makeFilesRelative_visit_cb(void *userdata, char *path_dst, const char *path_src) +{ + BPathRemap_Data *data = (BPathRemap_Data *)userdata; + + data->count_tot++; + + if (BLI_path_is_rel(path_src)) { + return FALSE; /* already relative */ + } + else { + strcpy(path_dst, path_src); + BLI_path_rel(path_dst, data->basedir); + if (BLI_path_is_rel(path_dst)) { + data->count_changed++; + } + else { + BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src); + data->count_failed++; + } + return TRUE; + } +} + +void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports) +{ + BPathRemap_Data data = {NULL}; + + if (basedir[0] == '\0') { + printf("%s: basedir='', this is a bug\n", __func__); + return; + } + + data.basedir = basedir; + data.reports = reports; + + BKE_bpath_traverse_main(bmain, makeFilesRelative_visit_cb, 0, (void *)&data); + + BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, + "Total files %d | Changed %d | Failed %d", + data.count_tot, data.count_changed, data.count_failed); +} + +static int makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const char *path_src) +{ + BPathRemap_Data *data = (BPathRemap_Data *)userdata; + + data->count_tot++; + + if (BLI_path_is_rel(path_src) == FALSE) { + return FALSE; /* already absolute */ + } + else { + strcpy(path_dst, path_src); + BLI_path_abs(path_dst, data->basedir); + if (BLI_path_is_rel(path_dst) == FALSE) { + data->count_changed++; + } + else { + BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src); + data->count_failed++; + } + return TRUE; + } +} + +/* similar to BKE_bpath_relative_convert - keep in sync! */ +void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports) +{ + BPathRemap_Data data = {NULL}; + + if (basedir[0] == '\0') { + printf("%s: basedir='', this is a bug\n", __func__); + return; + } + + data.basedir = basedir; + data.reports = reports; + + BKE_bpath_traverse_main(bmain, makeFilesAbsolute_visit_cb, 0, (void *)&data); + + BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, + "Total files %d | Changed %d | Failed %d", + data.count_tot, data.count_changed, data.count_failed); +} + +/** + * find this file recursively, use the biggest file so thumbnails don't get used by mistake + * \param filename_new: the path will be copied here, caller must initialize as empty string. + * \param dirname: subdir to search + * \param filename: set this filename + * \param filesize: filesize for the file + * + * \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) +{ + /* file searching stuff */ + DIR *dir; + struct dirent *de; + struct stat status; + char path[FILE_MAX]; + int size; + int found = FALSE; + + dir = opendir(dirname); + + if (dir == NULL) + return found; + + if (*filesize == -1) + *filesize = 0; /* dir opened fine */ + + while ((de = readdir(dir)) != NULL) { + + if (strcmp(".", de->d_name) == 0 || strcmp("..", de->d_name) == 0) + continue; + + BLI_join_dirfile(path, sizeof(path), dirname, de->d_name); + + if (stat(path, &status) != 0) + continue; /* cant stat, don't bother with this file, could print debug info here */ + + if (S_ISREG(status.st_mode)) { /* is file */ + if (strncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */ + /* open the file to read its size */ + size = status.st_size; + if ((size > 0) && (size > *filesize)) { /* find the biggest file */ + *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)--; + } + } + } + closedir(dir); + return found; +} + +typedef struct BPathFind_Data { + const char *basedir; + char searchdir[FILE_MAX]; + ReportList *reports; +} BPathFind_Data; + +static int findMissingFiles_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; + int recur_depth = 0; + int found; + + filename_new[0] = '\0'; + + found = findFileRecursive(filename_new, + data->searchdir, BLI_path_basename((char *)path_src), + &filesize, &recur_depth); + + if (filesize == -1) { /* could not open dir */ + BKE_reportf(data->reports, RPT_WARNING, + "Could not open directory '%s'", + BLI_path_basename(data->searchdir)); + return FALSE; + } + else if (found == FALSE) { + BKE_reportf(data->reports, RPT_WARNING, + "Could not find '%s' in '%s'", + BLI_path_basename((char *)path_src), data->searchdir); + return FALSE; + } + else { + BLI_strncpy(path_dst, filename_new, FILE_MAX); + return TRUE; + } +} + +void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportList *reports) +{ + struct BPathFind_Data data = {NULL}; + + data.reports = reports; + BLI_split_dir_part(searchpath, data.searchdir, sizeof(data.searchdir)); + + BKE_bpath_traverse_main(bmain, findMissingFiles_visit_cb, 0, (void *)&data); +} + +/* Run a visitor on a string, replacing the contents of the string as needed. */ +static int rewrite_path_fixed(char *path, BPathVisitor visit_cb, const char *absbase, void *userdata) +{ + char path_src_buf[FILE_MAX]; + const char *path_src; + char path_dst[FILE_MAX]; + + if (absbase) { + BLI_strncpy(path_src_buf, path, sizeof(path_src_buf)); + BLI_path_abs(path_src_buf, absbase); + path_src = path_src_buf; + } + else { + path_src = path; + } + + if (visit_cb(userdata, path_dst, path_src)) { + BLI_strncpy(path, path_dst, FILE_MAX); + return TRUE; + } + else { + return FALSE; + } +} + +static int rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR], + char path_file[FILE_MAXFILE], + BPathVisitor visit_cb, + const char *absbase, + void *userdata) +{ + char path_src[FILE_MAX]; + char path_dst[FILE_MAX]; + + BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file); + + if (absbase) { + BLI_path_abs(path_src, absbase); + } + + if (visit_cb(userdata, path_dst, (const char *)path_src)) { + BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE); + return TRUE; + } + else { + return FALSE; + } +} + +static int rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *absbase, void *userdata) +{ + char path_src_buf[FILE_MAX]; + const char *path_src; + char path_dst[FILE_MAX]; + + if (absbase) { + BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf)); + BLI_path_abs(path_src_buf, absbase); + path_src = path_src_buf; + } + else { + path_src = *path; + } + + if (visit_cb(userdata, path_dst, path_src)) { + MEM_freeN((*path)); + (*path) = BLI_strdup(path_dst); + return TRUE; + } + else { + return FALSE; + } +} + +/* Run visitor function 'visit' on all paths contained in 'id'. */ +void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data) +{ + const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL; + + if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) { + return; + } + + switch (GS(id->name)) { + case ID_IM: + { + Image *ima; + ima = (Image *)id; + if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { + if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data); + } + } + break; + } + case ID_BR: + { + Brush *brush = (Brush *)id; + if (brush->icon_filepath[0]) { + rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data); + } + break; + } + case ID_OB: + { + Object *ob = (Object *)id; + ModifierData *md; + ParticleSystem *psys; + +#define BPATH_TRAVERSE_POINTCACHE(ptcaches) \ + { \ + PointCache *cache; \ + for (cache = (ptcaches).first; cache; cache = cache->next) { \ + if (cache->flag & PTCACHE_DISK_CACHE) { \ + rewrite_path_fixed(cache->path, \ + visit_cb, \ + absbase, \ + bpath_user_data); \ + } \ + } \ + } (void)0 + + /* do via modifiers instead */ +#if 0 + if (ob->fluidsimSettings) { + rewrite_path_fixed(ob->fluidsimSettings->surfdataPath, visit_cb, absbase, bpath_user_data); + } +#endif + + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Fluidsim) { + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; + if (fluidmd->fss) { + rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data); + } + } + else if (md->type == eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData *)md; + if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { + 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); + } + } + + if (ob->soft) { + BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches); + } + + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + BPATH_TRAVERSE_POINTCACHE(psys->ptcaches); + } + +#undef BPATH_TRAVERSE_POINTCACHE + + break; + } + case ID_SO: + { + bSound *sound = (bSound *)id; + if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { + rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data); + } + break; + } + case ID_TXT: + if (((Text *)id)->name) { + rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data); + } + break; + case ID_VF: + { + VFont *vfont = (VFont *)id; + if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { + if (BKE_vfont_is_builtin(vfont) == FALSE) { + rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data); + } + } + break; + } + case ID_MA: + { + Material *ma = (Material *)id; + bNodeTree *ntree = ma->nodetree; + + if (ntree) { + bNode *node; + + for (node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_SCRIPT) { + NodeShaderScript *nss = (NodeShaderScript *)node->storage; + rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data); + } + } + } + break; + } + case ID_NT: + { + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + + if (ntree->type == NTREE_SHADER) { + /* same as lines above */ + for (node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_SCRIPT) { + NodeShaderScript *nss = (NodeShaderScript *)node->storage; + rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data); + } + } + } + break; + } + case ID_TE: + { + Tex *tex = (Tex *)id; + if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) { + rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data); + } + break; + } + case ID_SCE: + { + Scene *scene = (Scene *)id; + if (scene->ed) { + Sequence *seq; + + SEQ_BEGIN(scene->ed, seq) + { + if (SEQ_HAS_PATH(seq)) { + if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM)) { + rewrite_path_fixed_dirfile(seq->strip->dir, seq->strip->stripdata->name, + visit_cb, absbase, bpath_user_data); + } + else if (seq->type == SEQ_TYPE_IMAGE) { + /* might want an option not to loop over all strips */ + StripElem *se = seq->strip->stripdata; + int len = MEM_allocN_len(se) / sizeof(*se); + int i; + + if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) { + /* only operate on one path */ + len = MIN2(1, len); + } + + for (i = 0; i < len; i++, se++) { + rewrite_path_fixed_dirfile(seq->strip->dir, se->name, + visit_cb, absbase, bpath_user_data); + } + } + else { + /* simple case */ + rewrite_path_fixed(seq->strip->dir, visit_cb, absbase, bpath_user_data); + } + } + + } + SEQ_END + } + break; + } + case ID_ME: + { + Mesh *me = (Mesh *)id; + if (me->ldata.external) { + rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data); + } + break; + } + case ID_LI: + { + Library *lib = (Library *)id; + if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { + BKE_library_filepath_set(lib, lib->name); + } + break; + } + case ID_MC: + { + MovieClip *clip = (MovieClip *)id; + rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data); + break; + } + default: + /* Nothing to do for other IDs that don't contain file paths. */ + break; + } +} + +void BKE_bpath_traverse_id_list(Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data) +{ + ID *id; + for (id = lb->first; id; id = id->next) { + BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data); + } +} + +void BKE_bpath_traverse_main(Main *bmain, BPathVisitor visit_cb, const int flag, void *bpath_user_data) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int a = set_listbasepointers(bmain, lbarray); + while (a--) { + BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data); + } +} + +/* Rewrites a relative path to be relative to the main file - unless the path is + * absolute, in which case it is not altered. */ +int BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src) +{ + /* be sure there is low chance of the path being too short */ + char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE]; + const char *base_new = ((char **)pathbase_v)[0]; + const char *base_old = ((char **)pathbase_v)[1]; + + if (BLI_path_is_rel(base_old)) { + printf("%s: error, old base path '%s' is not absolute.\n", + __func__, base_old); + return FALSE; + } + + /* Make referenced file absolute. This would be a side-effect of + * BLI_cleanup_file, but we do it explicitly so we know if it changed. */ + BLI_strncpy(filepath, path_src, FILE_MAX); + if (BLI_path_abs(filepath, base_old)) { + /* Path was relative and is now absolute. Remap. + * Important BLI_cleanup_dir runs before the path is made relative + * because it wont work for paths that start with "//../" */ + BLI_cleanup_file(base_new, filepath); + BLI_path_rel(filepath, base_new); + BLI_strncpy(path_dst, filepath, FILE_MAX); + return TRUE; + } + else { + /* Path was not relative to begin with. */ + return FALSE; + } +} + + +/* -------------------------------------------------------------------- */ +/** + * Backup/Restore/Free functions, + * \note These functions assume the data won't chane order. + */ + +struct PathStore { + struct PathStore *next, *prev; +} PathStore; + +static int bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src) +{ + /* store the path and string in a single alloc */ + ListBase *ls = userdata; + size_t path_size = strlen(path_src) + 1; + struct PathStore *path_store = MEM_mallocN(sizeof(PathStore) + path_size, __func__); + char *filepath = (char *)(path_store + 1); + + memcpy(filepath, path_src, path_size); + BLI_addtail(ls, path_store); + return FALSE; +} + +static int bpath_list_restore(void *userdata, char *path_dst, const char *path_src) +{ + /* assume ls->first wont be NULL because the number of paths can't change! + * (if they do caller is wrong) */ + ListBase *ls = userdata; + struct PathStore *path_store = ls->first; + const char *filepath = (char *)(path_store + 1); + int ret; + + if (strcmp(path_src, filepath) == 0) { + ret = FALSE; + } + else { + BLI_strncpy(path_dst, filepath, FILE_MAX); + ret = TRUE; + } + + BLI_freelinkN(ls, path_store); + return ret; +} + +/* return ls_handle */ +void *BKE_bpath_list_backup(Main *bmain, const int flag) +{ + ListBase *ls = MEM_callocN(sizeof(ListBase), __func__); + + BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls); + + return ls; +} + +void BKE_bpath_list_restore(Main *bmain, const int flag, void *ls_handle) +{ + ListBase *ls = ls_handle; + + BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls); +} + +void BKE_bpath_list_free(void *ls_handle) +{ + ListBase *ls = ls_handle; + BLI_assert(ls->first == NULL); /* assumes we were used */ + BLI_freelistN(ls); + MEM_freeN(ls); +} diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index f310895f590..405b1efb25d 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -39,18 +39,19 @@ #include "DNA_color_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" #include "WM_types.h" #include "RNA_access.h" -#include "BLI_bpath.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_rand.h" #include "BLI_utildefines.h" +#include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_global.h" @@ -644,8 +645,9 @@ void BKE_brush_size_set(Scene *scene, Brush *brush, int size) int BKE_brush_size_get(const Scene *scene, Brush *brush) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - - return (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size; + int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size; + + return (int)((float)size * U.pixelsize); } int BKE_brush_use_locked_size(const Scene *scene, Brush *brush) diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 54bbe4bf495..34adeb4fefb 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -40,12 +40,12 @@ #include "BLI_blenlib.h" #include "BLI_edgehash.h" #include "BLI_math.h" -#include "BLI_pbvh.h" #include "BLI_array.h" #include "BLI_smallhash.h" #include "BLI_utildefines.h" #include "BLI_scanfill.h" +#include "BKE_pbvh.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 4641a02265a..f0043d9fa77 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -567,7 +567,9 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned Scene *sce_iter; /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { - if (base->lay & self->lay) + /* Need to check for active layers, too. + Otherwise this check fails if the objects are not on the same layer - DG */ + if ((base->lay & self->lay) || (base->lay & scene->lay)) add_collision_object(&objs, &numobj, &maxobj, base->object, self, 0, modifier_type); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 97d750854f4..c3aab22fe5a 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -219,7 +219,7 @@ void constraints_clear_evalob(bConstraintOb *cob) * of a matrix from one space to another for constraint evaluation. * For now, this is only implemented for Objects and PoseChannels. */ -void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[][4], short from, short to) +void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) { float diff_mat[4][4]; float imat[4][4]; @@ -345,7 +345,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[][4] /* ------------ General Target Matrix Tools ---------- */ /* function that sets the given matrix based on given vertex group in mesh */ -static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[][4]) +static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4]) { DerivedMesh *dm = NULL; BMEditMesh *em = BMEdit_FromObject(ob); @@ -441,7 +441,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ } /* function that sets the given matrix based on given vertex group in lattice */ -static void contarget_get_lattice_mat(Object *ob, const char *substring, float mat[][4]) +static void contarget_get_lattice_mat(Object *ob, const char *substring, float mat[4][4]) { Lattice *lt = (Lattice *)ob->data; @@ -494,7 +494,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m /* generic function to get the appropriate matrix for most target cases */ /* The cases where the target can be object data have not been implemented */ -static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[][4], short from, short to, float headtail) +static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, float headtail) { /* Case OBJECT */ if (!strlen(substring)) { @@ -890,7 +890,7 @@ static int basis_cross(int n, int m) } } -static void vectomat(const float vec[3], const float target_up[3], short axis, short upflag, short flags, float m[][3]) +static void vectomat(const float vec[3], const float target_up[3], short axis, short upflag, short flags, float m[3][3]) { float n[3]; float u[3]; /* vector specifying the up axis */ @@ -4610,7 +4610,7 @@ short proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) * None of the actual calculations of the matrices should be done here! Also, this function is * not to be used by any new constraints, particularly any that have multiple targets. */ -void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime) +void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime) { bConstraintTypeInfo *cti = constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 754a4fbc0c8..1d199cdf1e2 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -36,7 +36,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_bpath.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -68,7 +67,7 @@ /* local */ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3], short cox, short coy, - float *labda, float *mu, float vec[3]); + float *lambda, float *mu, float vec[3]); void BKE_curve_unlink(Curve *cu) { @@ -1615,7 +1614,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp, int forRende static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3], short cox, short coy, - float *labda, float *mu, float vec[3]) + float *lambda, float *mu, float vec[3]) { /* return: * -1: collinear @@ -1629,22 +1628,22 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c if (deler == 0.0f) return -1; - *labda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]); - *labda = -(*labda / deler); + *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]); + *lambda = -(*lambda / deler); deler = v3[coy] - v4[coy]; if (deler == 0) { deler = v3[cox] - v4[cox]; - *mu = -(*labda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler; + *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler; } else { - *mu = -(*labda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler; + *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler; } - vec[cox] = *labda * (v2[cox] - v1[cox]) + v1[cox]; - vec[coy] = *labda * (v2[coy] - v1[coy]) + v1[coy]; + vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox]; + vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy]; - if (*labda >= 0.0f && *labda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) { - if (*labda == 0.0f || *labda == 1.0f || *mu == 0.0f || *mu == 1.0f) + if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) { + if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f) return 1; return 2; } @@ -1654,7 +1653,7 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c static short bevelinside(BevList *bl1, BevList *bl2) { - /* is bl2 INSIDE bl1 ? with left-right method and "labda's" */ + /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */ /* returns '1' if correct hole */ BevPoint *bevp, *prevbevp; float min, max, vec[3], hvec1[3], hvec2[3], lab, mu; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index b2f8db0dcce..0f352dede23 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2104,7 +2104,7 @@ int CustomData_set_layer_name(const CustomData *data, int type, int n, const cha if (layer_index < 0) return 0; if (!name) return 0; - strcpy(data->layers[layer_index].name, name); + BLI_strncpy(data->layers[layer_index].name, name, sizeof(data->layers[layer_index].name)); return 1; } @@ -2854,10 +2854,11 @@ void CustomData_validate_layer_name(const CustomData *data, int type, const char * deleted, so assign the active layer to name */ index = CustomData_get_active_layer_index(data, type); - strcpy(outname, data->layers[index].name); + BLI_strncpy(outname, data->layers[index].name, MAX_CUSTOMDATA_LAYER_NAME); + } + else { + BLI_strncpy(outname, name, MAX_CUSTOMDATA_LAYER_NAME); } - else - strcpy(outname, name); } int CustomData_verify_versions(struct CustomData *data, int index) diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 3ed759392b6..6ba140fcec1 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2482,30 +2482,51 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s } -static void dag_current_scene_layers(Main *bmain, Scene **sce, unsigned int *lay) +/* struct returned by DagSceneLayer */ +typedef struct DagSceneLayer { + struct DagSceneLayer *next, *prev; + Scene *scene; + unsigned int layer; +} DagSceneLayer; + +/* returns visible scenes with valid DAG */ +static void dag_current_scene_layers(Main *bmain, ListBase *lb) { wmWindowManager *wm; wmWindow *win; + + lb->first = lb->last = NULL; - /* only one scene supported currently, making more scenes work - * correctly requires changes beyond just the dependency graph */ - - *sce = NULL; - *lay = 0; - + /* if we have a windowmanager, look into windows */ if ((wm = bmain->wm.first)) { - /* if we have a windowmanager, look into windows */ + + flag_listbase_ids(&bmain->scene, LIB_DOIT, 1); + for (win = wm->windows.first; win; win = win->next) { - if (win->screen) { - if (*sce == NULL) *sce = win->screen->scene; - *lay |= BKE_screen_visible_layers(win->screen, win->screen->scene); + if (win->screen && win->screen->scene->theDag) { + Scene *scene = win->screen->scene; + + if (scene->id.flag & LIB_DOIT) { + DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); + + BLI_addtail(lb, dsl); + + dsl->scene = scene; + dsl->layer = BKE_screen_visible_layers(win->screen, scene); + + scene->id.flag &= ~LIB_DOIT; + } } } } else { /* if not, use the first sce */ - *sce = bmain->scene.first; - if (*sce) *lay = (*sce)->lay; + DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); + + BLI_addtail(lb, dsl); + + dsl->scene = bmain->scene.first; + dsl->layer = dsl->scene->lay; /* XXX for background mode, we should get the scene * from somewhere, for the -S option, but it's in @@ -2515,29 +2536,36 @@ static void dag_current_scene_layers(Main *bmain, Scene **sce, unsigned int *lay void DAG_ids_flush_update(Main *bmain, int time) { - Scene *sce; - unsigned int lay; - - dag_current_scene_layers(bmain, &sce, &lay); + ListBase listbase; + DagSceneLayer *dsl; + + /* get list of visible scenes and layers */ + dag_current_scene_layers(bmain, &listbase); - if (sce) - DAG_scene_flush_update(bmain, sce, lay, time); + for (dsl = listbase.first; dsl; dsl = dsl->next) + DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, time); + + BLI_freelistN(&listbase); } void DAG_on_visible_update(Main *bmain, const short do_time) { - Scene *scene; - Base *base; - Object *ob; - Group *group; - GroupObject *go; - DagNode *node; - unsigned int lay, oblay; - - dag_current_scene_layers(bmain, &scene, &lay); - - if (scene && scene->theDag) { + ListBase listbase; + DagSceneLayer *dsl; + + /* get list of visible scenes and layers */ + dag_current_scene_layers(bmain, &listbase); + + for (dsl = listbase.first; dsl; dsl = dsl->next) { + Scene *scene = dsl->scene; Scene *sce_iter; + Base *base; + Object *ob; + Group *group; + GroupObject *go; + DagNode *node; + unsigned int lay = dsl->layer, oblay; + /* derivedmeshes and displists are not saved to file so need to be * remade, tag them so they get remade in the scene update loop, * note armature poses or object matrices are preserved and do not @@ -2574,6 +2602,8 @@ void DAG_on_visible_update(Main *bmain, const short do_time) DAG_scene_update_flags(bmain, scene, lay, do_time); scene->lay_updated |= lay; } + + BLI_freelistN(&listbase); /* hack to get objects updating on layer changes */ DAG_id_type_tag(bmain, ID_OB); @@ -2758,14 +2788,15 @@ static void dag_id_flush_update(Scene *sce, ID *id) void DAG_ids_flush_tagged(Main *bmain) { + ListBase listbase; + DagSceneLayer *dsl; ListBase *lbarray[MAX_LIBARRAY]; - Scene *sce; - unsigned int lay; int a, do_flush = FALSE; + + /* get list of visible scenes and layers */ + dag_current_scene_layers(bmain, &listbase); - dag_current_scene_layers(bmain, &sce, &lay); - - if (!sce || !sce->theDag) + if (listbase.first == NULL) return; /* loop over all ID types */ @@ -2780,7 +2811,10 @@ void DAG_ids_flush_tagged(Main *bmain) if (id && bmain->id_tag_update[id->name[0]]) { for (; id; id = id->next) { if (id->flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA)) { - dag_id_flush_update(sce, id); + + for (dsl = listbase.first; dsl; dsl = dsl->next) + dag_id_flush_update(dsl->scene, id); + do_flush = TRUE; } } @@ -2788,8 +2822,12 @@ void DAG_ids_flush_tagged(Main *bmain) } /* flush changes to other objects */ - if (do_flush) - DAG_scene_flush_update(bmain, sce, lay, 0); + if (do_flush) { + for (dsl = listbase.first; dsl; dsl = dsl->next) + DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, 0); + } + + BLI_freelistN(&listbase); } void DAG_ids_check_recalc(Main *bmain, Scene *scene, int time) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index ed85e5b627b..56b9db94108 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -397,7 +397,7 @@ void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface) } else { strcpy(surface->output_name, "dp_"); - strcpy(surface->output_name2, surface->output_name); + BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2)); surface->flags &= ~MOD_DPAINT_ANTIALIAS; surface->depth_clamp = 0.0f; } @@ -1193,7 +1193,68 @@ void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct Dyn /* Copy data */ if (tpmd->canvas) { + DynamicPaintSurface *surface; tpmd->canvas->pmd = tpmd; + /* free default surface */ + if (tpmd->canvas->surfaces.first) + dynamicPaint_freeSurface(tpmd->canvas->surfaces.first); + + /* copy existing surfaces */ + for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { + DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL); + + /* surface settings */ + t_surface->brush_group = surface->brush_group; + MEM_freeN(t_surface->effector_weights); + t_surface->effector_weights = MEM_dupallocN(surface->effector_weights); + + BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name)); + t_surface->format = surface->format; + t_surface->type = surface->type; + t_surface->disp_type = surface->disp_type; + t_surface->image_fileformat = surface->image_fileformat; + t_surface->effect_ui = surface->effect_ui; + t_surface->preview_id = surface->preview_id; + t_surface->init_color_type = surface->init_color_type; + t_surface->flags = surface->flags; + t_surface->effect = surface->effect; + + t_surface->image_resolution = surface->image_resolution; + t_surface->substeps = surface->substeps; + t_surface->start_frame = surface->start_frame; + t_surface->end_frame = surface->end_frame; + + copy_v4_v4(t_surface->init_color, surface->init_color); + t_surface->init_texture = surface->init_texture; + BLI_strncpy(t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername)); + + t_surface->dry_speed = surface->dry_speed; + t_surface->diss_speed = surface->diss_speed; + t_surface->color_dry_threshold = surface->color_dry_threshold; + t_surface->depth_clamp = surface->depth_clamp; + t_surface->disp_factor = surface->disp_factor; + + + t_surface->spread_speed = surface->spread_speed; + t_surface->color_spread_speed = surface->color_spread_speed; + t_surface->shrink_speed = surface->shrink_speed; + t_surface->drip_vel = surface->drip_vel; + t_surface->drip_acc = surface->drip_acc; + + t_surface->influence_scale = surface->influence_scale; + t_surface->radius_scale = surface->radius_scale; + + t_surface->wave_damping = surface->wave_damping; + t_surface->wave_speed = surface->wave_speed; + t_surface->wave_timescale = surface->wave_timescale; + t_surface->wave_spring = surface->wave_spring; + + BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name)); + BLI_strncpy(t_surface->image_output_path, surface->image_output_path, sizeof(t_surface->image_output_path)); + BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name)); + BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2)); + } + dynamicPaint_resetPreview(tpmd->canvas); } else if (tpmd->brush) { DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush; diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 321a61ce238..bb8df834d0f 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -39,8 +39,8 @@ #include "BLI_blenlib.h" #include "BLI_edgehash.h" #include "BLI_math.h" -#include "BLI_pbvh.h" +#include "BKE_pbvh.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" #include "BKE_mesh.h" @@ -71,24 +71,24 @@ extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */ BMEditMesh *BMEdit_Create(BMesh *bm, int do_tessellate) { - BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), __func__); + BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__); - tm->bm = bm; + em->bm = bm; if (do_tessellate) { - BMEdit_RecalcTessellation(tm); + BMEdit_RecalcTessellation(em); } - return tm; + return em; } -BMEditMesh *BMEdit_Copy(BMEditMesh *tm) +BMEditMesh *BMEdit_Copy(BMEditMesh *em) { - BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), __func__); - *tm2 = *tm; + BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__); + *em_copy = *em; - tm2->derivedCage = tm2->derivedFinal = NULL; + em_copy->derivedCage = em_copy->derivedFinal = NULL; - tm2->bm = BM_mesh_copy(tm->bm); + em_copy->bm = BM_mesh_copy(em->bm); /* The tessellation is NOT calculated on the copy here, * because currently all the callers of this function use @@ -97,22 +97,22 @@ BMEditMesh *BMEdit_Copy(BMEditMesh *tm) * reasons, in that case it makes more sense to do the * tessellation only when/if that copy ends up getting * used.*/ - tm2->looptris = NULL; + em_copy->looptris = NULL; - tm2->vert_index = NULL; - tm2->edge_index = NULL; - tm2->face_index = NULL; + em_copy->vert_index = NULL; + em_copy->edge_index = NULL; + em_copy->face_index = NULL; - return tm2; + return em_copy; } -static void BMEdit_RecalcTessellation_intern(BMEditMesh *tm) +static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) { /* use this to avoid locking pthread for _every_ polygon * and calling the fill function */ #define USE_TESSFACE_SPEEDUP - BMesh *bm = tm->bm; + BMesh *bm = em->bm; BMLoop *(*looptris)[3] = NULL; BLI_array_declare(looptris); BMIter iter, liter; @@ -125,26 +125,26 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *tm) #if 0 /* note, we could be clever and re-use this array but would need to ensure * its realloced at some point, for now just free it */ - if (tm->looptris) MEM_freeN(tm->looptris); + if (em->looptris) MEM_freeN(em->looptris); - /* Use tm->tottri when set, this means no reallocs while transforming, + /* Use em->tottri when set, this means no reallocs while transforming, * (unless scanfill fails), otherwise... */ /* allocate the length of totfaces, avoid many small reallocs, * if all faces are tri's it will be correct, quads == 2x allocs */ - BLI_array_reserve(looptris, (tm->tottri && tm->tottri < bm->totface * 3) ? tm->tottri : bm->totface); + BLI_array_reserve(looptris, (em->tottri && em->tottri < bm->totface * 3) ? em->tottri : bm->totface); #else /* this means no reallocs for quad dominant models, for */ - if ( (tm->looptris != NULL) && - (tm->tottri != 0) && + if ( (em->looptris != NULL) && + (em->tottri != 0) && /* (totrti <= bm->totface * 2) would be fine for all quads, * but in case there are some ngons, still re-use the array */ - (tm->tottri <= bm->totface * 3)) + (em->tottri <= bm->totface * 3)) { - looptris = tm->looptris; + looptris = em->looptris; } else { - if (tm->looptris) MEM_freeN(tm->looptris); + if (em->looptris) MEM_freeN(em->looptris); BLI_array_reserve(looptris, bm->totface); } @@ -237,8 +237,8 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *tm) } } - tm->tottri = i; - tm->looptris = looptris; + em->tottri = i; + em->looptris = looptris; #undef USE_TESSFACE_SPEEDUP diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index a7d0152a799..0c83bb8d39a 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -183,7 +183,7 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, int setactive) gpl->thickness = 3; /* auto-name */ - strcpy(gpl->info, name); + BLI_strncpy(gpl->info, name, sizeof(gpl->info)); BLI_uniquename(&gpd->layers, gpl, "GP_Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); /* make this one the active one */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f09f128e874..7f0475cf155 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -68,7 +68,6 @@ #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" #include "BKE_bmfont.h" #include "BKE_colortools.h" @@ -1400,7 +1399,9 @@ static void timecode_simple_string(char *text, size_t text_size, const int cfra, } } -/* could allow access externally - 512 is for long names, 64 is for id names */ +#define STAMP_NAME_SIZE ((MAX_ID_NAME - 2) + 16) +/* could allow access externally - 512 is for long names, + * STAMP_NAME_SIZE is for id names, allowing them some room for description */ typedef struct StampData { char file[512]; char note[512]; @@ -1408,12 +1409,13 @@ typedef struct StampData { char marker[512]; char time[512]; char frame[512]; - char camera[64]; - char cameralens[64]; - char scene[64]; - char strip[64]; - char rendertime[64]; + char camera[STAMP_NAME_SIZE]; + char cameralens[STAMP_NAME_SIZE]; + char scene[STAMP_NAME_SIZE]; + char strip[STAMP_NAME_SIZE]; + char rendertime[STAMP_NAME_SIZE]; } StampData; +#undef STAMP_NAME_SIZE static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix) { diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 782d796b8a7..ad95f09826a 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1078,7 +1078,7 @@ static void do_mesh_key(Scene *scene, Object *ob, Key *key, char *out, const int if (key->slurph && key->type != KEY_RELATIVE) { const float ctime_scaled = key->ctime / 100.0f; float delta = (float)key->slurph / tot; - float cfra = (float)scene->r.cfra; + float cfra = (float)scene->r.cfra + scene->r.subframe; int step, a; if (tot > 100 && slurph_opt) { @@ -1176,7 +1176,7 @@ static void do_curve_key(Scene *scene, Object *ob, Key *key, char *out, const in if (key->slurph && key->type != KEY_RELATIVE) { const float ctime_scaled = key->ctime / 100.0f; float delta = (float)key->slurph / tot; - float cfra = (float)scene->r.cfra; + float cfra = (float)scene->r.cfra + scene->r.subframe; Nurb *nu; int i = 0, remain = 0; int step, a; @@ -1258,7 +1258,7 @@ static void do_latt_key(Scene *scene, Object *ob, Key *key, char *out, const int if (key->slurph && key->type != KEY_RELATIVE) { const float ctime_scaled = key->ctime / 100.0f; float delta = (float)key->slurph / tot; - float cfra = (float)scene->r.cfra; + float cfra = (float)scene->r.cfra + scene->r.subframe; int a; for (a = 0; a < tot; a++, cfra += delta) { @@ -1373,7 +1373,7 @@ float *do_ob_key(Scene *scene, Object *ob) } else { /* do shapekey local drivers */ - float ctime = (float)scene->r.cfra; // XXX this needs to be checked + float ctime = (float)scene->r.cfra + scene->r.subframe; BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index a15ca7cb5ce..d98188d8a6f 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -37,7 +37,6 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BLI_bpath.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -753,7 +752,7 @@ void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, /* orco is original not-animated or deformed reference point */ /* result written in vec and mat */ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target, - float orco[3], float vec[3], float mat[][3], int no_rot_axis) + float orco[3], float vec[3], float mat[3][3], int no_rot_axis) { CurveDeform cd; float quat[4]; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index db96567a4da..d21a12b9e6a 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -71,7 +71,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" +#include "BKE_bpath.h" #include "BKE_animsys.h" #include "BKE_camera.h" @@ -137,9 +137,9 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) { char *bpath_user_data[2] = {bmain->name, lib->filepath}; - BLI_bpath_traverse_id(bmain, id, - BLI_bpath_relocate_visitor, - BLI_BPATH_TRAVERSE_SKIP_MULTIFILE, + BKE_bpath_traverse_id(bmain, id, + BKE_bpath_relocate_visitor, + BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, bpath_user_data); } @@ -153,6 +153,14 @@ void id_lib_extern(ID *id) } } +/* ensure we have a real user */ +void id_us_ensure_real(ID *id) +{ + if (ID_REAL_USERS(id) <= 0) { + id->us = MAX2(id->us, 0) + 1; + } +} + void id_us_plus(ID *id) { if (id) { diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 445ea2d4b3b..3bfd4f4f760 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -52,7 +52,6 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" #include "BLI_string.h" #include "BKE_animsys.h" @@ -1857,7 +1856,7 @@ static void convert_tfacematerial(Main *main, Material *ma) mat_new = BKE_material_copy(ma); if (mat_new) { /* rename the material*/ - strcpy(mat_new->id.name, idname); + BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name)); id_us_min((ID *)mat_new); mat_nr = mesh_addmaterial(me, mat_new); diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 805e77cf84f..5c882fd97d6 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -50,8 +50,6 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" - #include "BKE_global.h" #include "BKE_main.h" diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 036f8f5e673..55cf2743bfa 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -46,7 +46,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_bpath.h" #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_scanfill.h" @@ -3009,9 +3008,9 @@ float BKE_mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart, else { int i; MLoop *l_iter = loopstart; - float area, polynorm_local[3], (*vertexcos)[3]; + float area, polynorm_local[3]; + float (*vertexcos)[3] = BLI_array_alloca(vertexcos, mpoly->totloop); const float *no = polynormal ? polynormal : polynorm_local; - BLI_array_fixedstack_declare(vertexcos, BM_DEFAULT_NGON_STACK_SIZE, mpoly->totloop, __func__); /* pack vertex cos into an array for area_poly_v3 */ for (i = 0; i < mpoly->totloop; i++, l_iter++) { @@ -3026,8 +3025,6 @@ float BKE_mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart, /* finally calculate the area */ area = area_poly_v3(mpoly->totloop, vertexcos, no); - BLI_array_fixedstack_free(vertexcos); - return area; } } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 25b70ce1793..2aeda614f07 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -621,16 +621,6 @@ int modifiers_isPreview(Object *ob) return FALSE; } -int modifiers_indexInObject(Object *ob, ModifierData *md_seek) -{ - int i = 0; - ModifierData *md; - - for (md = ob->modifiers.first; (md && md_seek != md); md = md->next, i++) ; - if (!md) return -1; /* modifier isn't in the object */ - return i; -} - void modifier_freeTemporaryData(ModifierData *md) { if (md->type == eModifierType_Armature) { diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 381e4350391..7df7561a1a1 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -40,7 +40,11 @@ #include "BKE_bmesh.h" #include "BKE_tessmesh.h" -/* main function for copying DerivedMesh data into BMesh */ +/** + * The main function for copying DerivedMesh data into BMesh. + * + * \note The mesh may already have geometry. see 'is_init' + */ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) { MVert *mv, *mvert; @@ -56,6 +60,14 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) BLI_array_declare(edges); int i, j, k, totvert, totedge /* , totface */ /* UNUSED */ ; int is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0); + char has_orig_hflag = 0; + + if (is_init == FALSE) { + /* check if we have an origflag */ + has_orig_hflag |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0; + has_orig_hflag |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0; + has_orig_hflag |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0; + } /*merge custom data layout*/ CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT); @@ -85,10 +97,15 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) BM_elem_index_set(v, i); /* set_inline */ CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data); + vtable[i] = v; /* add bevel weight */ BM_elem_float_data_set(&bm->vdata, v, CD_BWEIGHT, (float)mv->bweight / 255.0f); - vtable[i] = v; + + if (UNLIKELY(has_orig_hflag & BM_VERT)) { + int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX); + *orig_index = ORIGINDEX_NONE; + } } MEM_freeN(mvert); if (is_init) bm->elem_index_dirty &= ~BM_VERT; @@ -109,6 +126,11 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (float)me->crease / 255.0f); /* add bevel weight */ BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (float)me->bweight / 255.0f); + + if (UNLIKELY(has_orig_hflag & BM_EDGE)) { + int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX); + *orig_index = ORIGINDEX_NONE; + } } MEM_freeN(medge); if (is_init) bm->elem_index_dirty &= ~BM_EDGE; @@ -158,6 +180,11 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm) else { BM_face_normal_update(f); } + + if (UNLIKELY(has_orig_hflag & BM_FACE)) { + int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX); + *orig_index = ORIGINDEX_NONE; + } } if (is_init) bm->elem_index_dirty &= ~BM_FACE; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index c737dccc5d2..06d7cf55d49 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -43,9 +43,9 @@ #include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_pbvh.h" #include "BLI_utildefines.h" +#include "BKE_pbvh.h" #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 9ea1c3e8c74..bf4e32ef122 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -57,14 +57,14 @@ #include "DNA_view3d_types.h" #include "DNA_world_types.h" #include "DNA_object_types.h" +#include "DNA_property_types.h" #include "BLI_blenlib.h" -#include "BLI_bpath.h" #include "BLI_math.h" -#include "BLI_pbvh.h" #include "BLI_utildefines.h" #include "BLI_linklist.h" +#include "BKE_pbvh.h" #include "BKE_main.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -739,6 +739,50 @@ void BKE_object_unlink(Object *ob) } } +/* actual check for internal data, not context or flags */ +int BKE_object_is_in_editmode(Object *ob) +{ + if (ob->data == NULL) + return 0; + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + if (me->edit_btmesh) + return 1; + } + else if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; + + if (arm->edbo) + return 1; + } + else if (ob->type == OB_FONT) { + Curve *cu = ob->data; + + if (cu->editfont) + return 1; + } + else if (ob->type == OB_MBALL) { + MetaBall *mb = ob->data; + + if (mb->editelems) + return 1; + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = ob->data; + + if (lt->editlatt) + return 1; + } + else if (ob->type == OB_SURF || ob->type == OB_CURVE) { + Curve *cu = ob->data; + + if (cu->editnurb) + return 1; + } + return 0; +} + int BKE_object_exists_check(Object *obtest) { Object *ob; @@ -1498,14 +1542,14 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) /* *************** CALC ****************** */ -void BKE_object_scale_to_mat3(Object *ob, float mat[][3]) +void BKE_object_scale_to_mat3(Object *ob, float mat[3][3]) { float vec[3]; mul_v3_v3v3(vec, ob->size, ob->dscale); size_to_mat3(mat, vec); } -void BKE_object_rot_to_mat3(Object *ob, float mat[][3]) +void BKE_object_rot_to_mat3(Object *ob, float mat[3][3], short use_drot) { float rmat[3][3], dmat[3][3]; @@ -1536,10 +1580,13 @@ void BKE_object_rot_to_mat3(Object *ob, float mat[][3]) } /* combine these rotations */ - mul_m3_m3m3(mat, dmat, rmat); + if (use_drot) + mul_m3_m3m3(mat, dmat, rmat); + else + copy_m3_m3(mat, rmat); } -void BKE_object_mat3_to_rot(Object *ob, float mat[][3], short use_compat) +void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], short use_compat) { switch (ob->rotmode) { case ROT_MODE_QUAT: @@ -1642,7 +1689,7 @@ void BKE_object_tfm_protected_restore(Object *ob, } /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */ -void BKE_object_apply_mat4(Object *ob, float mat[][4], const short use_compat, const short use_parent) +void BKE_object_apply_mat4(Object *ob, float mat[4][4], const short use_compat, const short use_parent) { float rot[3][3]; @@ -1671,7 +1718,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[][4], const short use_compat, c /* BKE_object_mat3_to_rot handles delta rotations */ } -void BKE_object_to_mat3(Object *ob, float mat[][3]) /* no parent */ +void BKE_object_to_mat3(Object *ob, float mat[3][3]) /* no parent */ { float smat[3][3]; float rmat[3][3]; @@ -1681,11 +1728,11 @@ void BKE_object_to_mat3(Object *ob, float mat[][3]) /* no parent */ BKE_object_scale_to_mat3(ob, smat); /* rot */ - BKE_object_rot_to_mat3(ob, rmat); + BKE_object_rot_to_mat3(ob, rmat, TRUE); mul_m3_m3m3(mat, rmat, smat); } -void BKE_object_to_mat4(Object *ob, float mat[][4]) +void BKE_object_to_mat4(Object *ob, float mat[4][4]) { float tmat[3][3]; @@ -1699,7 +1746,7 @@ void BKE_object_to_mat4(Object *ob, float mat[][4]) /* extern */ int enable_cu_speed = 1; -static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4]) +static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) { Curve *cu; float vec[4], dir[3], quat[4], radius, ctime; @@ -1783,7 +1830,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4]) } } -static void ob_parbone(Object *ob, Object *par, float mat[][4]) +static void ob_parbone(Object *ob, Object *par, float mat[4][4]) { bPoseChannel *pchan; float vec[3]; @@ -1913,7 +1960,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) } } -static void ob_parvert3(Object *ob, Object *par, float mat[][4]) +static void ob_parvert3(Object *ob, Object *par, float mat[4][4]) { float cmat[3][3], v1[3], v2[3], v3[3], q[4]; @@ -1941,7 +1988,7 @@ static void ob_parvert3(Object *ob, Object *par, float mat[][4]) } } -static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul) +static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4], int simul) { float totmat[4][4]; float tmat[4][4]; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 5f5a713064d..b2851962b49 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -55,7 +55,6 @@ #include "BLI_rand.h" #include "BLI_threads.h" #include "BLI_linklist.h" -#include "BLI_bpath.h" #include "BKE_anim.h" #include "BKE_animsys.h" @@ -680,7 +679,7 @@ static float psys_render_projected_area(ParticleSystem *psys, const float center return area; } -void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy, int timeoffset) +void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset) { ParticleRenderData *data; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); @@ -1919,7 +1918,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in /* Path Cache */ /************************************************/ -static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[][4], int smooth_start) +static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start) { float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f}; float t, dt = 1.f, result[3]; @@ -3351,7 +3350,7 @@ static void key_from_object(Object *ob, ParticleKey *key) } #endif -static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[][4]) +static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[4][4]) { float det, w1, w2, d1[2], d2[2]; @@ -3392,7 +3391,7 @@ static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat cross_v3_v3v3(mat[0], mat[1], mat[2]); } -static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float mat[][4], int orco) +static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float mat[4][4], int orco) { float v[3][3]; MFace *mface; @@ -3425,7 +3424,7 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat); } -void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4]) +void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4]) { float vec[3]; @@ -3440,7 +3439,7 @@ void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, Pa copy_v3_v3(hairmat[3], vec); } -void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4]) +void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4]) { float vec[3], orco[3]; @@ -3462,7 +3461,7 @@ void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float vec[3]) mul_mat3_m4_v3(mat, vec); } -void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4]) +void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4]) { float facemat[4][4]; @@ -4502,7 +4501,7 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco, 0); } -void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale) +void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[4][4], float *scale) { Object *ob = sim->ob; ParticleSystem *psys = sim->psys; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 90889d7c09e..090082b333d 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -23,7 +23,8 @@ * Contributor(s): Raul Fernandez Hernandez (Farsthary), Stephen Swhitehorn. * * Adaptive time step - * Copyright 2011 AutoCRC + * Classical SPH + * Copyright 2011-2012 AutoCRC * * ***** END GPL LICENSE BLOCK ***** */ @@ -1889,7 +1890,6 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, bpa->data.acc[0]=bpa->data.acc[1]=bpa->data.acc[2]=0.0f; } - if (part->type == PART_HAIR) { pa->lifetime = 100.0f; } @@ -2390,33 +2390,36 @@ typedef struct SPHRangeData { SPHNeighbor neighbors[SPH_NEIGHBORS]; int tot_neighbors; - float density, near_density; - float h; + float* data; ParticleSystem *npsys; ParticleData *pa; + float h; float massfac; int use_size; } SPHRangeData; -typedef struct SPHData { - ParticleSystem *psys[10]; - ParticleData *pa; - float mass; - EdgeHash *eh; - float *gravity; - /* Average distance to neighbors (other particles in the support domain), - * for calculating the Courant number (adaptive time step). */ - int pass; - float element_size; - float flow[3]; - - /* Integrator callbacks. This allows different SPH implementations. */ - void (*force_cb) (void *sphdata_v, ParticleKey *state, float *force, float *impulse); - void (*density_cb) (void *rangedata_v, int index, float squared_dist); -} SPHData; +static void sph_evaluate_func(BVHTree *tree, ParticleSystem **psys, float co[3], SPHRangeData *pfr, float interaction_radius, BVHTree_RangeQuery callback) +{ + int i; + + pfr->tot_neighbors = 0; + + for (i=0; i < 10 && psys[i]; i++) { + pfr->npsys = psys[i]; + pfr->massfac = psys[i]->part->mass; + pfr->use_size = psys[i]->part->flag & PART_SIZEMASS; + if (tree) { + BLI_bvhtree_range_query(tree, co, interaction_radius, callback, pfr); + break; + } + else { + BLI_bvhtree_range_query(psys[i]->bvhtree, co, interaction_radius, callback, pfr); + } + } +} static void sph_density_accum_cb(void *userdata, int index, float squared_dist) { SPHRangeData *pfr = (SPHRangeData *)userdata; @@ -2446,8 +2449,8 @@ static void sph_density_accum_cb(void *userdata, int index, float squared_dist) if (pfr->use_size) q *= npa->size; - pfr->density += q*q; - pfr->near_density += q*q*q; + pfr->data[0] += q*q; + pfr->data[1] += q*q*q; } /* @@ -2500,8 +2503,10 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa float inv_mass = 1.0f/mass; float spring_constant = fluid->spring_k; - - float h = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.f*pa->size : 1.f); /* 4.0 seems to be a pretty good value */ + + /* 4.0 seems to be a pretty good value */ + float interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f); + float h = interaction_radius * sphdata->hfac; float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.f); /* 4.77 is an experimentally determined density factor */ float rest_length = fluid->rest_length * (fluid->flag & SPH_FAC_REST_LENGTH ? 2.588f * pa->size : 1.f); @@ -2512,24 +2517,23 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa float vec[3]; float vel[3]; float co[3]; + float data[2]; + float density, near_density; int i, spring_index, index = pa - psys[0]->particles; - pfr.tot_neighbors = 0; - pfr.density = pfr.near_density = 0.f; + data[0] = data[1] = 0; + pfr.data = data; pfr.h = h; pfr.pa = pa; - for (i=0; i<10 && psys[i]; i++) { - pfr.npsys = psys[i]; - pfr.massfac = psys[i]->part->mass*inv_mass; - pfr.use_size = psys[i]->part->flag & PART_SIZEMASS; + sph_evaluate_func( NULL, psys, state->co, &pfr, interaction_radius, sph_density_accum_cb); - BLI_bvhtree_range_query(psys[i]->bvhtree, state->co, h, sphdata->density_cb, &pfr); - } + density = data[0]; + near_density = data[1]; - pressure = stiffness * (pfr.density - rest_density); - near_pressure = stiffness_near_fac * pfr.near_density; + pressure = stiffness * (density - rest_density); + near_pressure = stiffness_near_fac * near_density; pfn = pfr.neighbors; for (i=0; i<pfr.tot_neighbors; i++, pfn++) { @@ -2593,14 +2597,207 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa /* Artificial buoyancy force in negative gravity direction */ if (fluid->buoyancy > 0.f && gravity) - madd_v3_v3fl(force, gravity, fluid->buoyancy * (pfr.density-rest_density)); + madd_v3_v3fl(force, gravity, fluid->buoyancy * (density-rest_density)); if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF) sph_particle_courant(sphdata, &pfr); sphdata->pass++; } -static void sph_solver_init(ParticleSimulationData *sim, SPHData *sphdata) +/* powf is really slow for raising to integer powers. */ +MINLINE float pow2(float x) +{ + return x * x; +} +MINLINE float pow3(float x) +{ + return pow2(x) * x; +} +MINLINE float pow4(float x) +{ + return pow2(pow2(x)); +} +MINLINE float pow7(float x) +{ + return pow2(pow3(x)) * x; +} + +static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSED(squared_dist)) +{ + SPHRangeData *pfr = (SPHRangeData *)userdata; + ParticleData *npa = pfr->npsys->particles + index; + float q; + float qfac = 21.0f / (256.f * (float)M_PI); + float rij, rij_h; + float vec[3]; + + /* Exclude particles that are more than 2h away. Can't use squared_dist here + * because it is not accurate enough. Use current state, i.e. the output of + * basic_integrate() - z0r */ + sub_v3_v3v3(vec, npa->state.co, pfr->pa->state.co); + rij = len_v3(vec); + rij_h = rij / pfr->h; + if (rij_h > 2.0f) + return; + + /* Smoothing factor. Utilise the Wendland kernel. gnuplot: + * q1(x) = (2.0 - x)**4 * ( 1.0 + 2.0 * x) + * plot [0:2] q1(x) */ + q = qfac / pow3(pfr->h) * pow4(2.0f - rij_h) * ( 1.0f + 2.0f * rij_h); + q *= pfr->massfac; + + if (pfr->use_size) + q *= pfr->pa->size; + + pfr->data[0] += q; + pfr->data[1] += q / npa->sphdensity; +} + +static void sphclassical_neighbour_accum_cb(void *userdata, int index, float UNUSED(squared_dist)) +{ + SPHRangeData *pfr = (SPHRangeData *)userdata; + ParticleData *npa = pfr->npsys->particles + index; + float rij, rij_h; + float vec[3]; + + if (pfr->tot_neighbors >= SPH_NEIGHBORS) + return; + + /* Exclude particles that are more than 2h away. Can't use squared_dist here + * because it is not accurate enough. Use current state, i.e. the output of + * basic_integrate() - z0r */ + sub_v3_v3v3(vec, npa->state.co, pfr->pa->state.co); + rij = len_v3(vec); + rij_h = rij / pfr->h; + if (rij_h > 2.0f) + return; + + pfr->neighbors[pfr->tot_neighbors].index = index; + pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys; + pfr->tot_neighbors++; +} +static void sphclassical_force_cb(void *sphdata_v, ParticleKey *state, float *force, float *UNUSED(impulse)) +{ + SPHData *sphdata = (SPHData *)sphdata_v; + ParticleSystem **psys = sphdata->psys; + ParticleData *pa = sphdata->pa; + SPHFluidSettings *fluid = psys[0]->part->fluid; + SPHRangeData pfr; + SPHNeighbor *pfn; + float *gravity = sphdata->gravity; + + float dq, u, rij, dv[3]; + float pressure, npressure; + + float visc = fluid->viscosity_omega; + + float interaction_radius; + float h, hinv; + /* 4.77 is an experimentally determined density factor */ + float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.0f); + + float stiffness = fluid->stiffness_k; + + ParticleData *npa; + float vec[3]; + float co[3]; + float pressureTerm; + + int i; + + float qfac2 = 42.0f / (256.0f * (float)M_PI); + float rij_h; + + /* 4.0 here is to be consistent with previous formulation/interface */ + interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f); + h = interaction_radius * sphdata->hfac; + hinv = 1.0f / h; + + pfr.h = h; + pfr.pa = pa; + + sph_evaluate_func(NULL, psys, state->co, &pfr, interaction_radius, sphclassical_neighbour_accum_cb); + pressure = stiffness * (pow7(pa->sphdensity / rest_density) - 1.0f); + + /* multiply by mass so that we return a force, not accel */ + qfac2 *= sphdata->mass / pow3(pfr.h); + + pfn = pfr.neighbors; + for (i = 0; i < pfr.tot_neighbors; i++, pfn++) { + npa = pfn->psys->particles + pfn->index; + if (npa == pa) { + /* we do not contribute to ourselves */ + continue; + } + + /* Find vector to neighbour. Exclude particles that are more than 2h + * away. Can't use current state here because it may have changed on + * another thread - so do own mini integration. Unlike basic_integrate, + * SPH integration depends on neighbouring particles. - z0r */ + madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time); + sub_v3_v3v3(vec, co, state->co); + rij = normalize_v3(vec); + rij_h = rij / pfr.h; + if (rij_h > 2.0f) + continue; + + npressure = stiffness * (pow7(npa->sphdensity / rest_density) - 1.0f); + + /* First derivative of smoothing factor. Utilise the Wendland kernel. + * gnuplot: + * q2(x) = 2.0 * (2.0 - x)**4 - 4.0 * (2.0 - x)**3 * (1.0 + 2.0 * x) + * plot [0:2] q2(x) + * Particles > 2h away are excluded above. */ + dq = qfac2 * (2.0f * pow4(2.0f - rij_h) - 4.0f * pow3(2.0f - rij_h) * (1.0f + 2.0f * rij_h) ); + + if (pfn->psys->part->flag & PART_SIZEMASS) + dq *= npa->size; + + pressureTerm = pressure / pow2(pa->sphdensity) + npressure / pow2(npa->sphdensity); + + /* Note that 'minus' is removed, because vec = vecBA, not vecAB. + * This applies to the viscosity calculation below, too. */ + madd_v3_v3fl(force, vec, pressureTerm * dq); + + /* Viscosity */ + if (visc > 0.0f) { + sub_v3_v3v3(dv, npa->prev_state.vel, pa->prev_state.vel); + u = dot_v3v3(vec, dv); + /* Apply parameters */ + u *= -dq * hinv * visc / (0.5f * npa->sphdensity + 0.5f * pa->sphdensity); + madd_v3_v3fl(force, vec, u); + } + } + + /* Artificial buoyancy force in negative gravity direction */ + if (fluid->buoyancy > 0.f && gravity) + madd_v3_v3fl(force, gravity, fluid->buoyancy * (pa->sphdensity - rest_density)); + + if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF) + sph_particle_courant(sphdata, &pfr); + sphdata->pass++; +} + +static void sphclassical_calc_dens(ParticleData *pa, float UNUSED(dfra), SPHData *sphdata) +{ + ParticleSystem **psys = sphdata->psys; + SPHFluidSettings *fluid = psys[0]->part->fluid; + /* 4.0 seems to be a pretty good value */ + float interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f); + SPHRangeData pfr; + float data[2]; + + data[0] = 0; + data[1] = 0; + pfr.data = data; + pfr.h = interaction_radius * sphdata->hfac; + pfr.pa = pa; + + sph_evaluate_func( NULL, psys, pa->state.co, &pfr, interaction_radius, sphclassical_density_accum_cb); + pa->sphdensity = MIN2(MAX2(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f); +} + +void psys_sph_init(ParticleSimulationData *sim, SPHData *sphdata) { ParticleTarget *pt; int i; @@ -2621,17 +2818,46 @@ static void sph_solver_init(ParticleSimulationData *sim, SPHData *sphdata) sphdata->pa = NULL; sphdata->mass = 1.0f; - sphdata->force_cb = sph_force_cb; - sphdata->density_cb = sph_density_accum_cb; + if (sim->psys->part->fluid->solver == SPH_SOLVER_DDR) { + sphdata->force_cb = sph_force_cb; + sphdata->density_cb = sph_density_accum_cb; + sphdata->hfac = 1.0f; + } + else { + /* SPH_SOLVER_CLASSICAL */ + sphdata->force_cb = sphclassical_force_cb; + sphdata->density_cb = sphclassical_density_accum_cb; + sphdata->hfac = 0.5f; + } + } -static void sph_solver_finalise(SPHData *sphdata) +void psys_sph_finalise(SPHData *sphdata) { if (sphdata->eh) { BLI_edgehash_free(sphdata->eh, NULL); sphdata->eh = NULL; } } +/* Sample the density field at a point in space. */ +void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2]) +{ + ParticleSystem **psys = sphdata->psys; + SPHFluidSettings *fluid = psys[0]->part->fluid; + /* 4.0 seems to be a pretty good value */ + float interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f); + SPHRangeData pfr; + float density[2]; + + density[0] = density[1] = 0.0f; + pfr.data = density; + pfr.h = interaction_radius*sphdata->hfac; + + sph_evaluate_func(tree, psys, co, &pfr, interaction_radius, sphdata->density_cb); + + vars[0] = pfr.data[0]; + vars[1] = pfr.data[1]; +} static void sph_integrate(ParticleSimulationData *sim, ParticleData *pa, float dfra, SPHData *sphdata) { @@ -3781,18 +4007,19 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) /* Code for an adaptive time step based on the Courant-Friedrichs-Lewy * condition. */ -#define MIN_TIMESTEP 1.0f / 101.0f +static const float MIN_TIMESTEP = 1.0f / 101.0f; /* Tolerance of 1.5 means the last subframe neither favors growing nor * shrinking (e.g if it were 1.3, the last subframe would tend to be too * small). */ -#define TIMESTEP_EXPANSION_TOLERANCE 1.5f +static const float TIMESTEP_EXPANSION_FACTOR = 0.1f; +static const float TIMESTEP_EXPANSION_TOLERANCE = 1.5f; /* Calculate the speed of the particle relative to the local scale of the * simulation. This should be called once per particle during a simulation * step, after the velocity has been updated. element_size defines the scale of * the simulation, and is typically the distance to neighboring particles. */ static void update_courant_num(ParticleSimulationData *sim, ParticleData *pa, - float dtime, SPHData *sphdata) + float dtime, SPHData *sphdata) { float relative_vel[3]; float speed; @@ -3802,14 +4029,31 @@ static void update_courant_num(ParticleSimulationData *sim, ParticleData *pa, if (sim->courant_num < speed * dtime / sphdata->element_size) sim->courant_num = speed * dtime / sphdata->element_size; } +static float get_base_time_step(ParticleSettings *part) +{ + return 1.0f / (float) (part->subframes + 1); +} /* Update time step size to suit current conditions. */ static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim, float t_frac) { + float dt_target; if (sim->courant_num == 0.0f) - psys->dt_frac = 1.0f; + dt_target = 1.0f; + else + dt_target = psys->dt_frac * (psys->part->courant_target / sim->courant_num); + + /* Make sure the time step is reasonable. For some reason, the CLAMP macro + * doesn't work here. The time step becomes too large. - z0r */ + if (dt_target < MIN_TIMESTEP) + dt_target = MIN_TIMESTEP; + else if (dt_target > get_base_time_step(psys->part)) + dt_target = get_base_time_step(psys->part); + + /* Decrease time step instantly, but increase slowly. */ + if (dt_target > psys->dt_frac) + psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR); else - psys->dt_frac *= (psys->part->courant_target / sim->courant_num); - CLAMP(psys->dt_frac, MIN_TIMESTEP, 1.0f); + psys->dt_frac = dt_target; /* Sync with frame end if it's close. */ if (t_frac == 1.0f) @@ -3973,31 +4217,72 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) case PART_PHYS_FLUID: { SPHData sphdata; - sph_solver_init(sim, &sphdata); + ParticleSettings *part = sim->psys->part; + psys_sph_init(sim, &sphdata); - #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) - LOOP_DYNAMIC_PARTICLES { - /* do global forces & effectors */ - basic_integrate(sim, p, pa->state.time, cfra); + if (part->fluid->flag & SPH_SOLVER_DDR) { + /* Apply SPH forces using double-density relaxation algorithm + * (Clavat et. al.) */ + #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) + LOOP_DYNAMIC_PARTICLES { + /* do global forces & effectors */ + basic_integrate(sim, p, pa->state.time, cfra); - /* actual fluids calculations */ - sph_integrate(sim, pa, pa->state.time, &sphdata); + /* actual fluids calculations */ + sph_integrate(sim, pa, pa->state.time, &sphdata); - if (sim->colliders) - collision_check(sim, p, pa->state.time, cfra); - - /* SPH particles are not physical particles, just interpolation - * particles, thus rotation has not a direct sense for them */ - basic_rotate(part, pa, pa->state.time, timestep); + if (sim->colliders) + collision_check(sim, p, pa->state.time, cfra); + + /* SPH particles are not physical particles, just interpolation + * particles, thus rotation has not a direct sense for them */ + basic_rotate(part, pa, pa->state.time, timestep); + + #pragma omp critical + if (part->time_flag & PART_TIME_AUTOSF) + update_courant_num(sim, pa, dtime, &sphdata); + } + + sph_springs_modify(psys, timestep); - #pragma omp critical - if (part->time_flag & PART_TIME_AUTOSF) - update_courant_num(sim, pa, dtime, &sphdata); } + else { + /* SPH_SOLVER_CLASSICAL */ + /* Apply SPH forces using classical algorithm (due to Gingold + * and Monaghan). Note that, unlike double-density relaxation, + * this algorthim is separated into distinct loops. */ + + #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) + LOOP_DYNAMIC_PARTICLES { + basic_integrate(sim, p, pa->state.time, cfra); + } + + /* calculate summation density */ + #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) + LOOP_DYNAMIC_PARTICLES { + sphclassical_calc_dens(pa, pa->state.time, &sphdata); + } + + /* do global forces & effectors */ + #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) + LOOP_DYNAMIC_PARTICLES { + /* actual fluids calculations */ + sph_integrate(sim, pa, pa->state.time, &sphdata); + + if (sim->colliders) + collision_check(sim, p, pa->state.time, cfra); + + /* SPH particles are not physical particles, just interpolation + * particles, thus rotation has not a direct sense for them */ + basic_rotate(part, pa, pa->state.time, timestep); - sph_springs_modify(psys, timestep); + #pragma omp critical + if (part->time_flag & PART_TIME_AUTOSF) + update_courant_num(sim, pa, dtime, &sphdata); + } + } - sph_solver_finalise(&sphdata); + psys_sph_finalise(&sphdata); break; } } @@ -4309,14 +4594,14 @@ static void system_step(ParticleSimulationData *sim, float cfra) if (!(part->time_flag & PART_TIME_AUTOSF)) { /* Constant time step */ - psys->dt_frac = 1.0f / (float) (part->subframes + 1); + psys->dt_frac = get_base_time_step(part); } else if ((int)cfra == startframe) { - /* Variable time step; use a very conservative value at the start. - * If it doesn't need to be so small, it will quickly grow. */ - psys->dt_frac = 1.0; + /* Variable time step; initialise to subframes */ + psys->dt_frac = get_base_time_step(part); } else if (psys->dt_frac < MIN_TIMESTEP) { + /* Variable time step; subsequent frames */ psys->dt_frac = MIN_TIMESTEP; } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c new file mode 100644 index 00000000000..3a4e8afca76 --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh.c @@ -0,0 +1,1909 @@ +/* + * ***** 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/blenlib/intern/pbvh.c + * \ingroup bli + */ + +#include "DNA_meshdata_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "BKE_pbvh.h" +#include "BKE_ccg.h" +#include "BKE_DerivedMesh.h" +#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */ +#include "BKE_global.h" /* for BKE_mesh_calc_normals */ +#include "BKE_paint.h" +#include "BKE_subsurf.h" + +#include "GPU_buffers.h" + +#define LEAF_LIMIT 10000 + +//#define PERFCNTRS + +/* Axis-aligned bounding box */ +typedef struct { + float bmin[3], bmax[3]; +} BB; + +/* Axis-aligned bounding box with centroid */ +typedef struct { + float bmin[3], bmax[3], bcentroid[3]; +} BBC; + +struct PBVHNode { + /* Opaque handle for drawing code */ + GPU_Buffers *draw_buffers; + + /* Voxel bounds */ + BB vb; + BB orig_vb; + + /* For internal nodes, the offset of the children in the PBVH + * 'nodes' array. */ + int children_offset; + + /* Pointer into the PBVH prim_indices array and the number of + * primitives used by this leaf node. + * + * Used for leaf nodes in both mesh- and multires-based PBVHs. + */ + int *prim_indices; + unsigned int totprim; + + /* Array of indices into the mesh's MVert array. Contains the + * indices of all vertices used by faces that are within this + * node's bounding box. + * + * Note that a vertex might be used by a multiple faces, and + * these faces might be in different leaf nodes. Such a vertex + * will appear in the vert_indices array of each of those leaf + * nodes. + * + * In order to support cases where you want access to multiple + * nodes' vertices without duplication, the vert_indices array + * is ordered such that the first part of the array, up to + * index 'uniq_verts', contains "unique" vertex indices. These + * vertices might not be truly unique to this node, but if + * they appear in another node's vert_indices array, they will + * be above that node's 'uniq_verts' value. + * + * Used for leaf nodes in a mesh-based PBVH (not multires.) + */ + int *vert_indices; + unsigned int uniq_verts, face_verts; + + /* An array mapping face corners into the vert_indices + * array. The array is sized to match 'totprim', and each of + * the face's corners gets an index into the vert_indices + * array, in the same order as the corners in the original + * MFace. The fourth value should not be used if the original + * face is a triangle. + * + * Used for leaf nodes in a mesh-based PBVH (not multires.) + */ + int (*face_vert_indices)[4]; + + /* Indicates whether this node is a leaf or not; also used for + * marking various updates that need to be applied. */ + PBVHNodeFlags flag : 8; + + /* Used for raycasting: how close bb is to the ray point. */ + float tmin; + + int proxy_count; + PBVHProxyNode *proxies; +}; + +struct PBVH { + PBVHType type; + + PBVHNode *nodes; + int node_mem_count, totnode; + + int *prim_indices; + int totprim; + int totvert; + + int leaf_limit; + + /* Mesh data */ + MVert *verts; + MFace *faces; + CustomData *vdata; + + /* Grid Data */ + CCGKey gridkey; + CCGElem **grids; + DMGridAdjacency *gridadj; + void **gridfaces; + const DMFlagMat *grid_flag_mats; + int totgrid; + BLI_bitmap *grid_hidden; + + /* Only used during BVH build and update, + * don't need to remain valid after */ + BLI_bitmap vert_bitmap; + +#ifdef PERFCNTRS + int perf_modified; +#endif + + /* flag are verts/faces deformed */ + int deformed; + + int show_diffuse_color; +}; + +#define STACK_FIXED_DEPTH 100 + +typedef struct PBVHStack { + PBVHNode *node; + int revisiting; +} PBVHStack; + +typedef struct PBVHIter { + PBVH *bvh; + BLI_pbvh_SearchCallback scb; + void *search_data; + + PBVHStack *stack; + int stacksize; + + PBVHStack stackfixed[STACK_FIXED_DEPTH]; + int stackspace; +} PBVHIter; + +static void BB_reset(BB *bb) +{ + bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX; + bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX; +} + +/* Expand the bounding box to include a new coordinate */ +static void BB_expand(BB *bb, float co[3]) +{ + int i; + for (i = 0; i < 3; ++i) { + bb->bmin[i] = min_ff(bb->bmin[i], co[i]); + bb->bmax[i] = max_ff(bb->bmax[i], co[i]); + } +} + +/* Expand the bounding box to include another bounding box */ +static void BB_expand_with_bb(BB *bb, BB *bb2) +{ + int i; + for (i = 0; i < 3; ++i) { + bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]); + bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]); + } +} + +/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */ +static int BB_widest_axis(BB *bb) +{ + float dim[3]; + int i; + + for (i = 0; i < 3; ++i) + dim[i] = bb->bmax[i] - bb->bmin[i]; + + if (dim[0] > dim[1]) { + if (dim[0] > dim[2]) + return 0; + else + return 2; + } + else { + if (dim[1] > dim[2]) + return 1; + else + return 2; + } +} + +static void BBC_update_centroid(BBC *bbc) +{ + int i; + for (i = 0; i < 3; ++i) + bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f; +} + +/* Not recursive */ +static void update_node_vb(PBVH *bvh, PBVHNode *node) +{ + BB vb; + + BB_reset(&vb); + + if (node->flag & PBVH_Leaf) { + PBVHVertexIter vd; + + BLI_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) + { + BB_expand(&vb, vd.co); + } + BLI_pbvh_vertex_iter_end; + } + else { + BB_expand_with_bb(&vb, + &bvh->nodes[node->children_offset].vb); + BB_expand_with_bb(&vb, + &bvh->nodes[node->children_offset + 1].vb); + } + + node->vb = vb; +} + +//void BLI_pbvh_node_BB_reset(PBVHNode *node) +//{ +// BB_reset(&node->vb); +//} +// +//void BLI_pbvh_node_BB_expand(PBVHNode *node, float co[3]) +//{ +// BB_expand(&node->vb, co); +//} + +static int face_materials_match(const MFace *f1, const MFace *f2) +{ + return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && + (f1->mat_nr == f2->mat_nr)); +} + +static int grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) +{ + return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && + (f1->mat_nr == f2->mat_nr)); +} + +/* Adapted from BLI_kdopbvh.c */ +/* Returns the index of the first element on the right of the partition */ +static int partition_indices(int *prim_indices, int lo, int hi, int axis, + float mid, BBC *prim_bbc) +{ + int i = lo, j = hi; + for (;; ) { + for (; prim_bbc[prim_indices[i]].bcentroid[axis] < mid; i++) ; + for (; mid < prim_bbc[prim_indices[j]].bcentroid[axis]; j--) ; + + if (!(i < j)) + return i; + + SWAP(int, prim_indices[i], prim_indices[j]); + i++; + } +} + +/* Returns the index of the first element on the right of the partition */ +static int partition_indices_material(PBVH *bvh, int lo, int hi) +{ + const MFace *faces = bvh->faces; + const DMFlagMat *flagmats = bvh->grid_flag_mats; + const int *indices = bvh->prim_indices; + const void *first; + int i = lo, j = hi; + + if (bvh->faces) + first = &faces[bvh->prim_indices[lo]]; + else + first = &flagmats[bvh->prim_indices[lo]]; + + for (;; ) { + if (bvh->faces) { + for (; face_materials_match(first, &faces[indices[i]]); i++) ; + for (; !face_materials_match(first, &faces[indices[j]]); j--) ; + } + else { + for (; grid_materials_match(first, &flagmats[indices[i]]); i++) ; + for (; !grid_materials_match(first, &flagmats[indices[j]]); j--) ; + } + + if (!(i < j)) + return i; + + SWAP(int, bvh->prim_indices[i], bvh->prim_indices[j]); + i++; + } +} + +static void grow_nodes(PBVH *bvh, int totnode) +{ + if (totnode > bvh->node_mem_count) { + PBVHNode *prev = bvh->nodes; + bvh->node_mem_count *= 1.33; + if (bvh->node_mem_count < totnode) + bvh->node_mem_count = totnode; + bvh->nodes = MEM_callocN(sizeof(PBVHNode) * bvh->node_mem_count, + "bvh nodes"); + memcpy(bvh->nodes, prev, bvh->totnode * sizeof(PBVHNode)); + MEM_freeN(prev); + } + + bvh->totnode = totnode; +} + +/* Add a vertex to the map, with a positive value for unique vertices and + * a negative value for additional vertices */ +static int map_insert_vert(PBVH *bvh, GHash *map, + unsigned int *face_verts, + unsigned int *uniq_verts, int vertex) +{ + void *value, *key = SET_INT_IN_POINTER(vertex); + + if (!BLI_ghash_haskey(map, key)) { + if (BLI_BITMAP_GET(bvh->vert_bitmap, vertex)) { + value = SET_INT_IN_POINTER(~(*face_verts)); + ++(*face_verts); + } + else { + BLI_BITMAP_SET(bvh->vert_bitmap, vertex); + value = SET_INT_IN_POINTER(*uniq_verts); + ++(*uniq_verts); + } + + BLI_ghash_insert(map, key, value); + return GET_INT_FROM_POINTER(value); + } + else + return GET_INT_FROM_POINTER(BLI_ghash_lookup(map, key)); +} + +/* Find vertices used by the faces in this node and update the draw buffers */ +static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) +{ + GHashIterator *iter; + GHash *map; + int i, j, totface; + + map = BLI_ghash_int_new("build_mesh_leaf_node gh"); + + node->uniq_verts = node->face_verts = 0; + totface = node->totprim; + + node->face_vert_indices = MEM_callocN(sizeof(int) * 4 * totface, + "bvh node face vert indices"); + + for (i = 0; i < totface; ++i) { + MFace *f = bvh->faces + node->prim_indices[i]; + int sides = f->v4 ? 4 : 3; + + for (j = 0; j < sides; ++j) { + node->face_vert_indices[i][j] = + map_insert_vert(bvh, map, &node->face_verts, + &node->uniq_verts, (&f->v1)[j]); + } + } + + node->vert_indices = MEM_callocN(sizeof(int) * + (node->uniq_verts + node->face_verts), + "bvh node vert indices"); + + /* Build the vertex list, unique verts first */ + for (iter = BLI_ghashIterator_new(map), i = 0; + BLI_ghashIterator_isDone(iter) == FALSE; + BLI_ghashIterator_step(iter), ++i) + { + void *value = BLI_ghashIterator_getValue(iter); + int ndx = GET_INT_FROM_POINTER(value); + + if (ndx < 0) + ndx = -ndx + node->uniq_verts - 1; + + node->vert_indices[ndx] = + GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(iter)); + } + + BLI_ghashIterator_free(iter); + + for (i = 0; i < totface; ++i) { + MFace *f = bvh->faces + node->prim_indices[i]; + int sides = f->v4 ? 4 : 3; + + for (j = 0; j < sides; ++j) { + if (node->face_vert_indices[i][j] < 0) + node->face_vert_indices[i][j] = + -node->face_vert_indices[i][j] + + node->uniq_verts - 1; + } + } + + if (!G.background) { + node->draw_buffers = + GPU_build_mesh_buffers(node->face_vert_indices, + bvh->faces, bvh->verts, + node->prim_indices, + node->totprim); + } + + node->flag |= PBVH_UpdateDrawBuffers; + + BLI_ghash_free(map, NULL, NULL); +} + +static void build_grids_leaf_node(PBVH *bvh, PBVHNode *node) +{ + if (!G.background) { + node->draw_buffers = + GPU_build_grid_buffers(node->prim_indices, + node->totprim, bvh->grid_hidden, bvh->gridkey.grid_size); + } + node->flag |= PBVH_UpdateDrawBuffers; +} + +static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, + int offset, int count) +{ + int i; + + BB_reset(&node->vb); + for (i = offset + count - 1; i >= offset; --i) { + BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]])); + } + node->orig_vb = node->vb; +} + +static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc, + int offset, int count) +{ + bvh->nodes[node_index].flag |= PBVH_Leaf; + + bvh->nodes[node_index].prim_indices = bvh->prim_indices + offset; + bvh->nodes[node_index].totprim = count; + + /* Still need vb for searches */ + update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count); + + if (bvh->faces) + build_mesh_leaf_node(bvh, bvh->nodes + node_index); + else + build_grids_leaf_node(bvh, bvh->nodes + node_index); +} + +/* Return zero if all primitives in the node can be drawn with the + * same material (including flat/smooth shading), non-zerootherwise */ +static int leaf_needs_material_split(PBVH *bvh, int offset, int count) +{ + int i, prim; + + if (count <= 1) + return 0; + + if (bvh->faces) { + const MFace *first = &bvh->faces[bvh->prim_indices[offset]]; + + for (i = offset + count - 1; i > offset; --i) { + prim = bvh->prim_indices[i]; + if (!face_materials_match(first, &bvh->faces[prim])) + return 1; + } + } + else { + const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]]; + + for (i = offset + count - 1; i > offset; --i) { + prim = bvh->prim_indices[i]; + if (!grid_materials_match(first, &bvh->grid_flag_mats[prim])) + return 1; + } + } + + return 0; +} + + +/* Recursively build a node in the tree + * + * vb is the voxel box around all of the primitives contained in + * this node. + * + * cb is the bounding box around all the centroids of the primitives + * contained in this node + * + * offset and start indicate a range in the array of primitive indices + */ + +static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, + int offset, int count) +{ + int i, axis, end, below_leaf_limit; + BB cb_backing; + + /* Decide whether this is a leaf or not */ + below_leaf_limit = count <= bvh->leaf_limit; + if (below_leaf_limit) { + if (!leaf_needs_material_split(bvh, offset, count)) { + build_leaf(bvh, node_index, prim_bbc, offset, count); + return; + } + } + + /* Add two child nodes */ + bvh->nodes[node_index].children_offset = bvh->totnode; + grow_nodes(bvh, bvh->totnode + 2); + + /* Update parent node bounding box */ + update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count); + + if (!below_leaf_limit) { + /* Find axis with widest range of primitive centroids */ + if (!cb) { + cb = &cb_backing; + BB_reset(cb); + for (i = offset + count - 1; i >= offset; --i) + BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid); + } + axis = BB_widest_axis(cb); + + /* Partition primitives along that axis */ + end = partition_indices(bvh->prim_indices, + offset, offset + count - 1, + axis, + (cb->bmax[axis] + cb->bmin[axis]) * 0.5f, + prim_bbc); + } + else { + /* Partition primitives by material */ + end = partition_indices_material(bvh, offset, offset + count - 1); + } + + /* Build children */ + build_sub(bvh, bvh->nodes[node_index].children_offset, NULL, + prim_bbc, offset, end - offset); + build_sub(bvh, bvh->nodes[node_index].children_offset + 1, NULL, + prim_bbc, end, offset + count - end); +} + +static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) +{ + int i; + + if (totprim != bvh->totprim) { + bvh->totprim = totprim; + if (bvh->nodes) MEM_freeN(bvh->nodes); + if (bvh->prim_indices) MEM_freeN(bvh->prim_indices); + bvh->prim_indices = MEM_callocN(sizeof(int) * totprim, + "bvh prim indices"); + for (i = 0; i < totprim; ++i) + bvh->prim_indices[i] = i; + bvh->totnode = 0; + if (bvh->node_mem_count < 100) { + bvh->node_mem_count = 100; + bvh->nodes = MEM_callocN(sizeof(PBVHNode) * + bvh->node_mem_count, + "bvh initial nodes"); + } + } + + bvh->totnode = 1; + build_sub(bvh, 0, cb, prim_bbc, 0, totprim); +} + +/* Do a full rebuild with on Mesh data structure */ +void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert, struct CustomData *vdata) +{ + BBC *prim_bbc = NULL; + BB cb; + int i, j; + + bvh->type = PBVH_FACES; + bvh->faces = faces; + bvh->verts = verts; + bvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap"); + bvh->totvert = totvert; + bvh->leaf_limit = LEAF_LIMIT; + bvh->vdata = vdata; + + BB_reset(&cb); + + /* For each face, store the AABB and the AABB centroid */ + prim_bbc = MEM_mallocN(sizeof(BBC) * totface, "prim_bbc"); + + for (i = 0; i < totface; ++i) { + MFace *f = faces + i; + const int sides = f->v4 ? 4 : 3; + BBC *bbc = prim_bbc + i; + + BB_reset((BB *)bbc); + + for (j = 0; j < sides; ++j) + BB_expand((BB *)bbc, verts[(&f->v1)[j]].co); + + BBC_update_centroid(bbc); + + BB_expand(&cb, bbc->bcentroid); + } + + if (totface) + pbvh_build(bvh, &cb, prim_bbc, totface); + + MEM_freeN(prim_bbc); + MEM_freeN(bvh->vert_bitmap); +} + +/* Do a full rebuild with on Grids data structure */ +void BLI_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, + int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap *grid_hidden) +{ + BBC *prim_bbc = NULL; + BB cb; + int gridsize = key->grid_size; + int i, j; + + bvh->type = PBVH_GRIDS; + bvh->grids = grids; + bvh->gridadj = gridadj; + bvh->gridfaces = gridfaces; + bvh->grid_flag_mats = flagmats; + bvh->totgrid = totgrid; + bvh->gridkey = *key; + bvh->grid_hidden = grid_hidden; + bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1); + + BB_reset(&cb); + + /* For each grid, store the AABB and the AABB centroid */ + prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc"); + + for (i = 0; i < totgrid; ++i) { + CCGElem *grid = grids[i]; + BBC *bbc = prim_bbc + i; + + BB_reset((BB *)bbc); + + for (j = 0; j < gridsize * gridsize; ++j) + BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j)); + + BBC_update_centroid(bbc); + + BB_expand(&cb, bbc->bcentroid); + } + + if (totgrid) + pbvh_build(bvh, &cb, prim_bbc, totgrid); + + MEM_freeN(prim_bbc); +} + +PBVH *BLI_pbvh_new(void) +{ + PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); + + return bvh; +} + +void BLI_pbvh_free(PBVH *bvh) +{ + PBVHNode *node; + int i; + + for (i = 0; i < bvh->totnode; ++i) { + node = &bvh->nodes[i]; + + if (node->flag & PBVH_Leaf) { + if (node->draw_buffers) + GPU_free_buffers(node->draw_buffers); + if (node->vert_indices) + MEM_freeN(node->vert_indices); + if (node->face_vert_indices) + MEM_freeN(node->face_vert_indices); + } + } + + if (bvh->deformed) { + if (bvh->verts) { + /* if pbvh was deformed, new memory was allocated for verts/faces -- free it */ + + MEM_freeN(bvh->verts); + if (bvh->faces) + MEM_freeN(bvh->faces); + } + } + + if (bvh->nodes) + MEM_freeN(bvh->nodes); + + if (bvh->prim_indices) + MEM_freeN(bvh->prim_indices); + + MEM_freeN(bvh); +} + +static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BLI_pbvh_SearchCallback scb, void *search_data) +{ + iter->bvh = bvh; + iter->scb = scb; + iter->search_data = search_data; + + iter->stack = iter->stackfixed; + iter->stackspace = STACK_FIXED_DEPTH; + + iter->stack[0].node = bvh->nodes; + iter->stack[0].revisiting = 0; + iter->stacksize = 1; +} + +static void pbvh_iter_end(PBVHIter *iter) +{ + if (iter->stackspace > STACK_FIXED_DEPTH) + MEM_freeN(iter->stack); +} + +static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting) +{ + if (iter->stacksize == iter->stackspace) { + PBVHStack *newstack; + + 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; + } + + iter->stack[iter->stacksize].node = node; + iter->stack[iter->stacksize].revisiting = revisiting; + iter->stacksize++; +} + +static PBVHNode *pbvh_iter_next(PBVHIter *iter) +{ + PBVHNode *node; + int revisiting; + + /* purpose here is to traverse tree, visiting child nodes before their + * parents, this order is necessary for e.g. computing bounding boxes */ + + while (iter->stacksize) { + /* pop node */ + iter->stacksize--; + node = iter->stack[iter->stacksize].node; + + /* on a mesh with no faces this can happen + * can remove this check if we know meshes have at least 1 face */ + if (node == NULL) + return NULL; + + revisiting = iter->stack[iter->stacksize].revisiting; + + /* revisiting node already checked */ + if (revisiting) + return node; + + if (iter->scb && !iter->scb(node, iter->search_data)) + continue; /* don't traverse, outside of search zone */ + + if (node->flag & PBVH_Leaf) { + /* immediately hit leaf node */ + return node; + } + else { + /* come back later when children are done */ + pbvh_stack_push(iter, node, 1); + + /* push two child nodes on the stack */ + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, 0); + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, 0); + } + } + + return NULL; +} + +static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter) +{ + PBVHNode *node; + + while (iter->stacksize) { + /* pop node */ + iter->stacksize--; + node = iter->stack[iter->stacksize].node; + + /* on a mesh with no faces this can happen + * can remove this check if we know meshes have at least 1 face */ + if (node == NULL) return NULL; + + if (iter->scb && !iter->scb(node, iter->search_data)) continue; /* don't traverse, outside of search zone */ + + if (node->flag & PBVH_Leaf) { + /* immediately hit leaf node */ + return node; + } + else { + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, 0); + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, 0); + } + } + + return NULL; +} + +void BLI_pbvh_search_gather(PBVH *bvh, + BLI_pbvh_SearchCallback scb, void *search_data, + PBVHNode ***r_array, int *r_tot) +{ + PBVHIter iter; + PBVHNode **array = NULL, **newarray, *node; + int tot = 0, space = 0; + + pbvh_iter_begin(&iter, bvh, scb, search_data); + + while ((node = pbvh_iter_next(&iter))) { + if (node->flag & PBVH_Leaf) { + if (tot == space) { + /* resize array if needed */ + space = (tot == 0) ? 32 : space * 2; + newarray = MEM_callocN(sizeof(PBVHNode) * space, "PBVHNodeSearch"); + + if (array) { + memcpy(newarray, array, sizeof(PBVHNode) * tot); + MEM_freeN(array); + } + + array = newarray; + } + + array[tot] = node; + tot++; + } + } + + pbvh_iter_end(&iter); + + if (tot == 0 && array) { + MEM_freeN(array); + array = NULL; + } + + *r_array = array; + *r_tot = tot; +} + +void BLI_pbvh_search_callback(PBVH *bvh, + BLI_pbvh_SearchCallback scb, void *search_data, + BLI_pbvh_HitCallback hcb, void *hit_data) +{ + PBVHIter iter; + PBVHNode *node; + + pbvh_iter_begin(&iter, bvh, scb, search_data); + + while ((node = pbvh_iter_next(&iter))) + if (node->flag & PBVH_Leaf) + hcb(node, hit_data); + + pbvh_iter_end(&iter); +} + +typedef struct node_tree { + PBVHNode *data; + + struct node_tree *left; + struct node_tree *right; +} node_tree; + +static void node_tree_insert(node_tree *tree, node_tree *new_node) +{ + if (new_node->data->tmin < tree->data->tmin) { + if (tree->left) { + node_tree_insert(tree->left, new_node); + } + else { + tree->left = new_node; + } + } + else { + if (tree->right) { + node_tree_insert(tree->right, new_node); + } + else { + tree->right = new_node; + } + } +} + +static void traverse_tree(node_tree *tree, BLI_pbvh_HitOccludedCallback hcb, void *hit_data, float *tmin) +{ + if (tree->left) traverse_tree(tree->left, hcb, hit_data, tmin); + + hcb(tree->data, hit_data, tmin); + + if (tree->right) traverse_tree(tree->right, hcb, hit_data, tmin); +} + +static void free_tree(node_tree *tree) +{ + if (tree->left) { + free_tree(tree->left); + tree->left = 0; + } + + if (tree->right) { + free_tree(tree->right); + tree->right = 0; + } + + free(tree); +} + +float BLI_pbvh_node_get_tmin(PBVHNode *node) +{ + return node->tmin; +} + +static void BLI_pbvh_search_callback_occluded(PBVH *bvh, + BLI_pbvh_SearchCallback scb, void *search_data, + BLI_pbvh_HitOccludedCallback hcb, void *hit_data) +{ + PBVHIter iter; + PBVHNode *node; + node_tree *tree = 0; + + pbvh_iter_begin(&iter, bvh, scb, search_data); + + while ((node = pbvh_iter_next_occluded(&iter))) { + if (node->flag & PBVH_Leaf) { + node_tree *new_node = malloc(sizeof(node_tree)); + + new_node->data = node; + + new_node->left = NULL; + new_node->right = NULL; + + if (tree) { + node_tree_insert(tree, new_node); + } + else { + tree = new_node; + } + } + } + + pbvh_iter_end(&iter); + + if (tree) { + float tmin = FLT_MAX; + traverse_tree(tree, hcb, hit_data, &tmin); + free_tree(tree); + } +} + +static int update_search_cb(PBVHNode *node, void *data_v) +{ + int flag = GET_INT_FROM_POINTER(data_v); + + if (node->flag & PBVH_Leaf) + return (node->flag & flag); + + return 1; +} + +static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, + int totnode, float (*face_nors)[3]) +{ + float (*vnor)[3]; + int n; + + if (bvh->type != PBVH_FACES) + return; + + /* could be per node to save some memory, but also means + * we have to store for each vertex which node it is in */ + vnor = MEM_callocN(sizeof(float) * 3 * bvh->totvert, "bvh temp vnors"); + + /* subtle assumptions: + * - We know that for all edited vertices, the nodes with faces + * adjacent to these vertices have been marked with PBVH_UpdateNormals. + * This is true because if the vertex is inside the brush radius, the + * bounding box of it's adjacent faces will be as well. + * - However this is only true for the vertices that have actually been + * edited, not for all vertices in the nodes marked for update, so we + * can only update vertices marked with ME_VERT_PBVH_UPDATE. + */ + + #pragma omp parallel for private(n) schedule(static) + for (n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + + if ((node->flag & PBVH_UpdateNormals)) { + int i, j, totface, *faces; + + faces = node->prim_indices; + totface = node->totprim; + + for (i = 0; i < totface; ++i) { + MFace *f = bvh->faces + faces[i]; + float fn[3]; + unsigned int *fv = &f->v1; + int sides = (f->v4) ? 4 : 3; + + if (f->v4) + normal_quad_v3(fn, bvh->verts[f->v1].co, bvh->verts[f->v2].co, + bvh->verts[f->v3].co, bvh->verts[f->v4].co); + else + normal_tri_v3(fn, bvh->verts[f->v1].co, bvh->verts[f->v2].co, + bvh->verts[f->v3].co); + + for (j = 0; j < sides; ++j) { + int v = fv[j]; + + if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) { + /* this seems like it could be very slow but profile + * does not show this, so just leave it for now? */ + #pragma omp atomic + vnor[v][0] += fn[0]; + #pragma omp atomic + vnor[v][1] += fn[1]; + #pragma omp atomic + vnor[v][2] += fn[2]; + } + } + + if (face_nors) + copy_v3_v3(face_nors[faces[i]], fn); + } + } + } + + #pragma omp parallel for private(n) schedule(static) + for (n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + + if (node->flag & PBVH_UpdateNormals) { + int i, *verts, totvert; + + verts = node->vert_indices; + totvert = node->uniq_verts; + + for (i = 0; i < totvert; ++i) { + const int v = verts[i]; + MVert *mvert = &bvh->verts[v]; + + if (mvert->flag & ME_VERT_PBVH_UPDATE) { + float no[3]; + + copy_v3_v3(no, vnor[v]); + normalize_v3(no); + normal_float_to_short_v3(mvert->no, no); + + mvert->flag &= ~ME_VERT_PBVH_UPDATE; + } + } + + node->flag &= ~PBVH_UpdateNormals; + } + } + + MEM_freeN(vnor); +} + +static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, + int totnode, int flag) +{ + int n; + + /* update BB, redraw flag */ + #pragma omp parallel for private(n) schedule(static) + for (n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + + if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB)) + /* don't clear flag yet, leave it for flushing later */ + update_node_vb(bvh, node); + + if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB)) + node->orig_vb = node->vb; + + if ((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw)) + node->flag &= ~PBVH_UpdateRedraw; + } +} + +static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) +{ + PBVHNode *node; + int n; + + /* can't be done in parallel with OpenGL */ + for (n = 0; n < totnode; n++) { + node = nodes[n]; + + if (node->flag & PBVH_RebuildDrawBuffers) { + GPU_free_buffers(node->draw_buffers); + switch (bvh->type) { + case PBVH_GRIDS: + node->draw_buffers = + GPU_build_grid_buffers(node->prim_indices, + node->totprim, + bvh->grid_hidden, + bvh->gridkey.grid_size); + break; + case PBVH_FACES: + node->draw_buffers = + GPU_build_mesh_buffers(node->face_vert_indices, + bvh->faces, bvh->verts, + node->prim_indices, + node->totprim); + break; + } + + node->flag &= ~PBVH_RebuildDrawBuffers; + } + + if (node->flag & PBVH_UpdateDrawBuffers) { + switch (bvh->type) { + case PBVH_GRIDS: + GPU_update_grid_buffers(node->draw_buffers, + bvh->grids, + bvh->grid_flag_mats, + node->prim_indices, + node->totprim, + &bvh->gridkey, + bvh->show_diffuse_color); + break; + case PBVH_FACES: + GPU_update_mesh_buffers(node->draw_buffers, + bvh->verts, + node->vert_indices, + node->uniq_verts + + node->face_verts, + CustomData_get_layer(bvh->vdata, + CD_PAINT_MASK), + node->face_vert_indices, + bvh->show_diffuse_color); + break; + } + + node->flag &= ~PBVH_UpdateDrawBuffers; + } + } +} + +static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) +{ + int update = 0; + + /* difficult to multithread well, we just do single threaded recursive */ + if (node->flag & PBVH_Leaf) { + if (flag & PBVH_UpdateBB) { + update |= (node->flag & PBVH_UpdateBB); + node->flag &= ~PBVH_UpdateBB; + } + + if (flag & PBVH_UpdateOriginalBB) { + update |= (node->flag & PBVH_UpdateOriginalBB); + node->flag &= ~PBVH_UpdateOriginalBB; + } + + return update; + } + else { + update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset, flag); + update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1, flag); + + if (update & PBVH_UpdateBB) + update_node_vb(bvh, node); + if (update & PBVH_UpdateOriginalBB) + node->orig_vb = node->vb; + } + + return update; +} + +void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) +{ + PBVHNode **nodes; + int totnode; + + if (!bvh->nodes) + return; + + BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), + &nodes, &totnode); + + if (flag & PBVH_UpdateNormals) + pbvh_update_normals(bvh, nodes, totnode, face_nors); + + if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw)) + pbvh_update_BB_redraw(bvh, nodes, totnode, flag); + + if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB)) + pbvh_flush_bb(bvh, bvh->nodes, flag); + + if (nodes) MEM_freeN(nodes); +} + +void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) +{ + PBVHIter iter; + PBVHNode *node; + BB bb; + + BB_reset(&bb); + + pbvh_iter_begin(&iter, bvh, NULL, NULL); + + while ((node = pbvh_iter_next(&iter))) + if (node->flag & PBVH_UpdateRedraw) + BB_expand_with_bb(&bb, &node->vb); + + pbvh_iter_end(&iter); + + copy_v3_v3(bb_min, bb.bmin); + copy_v3_v3(bb_max, bb.bmax); +} + +void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface) +{ + PBVHIter iter; + PBVHNode *node; + GHashIterator *hiter; + GHash *map; + void *face, **faces; + unsigned i; + int tot; + + map = BLI_ghash_ptr_new("pbvh_get_grid_updates gh"); + + pbvh_iter_begin(&iter, bvh, NULL, NULL); + + while ((node = pbvh_iter_next(&iter))) { + if (node->flag & PBVH_UpdateNormals) { + for (i = 0; i < node->totprim; ++i) { + face = bvh->gridfaces[node->prim_indices[i]]; + if (!BLI_ghash_lookup(map, face)) + BLI_ghash_insert(map, face, face); + } + + if (clear) + node->flag &= ~PBVH_UpdateNormals; + } + } + + pbvh_iter_end(&iter); + + tot = BLI_ghash_size(map); + if (tot == 0) { + *totface = 0; + *gridfaces = NULL; + BLI_ghash_free(map, NULL, NULL); + return; + } + + faces = MEM_callocN(sizeof(void *) * tot, "PBVH Grid Faces"); + + for (hiter = BLI_ghashIterator_new(map), i = 0; + !BLI_ghashIterator_isDone(hiter); + BLI_ghashIterator_step(hiter), ++i) + { + faces[i] = BLI_ghashIterator_getKey(hiter); + } + + BLI_ghashIterator_free(hiter); + + BLI_ghash_free(map, NULL, NULL); + + *totface = tot; + *gridfaces = faces; +} + +/***************************** PBVH Access ***********************************/ + +PBVHType BLI_pbvh_type(const PBVH *bvh) +{ + return bvh->type; +} + +BLI_bitmap *BLI_pbvh_grid_hidden(const PBVH *bvh) +{ + BLI_assert(bvh->type == PBVH_GRIDS); + return bvh->grid_hidden; +} + +void BLI_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) +{ + BLI_assert(bvh->type == PBVH_GRIDS); + *key = bvh->gridkey; +} + +/***************************** Node Access ***********************************/ + +void BLI_pbvh_node_mark_update(PBVHNode *node) +{ + node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; +} + +void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node) +{ + node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; +} + +void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) +{ + BLI_assert(node->flag & PBVH_Leaf); + + if (fully_hidden) + node->flag |= PBVH_FullyHidden; + else + node->flag &= ~PBVH_FullyHidden; +} + +void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts) +{ + if (vert_indices) *vert_indices = node->vert_indices; + if (verts) *verts = bvh->verts; +} + +void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert) +{ + int tot; + + switch (bvh->type) { + case PBVH_GRIDS: + tot = node->totprim * bvh->gridkey.grid_area; + if (totvert) *totvert = tot; + if (uniquevert) *uniquevert = tot; + break; + case PBVH_FACES: + if (totvert) *totvert = node->uniq_verts + node->face_verts; + if (uniquevert) *uniquevert = node->uniq_verts; + break; + } +} + +void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) +{ + switch (bvh->type) { + case PBVH_GRIDS: + if (grid_indices) *grid_indices = node->prim_indices; + if (totgrid) *totgrid = node->totprim; + 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: + if (grid_indices) *grid_indices = NULL; + if (totgrid) *totgrid = 0; + if (maxgrid) *maxgrid = 0; + if (gridsize) *gridsize = 0; + if (griddata) *griddata = NULL; + if (gridadj) *gridadj = NULL; + break; + } +} + +void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +{ + copy_v3_v3(bb_min, node->vb.bmin); + copy_v3_v3(bb_max, node->vb.bmax); +} + +void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +{ + copy_v3_v3(bb_min, node->orig_vb.bmin); + copy_v3_v3(bb_max, node->orig_vb.bmax); +} + +void BLI_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count) +{ + if (node->proxy_count > 0) { + if (proxies) *proxies = node->proxies; + if (proxy_count) *proxy_count = node->proxy_count; + } + else { + if (proxies) *proxies = 0; + if (proxy_count) *proxy_count = 0; + } +} + +/********************************* Raycast ***********************************/ + +typedef struct { + IsectRayAABBData ray; + int original; +} RaycastData; + +static int ray_aabb_intersect(PBVHNode *node, void *data_v) +{ + RaycastData *rcd = data_v; + float bb_min[3], bb_max[3]; + + if (rcd->original) + BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + else + BLI_pbvh_node_get_BB(node, bb_min, bb_max); + + return isect_ray_aabb(&rcd->ray, bb_min, bb_max, &node->tmin); +} + +void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, + const float ray_start[3], const float ray_normal[3], + int original) +{ + RaycastData rcd; + + isect_ray_aabb_initialize(&rcd.ray, ray_start, ray_normal); + rcd.original = original; + + BLI_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data); +} + +static int 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) +{ + float dist; + + if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &dist, NULL, 0.1f) && dist < *fdist) || + (t3 && isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist, NULL, 0.1f) && dist < *fdist)) + { + *fdist = dist; + return 1; + } + else { + return 0; + } +} + +static int pbvh_faces_node_raycast(PBVH *bvh, const PBVHNode *node, + float (*origco)[3], + const float ray_start[3], + const float ray_normal[3], float *dist) +{ + const MVert *vert = bvh->verts; + const int *faces = node->prim_indices; + int i, hit = 0, totface = node->totprim; + + for (i = 0; i < totface; ++i) { + const MFace *f = bvh->faces + faces[i]; + const int *face_verts = node->face_vert_indices[i]; + + if (paint_is_face_hidden(f, vert)) + continue; + + if (origco) { + /* intersect with backuped original coordinates */ + hit |= ray_face_intersection(ray_start, ray_normal, + origco[face_verts[0]], + origco[face_verts[1]], + origco[face_verts[2]], + f->v4 ? origco[face_verts[3]] : NULL, + dist); + } + else { + /* intersect with current coordinates */ + hit |= ray_face_intersection(ray_start, ray_normal, + vert[f->v1].co, + vert[f->v2].co, + vert[f->v3].co, + f->v4 ? vert[f->v4].co : NULL, + dist); + } + } + + return hit; +} + +static int pbvh_grids_node_raycast(PBVH *bvh, PBVHNode *node, + float (*origco)[3], + const float ray_start[3], + const float ray_normal[3], float *dist) +{ + int totgrid = node->totprim; + int gridsize = bvh->gridkey.grid_size; + int i, x, y, hit = 0; + + for (i = 0; i < totgrid; ++i) { + CCGElem *grid = bvh->grids[node->prim_indices[i]]; + BLI_bitmap gh; + + if (!grid) + continue; + + gh = bvh->grid_hidden[node->prim_indices[i]]; + + for (y = 0; y < gridsize - 1; ++y) { + for (x = 0; x < gridsize - 1; ++x) { + /* check if grid face is hidden */ + if (gh) { + if (paint_is_grid_face_hidden(gh, gridsize, x, y)) + continue; + } + + if (origco) { + hit |= ray_face_intersection(ray_start, ray_normal, + origco[y * gridsize + x], + origco[y * gridsize + x + 1], + origco[(y + 1) * gridsize + x + 1], + origco[(y + 1) * gridsize + x], + dist); + } + else { + hit |= ray_face_intersection(ray_start, ray_normal, + CCG_grid_elem_co(&bvh->gridkey, grid, x, y), + CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y), + CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1), + CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1), + dist); + } + } + } + + if (origco) + origco += gridsize * gridsize; + } + + return hit; +} + +int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], + const float ray_start[3], const float ray_normal[3], + float *dist) +{ + int hit = 0; + + if (node->flag & PBVH_FullyHidden) + return 0; + + switch (bvh->type) { + case PBVH_FACES: + hit |= pbvh_faces_node_raycast(bvh, node, origco, + ray_start, ray_normal, dist); + break; + case PBVH_GRIDS: + hit |= pbvh_grids_node_raycast(bvh, node, origco, + ray_start, ray_normal, dist); + break; + } + + return hit; +} + +//#include <GL/glew.h> + +void BLI_pbvh_node_draw(PBVHNode *node, void *setMaterial) +{ +#if 0 + /* XXX: Just some quick code to show leaf nodes in different colors */ + float col[3]; int i; + + if (0) { //is_partial) { + col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6; + } + else { + srand((long long)node); + for (i = 0; i < 3; ++i) + col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7; + } + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col); + + glColor3f(1, 0, 0); +#endif + + if (!(node->flag & PBVH_FullyHidden)) + GPU_draw_buffers(node->draw_buffers, setMaterial); +} + +typedef enum { + ISECT_INSIDE, + ISECT_OUTSIDE, + ISECT_INTERSECT +} PlaneAABBIsect; + +/* Adapted from: + * http://www.gamedev.net/community/forums/topic.asp?topic_id=512123 + * Returns true if the AABB is at least partially within the frustum + * (ok, not a real frustum), false otherwise. + */ +static PlaneAABBIsect test_planes_aabb(const float bb_min[3], + const float bb_max[3], + const float (*planes)[4]) +{ + float vmin[3], vmax[3]; + PlaneAABBIsect ret = ISECT_INSIDE; + int i, axis; + + for (i = 0; i < 4; ++i) { + for (axis = 0; axis < 3; ++axis) { + if (planes[i][axis] > 0) { + vmin[axis] = bb_min[axis]; + vmax[axis] = bb_max[axis]; + } + else { + vmin[axis] = bb_max[axis]; + vmax[axis] = bb_min[axis]; + } + } + + if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0) + return ISECT_OUTSIDE; + else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0) + ret = ISECT_INTERSECT; + } + + return ret; +} + +int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) +{ + float bb_min[3], bb_max[3]; + + BLI_pbvh_node_get_BB(node, bb_min, bb_max); + return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; +} + +int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) +{ + float bb_min[3], bb_max[3]; + + BLI_pbvh_node_get_BB(node, bb_min, bb_max); + return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; +} + +static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node) +{ + if (!node->draw_buffers) + return; + + if (GPU_buffers_diffuse_changed(node->draw_buffers, bvh->show_diffuse_color)) + node->flag |= PBVH_UpdateDrawBuffers; +} + +void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], + DMSetMaterial setMaterial) +{ + PBVHNode **nodes; + int a, totnode; + + for (a = 0; a < bvh->totnode; a++) + pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); + + BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), + &nodes, &totnode); + + pbvh_update_normals(bvh, nodes, totnode, face_nors); + pbvh_update_draw_buffers(bvh, nodes, totnode); + + if (nodes) MEM_freeN(nodes); + + if (planes) { + BLI_pbvh_search_callback(bvh, BLI_pbvh_node_planes_contain_AABB, + planes, BLI_pbvh_node_draw, setMaterial); + } + else { + BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, setMaterial); + } +} + +void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, 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) { + bvh->grid_flag_mats = flagmats; + bvh->grid_hidden = grid_hidden; + + for (a = 0; a < bvh->totnode; ++a) + BLI_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); + } +} + +float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] +{ + int a; + float (*vertCos)[3] = NULL; + + if (pbvh->verts) { + float *co; + MVert *mvert = pbvh->verts; + + vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BLI_pbvh_get_vertCoords"); + co = (float *)vertCos; + + for (a = 0; a < pbvh->totvert; a++, mvert++, co += 3) { + copy_v3_v3(co, mvert->co); + } + } + + return vertCos; +} + +void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) +{ + int a; + + if (!pbvh->deformed) { + if (pbvh->verts) { + /* if pbvh is not already deformed, verts/faces points to the */ + /* original data and applying new coords to this arrays would lead to */ + /* unneeded deformation -- duplicate verts/faces to avoid this */ + + pbvh->verts = MEM_dupallocN(pbvh->verts); + pbvh->faces = MEM_dupallocN(pbvh->faces); + + pbvh->deformed = 1; + } + } + + if (pbvh->verts) { + MVert *mvert = pbvh->verts; + /* copy new verts coords */ + for (a = 0; a < pbvh->totvert; ++a, ++mvert) { + copy_v3_v3(mvert->co, vertCos[a]); + mvert->flag |= ME_VERT_PBVH_UPDATE; + } + + /* coordinates are new -- normals should also be updated */ + BKE_mesh_calc_normals_tessface(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL); + + for (a = 0; a < pbvh->totnode; ++a) + BLI_pbvh_node_mark_update(&pbvh->nodes[a]); + + BLI_pbvh_update(pbvh, PBVH_UpdateBB, NULL); + BLI_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL); + + } +} + +int BLI_pbvh_isDeformed(PBVH *pbvh) +{ + return pbvh->deformed; +} +/* Proxies */ + +PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) +{ + int index, totverts; + + #pragma omp critical + { + + index = node->proxy_count; + + node->proxy_count++; + + if (node->proxies) + node->proxies = MEM_reallocN(node->proxies, node->proxy_count * sizeof(PBVHProxyNode)); + else + node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy"); + + BLI_pbvh_node_num_verts(bvh, node, &totverts, NULL); + node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co"); + } + + return node->proxies + index; +} + +void BLI_pbvh_node_free_proxies(PBVHNode *node) +{ + #pragma omp critical + { + int p; + + for (p = 0; p < node->proxy_count; p++) { + MEM_freeN(node->proxies[p].co); + node->proxies[p].co = 0; + } + + MEM_freeN(node->proxies); + node->proxies = 0; + + node->proxy_count = 0; + } +} + +void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) +{ + PBVHNode **array = NULL, **newarray, *node; + int tot = 0, space = 0; + int n; + + for (n = 0; n < pbvh->totnode; n++) { + node = pbvh->nodes + n; + + if (node->proxy_count > 0) { + if (tot == space) { + /* resize array if needed */ + space = (tot == 0) ? 32 : space * 2; + newarray = MEM_callocN(sizeof(PBVHNode) * space, "BLI_pbvh_gather_proxies"); + + if (array) { + memcpy(newarray, array, sizeof(PBVHNode) * tot); + MEM_freeN(array); + } + + array = newarray; + } + + array[tot] = node; + tot++; + } + } + + if (tot == 0 && array) { + MEM_freeN(array); + array = NULL; + } + + *r_array = array; + *r_tot = tot; +} + +void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, + PBVHVertexIter *vi, int mode) +{ + struct CCGElem **grids; + struct MVert *verts; + int *grid_indices, *vert_indices; + int totgrid, gridsize, uniq_verts, totvert; + + vi->grid = 0; + vi->no = 0; + vi->fno = 0; + vi->mvert = 0; + + BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); + BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); + BLI_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); + vi->key = &bvh->gridkey; + + vi->grids = grids; + vi->grid_indices = grid_indices; + vi->totgrid = (grids) ? totgrid : 1; + vi->gridsize = gridsize; + + if (mode == PBVH_ITER_ALL) + vi->totvert = totvert; + else + vi->totvert = uniq_verts; + vi->vert_indices = vert_indices; + vi->mverts = verts; + + vi->gh = NULL; + if (vi->grids && mode == PBVH_ITER_UNIQUE) + vi->grid_hidden = bvh->grid_hidden; + + vi->mask = NULL; + if (!vi->grids) + vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK); +} + +void pbvh_show_diffuse_color_set(PBVH *bvh, int show_diffuse_color) +{ + bvh->show_diffuse_color = show_diffuse_color; +} diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 965a1e2b4a6..2eadfe73858 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -2782,7 +2782,8 @@ static PointCache *ptcache_copy(PointCache *cache, int copy_data) ncache->mem_cache.last = NULL; ncache->cached_frames = NULL; - ncache->flag= 0; + /* flag is a mix of user settings and simulator/baking state */ + ncache->flag= ncache->flag & (PTCACHE_DISK_CACHE|PTCACHE_EXTERNAL|PTCACHE_IGNORE_LIBPATH); ncache->simframe= 0; } else { diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c index 8da4f11fed3..c4658712ecb 100644 --- a/source/blender/blenkernel/intern/property.c +++ b/source/blender/blenkernel/intern/property.c @@ -287,7 +287,7 @@ void BKE_bproperty_add(bProperty *prop, const char *str) } /* reads value of property, sets it in chars in str */ -void BKE_bproperty_set_valstr(bProperty *prop, char *str) +void BKE_bproperty_set_valstr(bProperty *prop, char str[MAX_PROPSTRING]) { // extern int Gdfra; /* sector.c */ diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index d925d736358..185aeac5452 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -52,6 +52,8 @@ static const char *report_type_str(int type) return TIP_("Info"); case RPT_OPERATOR: return TIP_("Operator"); + case RPT_PROPERTY: + return TIP_("Property"); case RPT_WARNING: return TIP_("Warning"); case RPT_ERROR: diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 8fcd5ca56d0..5e6d7647d1d 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -145,7 +145,8 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (type == SCE_COPY_EMPTY) { ListBase lb; - scen = BKE_scene_add(sce->id.name + 2); + /* XXX. main should become an arg */ + scen = BKE_scene_add(G.main, sce->id.name + 2); lb = scen->r.layers; scen->r = sce->r; @@ -379,9 +380,8 @@ void BKE_scene_free(Scene *sce) BKE_color_managed_view_settings_free(&sce->view_settings); } -Scene *BKE_scene_add(const char *name) +static Scene *scene_add(Main *bmain, const char *name) { - Main *bmain = G.main; Scene *sce; ParticleEditSettings *pset; int a; @@ -439,6 +439,7 @@ Scene *BKE_scene_add(const char *name) sce->r.bake_osa = 5; sce->r.bake_flag = R_BAKE_CLEAR; sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT; + sce->r.bake_rays_number = 256; sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION; sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME; sce->r.stamp_font_id = 12; @@ -612,6 +613,11 @@ Scene *BKE_scene_add(const char *name) return sce; } +Scene *BKE_scene_add(Main *bmain, const char *name) +{ + return scene_add(bmain, name); +} + Base *BKE_scene_base_find(Scene *scene, Object *ob) { return BLI_findptr(&scene->base, ob, offsetof(Base, object)); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 0b7fdaa7c1d..3bff209f53c 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1745,7 +1745,7 @@ static void transform_image(int x, int y, ImBuf *ibuf1, ImBuf *out, float scale /* interpolate */ switch (interpolation) { case 0: - neareast_interpolation(ibuf1, out, xt, yt, xi, yi); + nearest_interpolation(ibuf1, out, xt, yt, xi, yi); break; case 1: bilinear_interpolation(ibuf1, out, xt, yt, xi, yi); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index acce3740c98..1467d24f323 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -191,7 +191,9 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const int do_cache ((ID *)seq->sound)->us--; } - /* clipboard has no scene and will never have a sound handle or be active */ + /* clipboard has no scene and will never have a sound handle or be active + * same goes to sequences copy for proxy rebuild job + */ if (scene) { Editing *ed = scene->ed; @@ -1451,7 +1453,7 @@ void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, short sto IMB_anim_index_rebuild_finish(context->index_context, stop); } - seq_free_sequence_recurse(context->scene, context->seq); + seq_free_sequence_recurse(NULL, context->seq); MEM_freeN(context); } @@ -2409,8 +2411,9 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float /* opengl offscreen render */ BKE_scene_update_for_newframe(context.bmain, scene, scene->lay); - ibuf = sequencer_view3d_cb(scene, camera, context.rectx, context.recty, - IB_rect, context.scene->r.seq_prev_type, TRUE, FALSE, err_out); + ibuf = sequencer_view3d_cb(scene, camera, context.rectx, context.recty, IB_rect, + context.scene->r.seq_prev_type, context.scene->r.seq_flag & R_SEQ_SOLID_TEX, + TRUE, FALSE, err_out); if (ibuf == NULL) { fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out); } diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 53dfbdcfb85..c9cf5d561e5 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -924,7 +924,8 @@ static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3] } } -static void em_allocateData(EmissionMap *em, int use_velocity) { +static void em_allocateData(EmissionMap *em, int use_velocity) +{ int i, res[3]; for (i = 0; i < 3; i++) { @@ -941,7 +942,8 @@ static void em_allocateData(EmissionMap *em, int use_velocity) { em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity"); } -static void em_freeData(EmissionMap *em) { +static void em_freeData(EmissionMap *em) +{ if (em->influence) MEM_freeN(em->influence); if (em->velocity) @@ -2509,7 +2511,8 @@ float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity return -1.0f; } -int smoke_get_data_flags(SmokeDomainSettings *sds) { +int smoke_get_data_flags(SmokeDomainSettings *sds) +{ int flags = 0; if (smoke_has_heat(sds->fluid)) flags |= SM_ACTIVE_HEAT; if (smoke_has_fuel(sds->fluid)) flags |= SM_ACTIVE_FIRE; diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 09440591826..f6599cc9648 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -35,7 +35,6 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" #include "BKE_animsys.h" #include "BKE_global.h" diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f76b480c423..7c58c7b21ed 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -50,8 +50,8 @@ #include "BLI_edgehash.h" #include "BLI_math.h" #include "BLI_memarena.h" -#include "BLI_pbvh.h" +#include "BKE_pbvh.h" #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 6d0313f6334..149842bc038 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -42,7 +42,6 @@ #include "BLI_math.h" #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" #include "DNA_key_types.h" #include "DNA_object_types.h" diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 30b48401046..801fecc9f7c 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -3462,15 +3462,15 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, aspect, tloc, tscale, tangle, mat); invert_m4(mat); - if (filter == TRACKING_FILTER_NEAREAST) - interpolation = neareast_interpolation; + if (filter == TRACKING_FILTER_NEAREST) + interpolation = nearest_interpolation; else if (filter == TRACKING_FILTER_BILINEAR) interpolation = bilinear_interpolation; else if (filter == TRACKING_FILTER_BICUBIC) interpolation = bicubic_interpolation; else /* fallback to default interpolation method */ - interpolation = neareast_interpolation; + interpolation = nearest_interpolation; for (j = 0; j < tmpibuf->y; j++) { for (i = 0; i < tmpibuf->x; i++) { diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 4bde895cf7d..ad101c41dc5 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -40,7 +40,6 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" -#include "BLI_bpath.h" #include "BKE_animsys.h" #include "BKE_global.h" diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 0f861a7ed37..cf2a165c2b2 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -497,8 +497,15 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex 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; + +#if 0 + /* this options are not set in ffmpeg.c and leads to artifacts with MPEG-4 + * see #33586: Encoding to mpeg4 makes first frame(s) blocky + */ c->rc_initial_buffer_occupancy = rd->ffcodecdata.rc_buffer_size * 3 / 4; c->rc_buffer_aggressivity = 1.0; +#endif + c->me_method = ME_EPZS; codec = avcodec_find_encoder(c->codec_id); |