diff options
Diffstat (limited to 'source/blender/blenkernel')
68 files changed, 2492 insertions, 492 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index f06547fe2e3..5f504df5628 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -95,6 +95,8 @@ struct BMEditMesh; struct ListBase; struct PBVH; +#define DM_OMP_LIMIT 0 /* setting zero so we can catch bugs in OpenMP/BMesh */ + /* number of sub-elements each mesh element has (for interpolation) */ #define SUB_ELEMS_VERT 0 #define SUB_ELEMS_EDGE 2 @@ -729,4 +731,4 @@ BLI_INLINE int DM_origindex_mface_mpoly(const int *index_mf_to_mpoly, const int return (j != ORIGINDEX_NONE) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : ORIGINDEX_NONE; } -#endif +#endif /* __BKE_DERIVEDMESH_H__ */ diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 2d7030b2d42..4f54f93a7fc 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -220,7 +220,7 @@ void BKE_pose_remove_group(struct Object *ob); void what_does_obaction(struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe); /* for proxy */ -void BKE_pose_copy_result(struct bPose *to, struct bPose *from); +bool BKE_pose_copy_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void BKE_pose_rest(struct bPose *pose); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 9c6d26c08bc..2548d95c383 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 8 +#define BLENDER_SUBVERSION 9 /* 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 a /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE alpha +#define BLENDER_VERSION_CYCLE beta extern char versionstr[]; /* from blender.c */ diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 248fe9c8968..91f0525d4f3 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -36,6 +36,7 @@ struct ID; struct Brush; struct ImBuf; +struct ImagePool; struct Scene; struct wmOperator; // enum CurveMappingPreset; @@ -67,7 +68,8 @@ float BKE_brush_curve_strength_clamp(struct Brush *br, float p, const float len) float BKE_brush_curve_strength(struct Brush *br, float p, const float len); /* used for sculpt */ /* sampling */ -void BKE_brush_sample_tex(const struct Scene *scene, struct Brush *brush, const float xy[2], float rgba[4], const int thread); +void BKE_brush_sample_tex(const struct Scene *scene, struct Brush *brush, const float sampleco[3], float rgba[4], const int thread, struct ImagePool *pool); +void BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, const float xy[2], float rgba[4], const int thread); void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size, struct ImBuf **imbuf, int use_color_correction); diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index 96e05aa87b9..e0b7e68bafc 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -42,14 +42,6 @@ struct Histogram; struct ImBuf; struct rctf; -#if defined _MSC_VER -# define DO_INLINE __inline -#elif defined(__sun) || defined(__sun__) -# define DO_INLINE -#else -# define DO_INLINE static inline -#endif - void curvemapping_set_defaults(struct CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy); struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy); void curvemapping_free_data(struct CurveMapping *cumap); diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index cf7e4b24288..49dc1bfd732 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -36,13 +36,14 @@ extern "C" { // #define DEPS_DEBUG -struct ID; -struct Main; -struct Scene; -struct DagNodeQueue; struct DagForest; struct DagNode; +struct DagNodeQueue; struct GHash; +struct ID; +struct Main; +struct Object; +struct Scene; /* **** DAG relation types *** */ diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 499609932d1..bfee5e820c3 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -44,6 +44,7 @@ struct anim; struct Scene; struct Object; struct ImageFormatData; +struct ImagePool; struct Main; #define IMA_MAX_SPACE 64 @@ -146,6 +147,11 @@ int BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser); struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **lock_r); void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock); +struct ImagePool *BKE_image_pool_new(void); +void BKE_image_pool_free(struct ImagePool *pool); +struct ImBuf *BKE_image_pool_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, struct ImagePool *pool); +void BKE_image_pool_release_ibuf(struct Image *ima, struct ImBuf *ibuf, struct ImagePool *pool); + /* returns a new image or NULL if it can't load */ struct Image *BKE_image_load(const char *filepath); /* returns existing Image when filename/type is same (frame optional) */ @@ -219,6 +225,10 @@ void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int height, int width); void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int height, int width); +/* Cycles hookup */ +unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame); +float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index be42ee524de..7c36ff07da5 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -102,5 +102,4 @@ typedef struct Main { } #endif -#endif - +#endif /* __BKE_MAIN_H__ */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 3466a914bce..cfe562e231c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -100,6 +100,16 @@ void BKE_mesh_calc_poly_center(struct MPoly *mpoly, struct MLoop *loopstart, float BKE_mesh_calc_poly_area(struct MPoly *mpoly, struct MLoop *loopstart, struct MVert *mvarray, const float polynormal[3]); +void BKE_mesh_calc_relative_deform( + const struct MPoly *mpoly, const int totpoly, + const struct MLoop *mloop, const int totvert, + + const float (*vert_cos_src)[3], + const float (*vert_cos_dst)[3], + + const float (*vert_cos_org)[3], + float (*vert_cos_new)[3]); + /* Find the index of the loop in 'poly' which references vertex, * returns -1 if not found */ int poly_find_loop_from_vert(const struct MPoly *poly, diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 0a2f757b38e..718fa2f9ecd 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -577,7 +577,7 @@ struct ShadeResult; struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree, int use_tree_data); void ntreeShaderEndExecTree(struct bNodeTreeExec *exec, int use_tree_data); -void ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr); +bool ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr); void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode); void nodeShaderSynchronizeID(struct bNode *node, int copyto); @@ -737,8 +737,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria /* API */ struct CompBuf; -struct bNodeTreeExec *ntreeCompositBeginExecTree(struct bNodeTree *ntree, int use_tree_data); -void ntreeCompositEndExecTree(struct bNodeTreeExec *exec, int use_tree_data); void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings); void ntreeCompositTagRender(struct Scene *sce); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 0a4a7f75e25..211b6189fa8 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -34,6 +34,7 @@ struct bContext; struct BMesh; +struct BMFace; struct Brush; struct MDisps; struct MeshElemMap; @@ -46,6 +47,7 @@ struct Paint; struct PBVH; struct Scene; struct StrokeCache; +struct ImagePool; extern const char PAINT_CURSOR_SCULPT[3]; extern const char PAINT_CURSOR_VERTEX_PAINT[3]; @@ -72,6 +74,7 @@ int paint_vertsel_test(struct Object *ob); int paint_is_face_hidden(const struct MFace *f, const struct MVert *mvert); int paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y); +int paint_is_bmesh_face_hidden(struct BMFace *f); /* paint masks */ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, @@ -114,6 +117,7 @@ typedef struct SculptSession { /* Used to cache the render of the active texture */ unsigned int texcache_side, *texcache, texcache_actual; + struct ImagePool *tex_pool; /* Layer brush persistence between strokes */ float (*layer_co)[3]; /* Copy of the mesh vertices' locations */ diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index f15ad296e4a..3394c4f4ce0 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -306,7 +306,7 @@ int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct Pa 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]); +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, diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 709db7e4570..99ed978561e 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -113,6 +113,9 @@ typedef enum { PBVHType BKE_pbvh_type(const PBVH *bvh); +/* Get the PBVH root's bounding box */ +void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]); + /* multires hidden data, only valid for type == PBVH_GRIDS */ unsigned int **BKE_pbvh_grid_hidden(const PBVH *bvh); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 77b35e1a25c..1cb50425c40 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -67,6 +67,7 @@ #define PTCACHE_TYPE_SMOKE_DOMAIN 3 #define PTCACHE_TYPE_SMOKE_HIGHRES 4 #define PTCACHE_TYPE_DYNAMICPAINT 5 +#define PTCACHE_TYPE_RIGIDBODY 6 /* high bits reserved for flags that need to be stored in file */ #define PTCACHE_TYPEFLAG_COMPRESS (1 << 16) @@ -91,6 +92,7 @@ struct PointCache; struct Scene; struct SmokeModifierData; struct SoftBody; +struct RigidBodyWorld; /* temp structure for read/write */ typedef struct PTCacheData { @@ -260,6 +262,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct Par void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd); void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd); void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface); +void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw); void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis); @@ -294,10 +297,6 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra); /* Main cache writing call. */ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra); -/****************** Continue physics ***************/ -void BKE_ptcache_set_continue_physics(struct Main *bmain, struct Scene *scene, int enable); -int BKE_ptcache_get_continue_physics(void); - /******************* Allocate & free ***************/ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); void BKE_ptcache_free_mem(struct ListBase *mem_cache); diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h new file mode 100644 index 00000000000..607c3026388 --- /dev/null +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -0,0 +1,95 @@ +/* + * ***** 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) 2013 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_rigidbody.h + * \ingroup blenkernel + * \brief API for Blender-side Rigid Body stuff + */ + + +#ifndef __BKE_RIGIDBODY_H__ +#define __BKE_RIGIDBODY_H__ + +struct RigidBodyWorld; +struct RigidBodyOb; + +struct Scene; +struct Object; +struct Group; + +/* -------------- */ +/* Memory Management */ + +void BKE_rigidbody_free_world(struct RigidBodyWorld *rbw); +void BKE_rigidbody_free_object(struct Object *ob); +void BKE_rigidbody_free_constraint(struct Object *ob); + +/* ...... */ + +struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob); +struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob); + +/* -------------- */ +/* Setup */ + +/* create Blender-side settings data - physics objects not initialised yet */ +struct RigidBodyWorld *BKE_rigidbody_create_world(struct Scene *scene); +struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Object *ob, short type); +struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type); + +/* 'validate' (i.e. make new or replace old) Physics-Engine objects */ +void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, short rebuild); +void BKE_rigidbody_validate_sim_object(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild); +void BKE_rigidbody_validate_sim_shape(struct Object *ob, short rebuild); +void BKE_rigidbody_validate_sim_constraint(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild); + +/* -------------- */ +/* Utilities */ + +struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene); +void BKE_rigidbody_remove_object(struct Scene *scene, struct Object *ob); +void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob); + +/* -------------- */ +/* Utility Macros */ + +/* get mass of Rigid Body Object to supply to RigidBody simulators */ +#define RBO_GET_MASS(rbo) \ + ((rbo && ((rbo->type == RBO_TYPE_PASSIVE) || (rbo->flag & RBO_FLAG_KINEMATIC) || (rbo->flag & RBO_FLAG_DISABLED))) ? (0.0f) : (rbo->mass)) +/* get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin, convex hull always uses custom margin */ +#define RBO_GET_MARGIN(rbo) \ + ((rbo->flag & RBO_FLAG_USE_MARGIN || rbo->shape == RB_SHAPE_CONVEXH || rbo->shape == RB_SHAPE_TRIMESH || rbo->shape == RB_SHAPE_CONE) ? (rbo->margin) : (0.04f)) + +/* -------------- */ +/* Simulation */ + +void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle); +void BKE_rigidbody_sync_transforms(struct Scene *scene, struct Object *ob, float ctime); +void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw); +void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime); + +#endif /* __BKE_RIGIDBODY_H__ */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 6447b2a8dee..9bf0991272a 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -72,6 +72,7 @@ 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); struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob); +void BKE_scene_base_unlink(struct Scene *sce, struct Base *base); void BKE_scene_base_deselect_all(struct Scene *sce); void BKE_scene_base_select(struct Scene *sce, struct Base *selbase); int BKE_scene_base_iter_next(struct Scene **scene, int val, struct Base **base, struct Object **ob); @@ -115,6 +116,7 @@ int BKE_scene_use_new_shading_nodes(struct Scene *scene); void BKE_scene_disable_color_management(struct Scene *scene); int BKE_scene_check_color_management_enabled(const struct Scene *scene); +int BKE_scene_check_rigidbody_active(const struct Scene *scene); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_tessmesh.h b/source/blender/blenkernel/BKE_tessmesh.h index 9462822e25f..b3e6ab37273 100644 --- a/source/blender/blenkernel/BKE_tessmesh.h +++ b/source/blender/blenkernel/BKE_tessmesh.h @@ -83,7 +83,7 @@ typedef struct BMEditMesh { } BMEditMesh; void BMEdit_RecalcTessellation(BMEditMesh *em); -BMEditMesh *BMEdit_Create(BMesh *bm, int do_tessellate); +BMEditMesh *BMEdit_Create(BMesh *bm, const bool do_tessellate); BMEditMesh *BMEdit_Copy(BMEditMesh *em); BMEditMesh *BMEdit_FromObject(struct Object *ob); void BMEdit_Free(BMEditMesh *em); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 1e3dd426efa..be30eba0559 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -105,6 +105,7 @@ int text_check_bracket(const char ch); int text_check_delim(const char ch); int text_check_digit(const char ch); int text_check_identifier(const char ch); +int text_check_identifier_nodigit(const char ch); int text_check_whitespace(const char ch); int text_find_identifier_start(const char *str, int i); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 23f23acad6b..2eeecefe231 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -128,6 +128,7 @@ set(SRC intern/pointcache.c intern/property.c intern/report.c + intern/rigidbody.c intern/sca.c intern/scene.c intern/screen.c @@ -219,6 +220,7 @@ set(SRC BKE_pointcache.h BKE_property.h BKE_report.h + BKE_rigidbody.h BKE_sca.h BKE_scene.h BKE_screen.h @@ -261,7 +263,10 @@ if(WITH_BULLET) list(APPEND INC_SYS ${BULLET_INCLUDE_DIRS} ) - add_definitions(-DUSE_BULLET) + list(APPEND INC + ../rigidbody + ) + add_definitions(-DWITH_BULLET) endif() #if(WITH_MOD_CLOTH_ELTOPO) diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 2998da824ef..bcdf37da104 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -41,6 +41,7 @@ incs += ' ../render/extern/include ../makesrna' incs += ' ../imbuf ../ikplugin ../avi #/intern/elbeem/extern ../nodes ../modifiers' incs += ' #/intern/iksolver/extern ../blenloader' incs += ' #/extern/bullet2/src' +incs += ' ../rigidbody' incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' incs += ' ../bmesh' @@ -110,7 +111,7 @@ if env['WITH_BF_QUICKTIME']: incs += ' ' + env['BF_QUICKTIME_INC'] if env['WITH_BF_BULLET']: - defs.append('USE_BULLET') + defs.append('WITH_BULLET') if env['OURPLATFORM'] == 'darwin': if env['WITH_BF_OPENMP']: diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index cc20470b4d5..2079c783898 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -16,12 +16,6 @@ #include "BLI_utildefines.h" /* for BLI_assert */ -#ifdef _MSC_VER -# define CCG_INLINE __inline -#else -# define CCG_INLINE inline -#endif - /* used for normalize_v3 in BLI_math_vector * float.h's FLT_EPSILON causes trouble with subsurf normals - campbell */ #define EPSILON (1.0e-35f) @@ -305,7 +299,7 @@ struct CCGVert { // byte *userData; }; -static CCG_INLINE byte *VERT_getLevelData(CCGVert *v) +BLI_INLINE byte *VERT_getLevelData(CCGVert *v) { return (byte *)(&(v)[1]); } @@ -324,7 +318,7 @@ struct CCGEdge { // byte *userData; }; -static CCG_INLINE byte *EDGE_getLevelData(CCGEdge *e) +BLI_INLINE byte *EDGE_getLevelData(CCGEdge *e) { return (byte *)(&(e)[1]); } @@ -342,17 +336,17 @@ struct CCGFace { // byte *userData; }; -static CCG_INLINE CCGVert **FACE_getVerts(CCGFace *f) +BLI_INLINE CCGVert **FACE_getVerts(CCGFace *f) { return (CCGVert **)(&f[1]); } -static CCG_INLINE CCGEdge **FACE_getEdges(CCGFace *f) +BLI_INLINE CCGEdge **FACE_getEdges(CCGFace *f) { return (CCGEdge **)(&(FACE_getVerts(f)[f->numVerts])); } -static CCG_INLINE byte *FACE_getCenterData(CCGFace *f) +BLI_INLINE byte *FACE_getCenterData(CCGFace *f) { return (byte *)(&(FACE_getEdges(f)[(f)->numVerts])); } @@ -698,28 +692,28 @@ static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int return f; } -static CCG_INLINE void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) +BLI_INLINE void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) { int maxGridSize = ccg_gridsize(levels); int spacing = ccg_spacing(levels, lvl); byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); return &gridBase[dataSize * x * spacing]; } -static CCG_INLINE void *_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) +BLI_INLINE void *_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) { int maxGridSize = ccg_gridsize(levels); int spacing = ccg_spacing(levels, lvl); byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); return &gridBase[dataSize * x * spacing + normalDataOffset]; } -static CCG_INLINE void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) +BLI_INLINE void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) { int maxGridSize = ccg_gridsize(levels); int spacing = ccg_spacing(levels, lvl); byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); return &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing)]; } -static CCG_INLINE float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) +BLI_INLINE float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) { int maxGridSize = ccg_gridsize(levels); int spacing = ccg_spacing(levels, lvl); @@ -742,7 +736,7 @@ static int _face_getEdgeIndex(CCGFace *f, CCGEdge *e) return i; return -1; } -static CCG_INLINE void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize) +BLI_INLINE void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize) { int maxGridSize = ccg_gridsize(levels); int spacing = ccg_spacing(levels, lvl); @@ -1422,18 +1416,25 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, float no[3]; for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) - for (x = 0; x < gridSize - 1; x++) + for (y = 0; y < gridSize - 1; y++) { + for (x = 0; x < gridSize - 1; x++) { NormZero(FACE_getIFNo(f, lvl, S, x, y)); + } + } - if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) - for (x = 0; x < gridSize - 1; x++) + if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) { + for (x = 0; x < gridSize - 1; x++) { NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1)); - if (FACE_getEdges(f)[S]->flags & Edge_eEffected) - for (y = 0; y < gridSize - 1; y++) + } + } + if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { + for (y = 0; y < gridSize - 1; y++) { NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y)); - if (FACE_getVerts(f)[S]->flags & Vert_eEffected) + } + } + if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1)); + } } for (S = 0; S < f->numVerts; S++) { diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index dde1d5870ca..8ca6d045712 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -169,7 +169,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) static MVert *dm_dupVertArray(DerivedMesh *dm) { - MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm), + MVert *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumVerts(dm), "dm_dupVertArray tmp"); if (tmp) dm->copyVertArray(dm, tmp); @@ -179,7 +179,7 @@ static MVert *dm_dupVertArray(DerivedMesh *dm) static MEdge *dm_dupEdgeArray(DerivedMesh *dm) { - MEdge *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumEdges(dm), + MEdge *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumEdges(dm), "dm_dupEdgeArray tmp"); if (tmp) dm->copyEdgeArray(dm, tmp); @@ -189,7 +189,7 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm) static MFace *dm_dupFaceArray(DerivedMesh *dm) { - MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumTessFaces(dm), + MFace *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumTessFaces(dm), "dm_dupFaceArray tmp"); if (tmp) dm->copyTessFaceArray(dm, tmp); @@ -199,7 +199,7 @@ static MFace *dm_dupFaceArray(DerivedMesh *dm) static MLoop *dm_dupLoopArray(DerivedMesh *dm) { - MLoop *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumLoops(dm), + MLoop *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumLoops(dm), "dm_dupLoopArray tmp"); if (tmp) dm->copyLoopArray(dm, tmp); @@ -209,7 +209,7 @@ static MLoop *dm_dupLoopArray(DerivedMesh *dm) static MPoly *dm_dupPolyArray(DerivedMesh *dm) { - MPoly *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumPolys(dm), + MPoly *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumPolys(dm), "dm_dupPolyArray tmp"); if (tmp) dm->copyPolyArray(dm, tmp); @@ -574,7 +574,7 @@ void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb) if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) return; if (kb->data) MEM_freeN(kb->data); - kb->data = MEM_callocN(me->key->elemsize * me->totvert, "kb->data"); + kb->data = MEM_mallocN(me->key->elemsize * me->totvert, "kb->data"); kb->totelem = totvert; fp = kb->data; @@ -1584,9 +1584,15 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); - range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); - range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); - range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); +#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= DM_OMP_LIMIT) + { +#pragma omp section + { range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); } +#pragma omp section + { range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); } +#pragma omp section + { range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); } + } } } @@ -2353,15 +2359,14 @@ DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) return NULL; dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); - vertexcosnos = MEM_callocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); if (dm->foreachMappedVert) { + vertexcosnos = MEM_callocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos); } else { - DMCoNo *v_co_no = vertexcosnos; + DMCoNo *v_co_no = vertexcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); int a; - 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 63e12dfb99d..5ccf9146440 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1118,18 +1118,18 @@ void BKE_pose_rest(bPose *pose) } /* both poses should be in sync */ -void BKE_pose_copy_result(bPose *to, bPose *from) +bool BKE_pose_copy_result(bPose *to, bPose *from) { bPoseChannel *pchanto, *pchanfrom; if (to == NULL || from == NULL) { - printf("pose result copy error to:%p from:%p\n", (void *)to, (void *)from); /* debug temp */ - return; + printf("Pose copy error, pose to:%p from:%p\n", (void *)to, (void *)from); /* debug temp */ + return false; } if (to == from) { printf("BKE_pose_copy_result source and target are the same\n"); - return; + return false; } @@ -1153,6 +1153,7 @@ void BKE_pose_copy_result(bPose *to, bPose *from) pchanto->protectflag = pchanfrom->protectflag; } } + return true; } /* For the calculation of the effects of an Action at the given frame on an object diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 4058809c275..dab54756c82 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -69,6 +69,7 @@ #include "BKE_depsgraph.h" #include "BKE_anim.h" #include "BKE_report.h" +#include "BKE_rigidbody.h" // XXX bad level call... @@ -327,6 +328,7 @@ static void motionpaths_calc_update_scene(Scene *scene) { #if 1 // 'production' optimizations always on Base *base, *last = NULL; + float ctime = BKE_scene_frame_get(scene); /* only stuff that moves or needs display still */ DAG_scene_update_flags(G.main, scene, scene->lay, TRUE); @@ -340,6 +342,14 @@ static void motionpaths_calc_update_scene(Scene *scene) last = base; } + /* run rigidbody sim + * NOTE: keep in sync with BKE_scene_update_for_newframe() in scene.c + */ + // XXX: this position may still change, objects not being updated correctly before simulation is run + // NOTE: current position is so that rigidbody sim affects other objects + if (BKE_scene_check_rigidbody_active(scene)) + BKE_rigidbody_do_simulation(scene, ctime); + /* perform updates for tagged objects */ /* XXX: this will break if rigs depend on scene or other data that * is animated but not attached to/updatable from objects */ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 11ae242023c..fb2d1a3aaf7 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -426,6 +426,9 @@ void BKE_userdef_free(void) /* handle changes in settings that need recalc */ void BKE_userdef_state(void) { + /* prevent accidents */ + if (U.pixelsize == 0) U.pixelsize = 1; + BLF_default_dpi(U.pixelsize * U.dpi); U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 6db1052d6bd..624e86d5787 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -462,6 +462,10 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int OceanModifierData *omd = (OceanModifierData *) md; rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data); } + else if (md->type == eModifierType_MeshCache) { + MeshCacheModifierData *mcmd = (MeshCacheModifierData *) md; + rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data); + } } if (ob->soft) { diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index aeb0407b37f..70eaa00b82e 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -259,7 +259,6 @@ void BKE_brush_debug_print_state(Brush *br) BR_TEST_FLAG(BRUSH_SIZE_PRESSURE); BR_TEST_FLAG(BRUSH_JITTER_PRESSURE); BR_TEST_FLAG(BRUSH_SPACING_PRESSURE); - BR_TEST_FLAG(BRUSH_FIXED_TEX); BR_TEST_FLAG(BRUSH_RAKE); BR_TEST_FLAG(BRUSH_ANCHORED); BR_TEST_FLAG(BRUSH_DIR_IN); @@ -472,8 +471,49 @@ int BKE_brush_clone_image_delete(Brush *brush) return 0; } -/* Brush Sampling */ -void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float xy[2], float rgba[4], const int thread) +/* Brush Sampling for 3d brushes. Currently used for texture painting only, but should be generalized */ +void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float sampleco[3], float rgba[4], const int thread, struct ImagePool *pool) +{ + MTex *mtex = &brush->mtex; + + if (mtex && mtex->tex) { + float tin, tr, tg, tb, ta; + int hasrgb; + const int radius = BKE_brush_size_get(scene, brush); + + if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { + hasrgb = externtex(mtex, sampleco, &tin, &tr, &tg, &tb, &ta, thread, pool); + } + else { + float co[3]; + + co[0] = sampleco[0] / radius; + co[1] = sampleco[1] / radius; + co[2] = 0.0f; + + hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, thread, pool); + } + + if (hasrgb) { + rgba[0] = tr; + rgba[1] = tg; + rgba[2] = tb; + rgba[3] = ta; + } + else { + rgba[0] = tin; + rgba[1] = tin; + rgba[2] = tin; + rgba[3] = 1.0f; + } + } + else { + rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0f; + } +} + +/* Brush Sampling for 2D brushes. when we unify the brush systems this will be necessarily a separate function */ +void BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2], float rgba[4], const int thread) { MTex *mtex = &brush->mtex; @@ -486,7 +526,7 @@ void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float xy[2], f co[1] = xy[1] / radius; co[2] = 0.0f; - hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, thread); + hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, thread, NULL); if (hasrgb) { rgba[0] = tr; @@ -506,7 +546,8 @@ void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float xy[2], f } } -/* TODO, use define for 'texfall' arg */ +/* TODO, use define for 'texfall' arg + * NOTE: only used for 2d brushes currently! */ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction) { ImBuf *ibuf; @@ -545,10 +586,10 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf dstf[3] = alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); } else if (texfall == 1) { - BKE_brush_sample_tex(scene, brush, xy, dstf, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, dstf, 0); } else { - BKE_brush_sample_tex(scene, brush, xy, rgba, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0); mul_v3_v3v3(dstf, rgba, brush_rgb); dstf[3] = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); } @@ -575,11 +616,11 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf dst[3] = FTOCHAR(alpha_f); } else if (texfall == 1) { - BKE_brush_sample_tex(scene, brush, xy, rgba, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0); rgba_float_to_uchar(dst, rgba); } else if (texfall == 2) { - BKE_brush_sample_tex(scene, brush, xy, rgba, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0); mul_v3_v3(rgba, brush->rgb); alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); @@ -588,7 +629,7 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf dst[3] = FTOCHAR(alpha_f); } else { - BKE_brush_sample_tex(scene, brush, xy, rgba, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0); alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius); dst[0] = crgb[0]; @@ -621,7 +662,9 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf void BKE_brush_size_set(Scene *scene, Brush *brush, int size) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - + + size = (int)((float)size / U.pixelsize); + if (ups->flag & UNIFIED_PAINT_SIZE) ups->size = size; else diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index ad828a70dd8..5028d978351 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -38,11 +38,11 @@ #include "BLI_utildefines.h" #include "BLI_linklist.h" +#include "BLI_math.h" #include "BKE_DerivedMesh.h" #include "BKE_tessmesh.h" -#include "BLI_math.h" #include "MEM_guardedalloc.h" /* Math stuff for ray casting on mesh faces and for nearest surface */ diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 57c88919021..d1842b99831 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -237,6 +237,9 @@ void BKE_camera_params_from_object(CameraParams *params, Object *ob) params->clipsta = la->clipsta; params->clipend = la->clipend; } + else { + params->lens = 35.0f; + } } void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView3D *rv3d) diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 85dd4c67fdf..66b457ec502 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1111,6 +1111,19 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, index_mp_to_orig = NULL; } + /* TODO: same as for solid draw, not entirely correct, but works fine for now, + * will skip using textures (dyntopo currently destroys UV anyway) and + * works fine for matcap + */ + if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { + if (dm->numTessFaceData) { + setMaterial(1, &gattribs); + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, FALSE); + } + + return; + } + cdDM_update_normals_from_pbvh(dm); matnr = -1; @@ -1412,6 +1425,19 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm, index_mp_to_orig = NULL; } + /* TODO: same as for solid draw, not entirely correct, but works fine for now, + * will skip using textures (dyntopo currently destroys UV anyway) and + * works fine for matcap + */ + if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { + if (dm->numTessFaceData) { + setMaterial(userData, 1, NULL); + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, FALSE); + } + + return; + } + cdDM_update_normals_from_pbvh(dm); matnr = -1; @@ -2285,6 +2311,7 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm) */ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) { +// #define USE_LOOPS CDDerivedMesh *cddm = (CDDerivedMesh *)dm; CDDerivedMesh *cddm2 = NULL; MVert *mv, *mvert = NULL; @@ -2296,18 +2323,27 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) MLoop *ml, *mloop = NULL; BLI_array_declare(mloop); EdgeHash *ehash = BLI_edgehash_new(); - int *newv = NULL, *newe = NULL, *newl = NULL; + int *newv = NULL, *newe = NULL; +#ifdef USE_LOOPS + int *newl = NULL; +#endif int *oldv = NULL, *olde = NULL, *oldl = NULL, *oldp = NULL; BLI_array_declare(oldv); BLI_array_declare(olde); BLI_array_declare(oldl); BLI_array_declare(oldp); - int i, j, c, totloop, totpoly; - + int i, j, c, totpoly; +#ifdef USE_LOOPS + int totloop; +#endif + +#ifdef USE_LOOPS totloop = dm->numLoopData; +#endif totpoly = dm->numPolyData; - newv = MEM_callocN(sizeof(int) * dm->numVertData, "newv vtable CDDM_merge_verts"); - newe = MEM_callocN(sizeof(int) * dm->numEdgeData, "newv etable CDDM_merge_verts"); - newl = MEM_callocN(sizeof(int) * totloop, "newv ltable CDDM_merge_verts"); - + newv = MEM_mallocN(sizeof(int) * dm->numVertData, "newv vtable CDDM_merge_verts"); + newe = MEM_mallocN(sizeof(int) * dm->numEdgeData, "newv etable CDDM_merge_verts"); +#ifdef USE_LOOPS + newl = MEM_mallocN(sizeof(int) * totloop, "newv ltable CDDM_merge_verts"); +#endif /* fill newl with destination vertex indices */ mv = cddm->mvert; c = 0; @@ -2317,6 +2353,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) newv[i] = c++; BLI_array_append(mvert, *mv); } + else { + /* dummy value */ + newv[i] = 0; + } } /* now link target vertices to destination indices */ @@ -2385,7 +2425,9 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) for (j = 0; j < mp->totloop; j++, ml++) { med = cddm->medge + ml->e; if (LIKELY(med->v1 != med->v2)) { +#ifdef USE_LOOPS newl[j + mp->loopstart] = BLI_array_count(mloop); +#endif BLI_array_append(oldl, j + mp->loopstart); BLI_array_append(mloop, *ml); c++; @@ -2451,8 +2493,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) MEM_freeN(newv); if (newe) MEM_freeN(newe); +#ifdef USE_LOOPS if (newl) MEM_freeN(newl); +#endif if (oldv) MEM_freeN(oldv); if (olde) diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index fdd7dc94979..c1293542963 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -483,7 +483,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; /* handle continuous simulation with the play button */ - if (BKE_ptcache_get_continue_physics() || ((clmd->sim_parms->preroll > 0) && (framenr > startframe - clmd->sim_parms->preroll) && (framenr < startframe))) { + if ((clmd->sim_parms->preroll > 0) && (framenr > startframe - clmd->sim_parms->preroll) && (framenr < startframe)) { BKE_ptcache_invalidate(cache); /* do simulation */ diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 60bf67e19e3..061657c8f2d 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -59,7 +59,7 @@ #include "BKE_modifier.h" #include "BKE_DerivedMesh.h" -#ifdef USE_BULLET +#ifdef WITH_BULLET #include "Bullet-C-Api.h" #endif #include "BLI_kdopbvh.h" @@ -385,7 +385,7 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2, CollisionModifierData *collmd = (CollisionModifierData *) md2; /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */ MFace *face1=NULL, *face2 = NULL; -#ifdef USE_BULLET +#ifdef WITH_BULLET ClothVertex *verts1 = clmd->clothObject->verts; #endif double distance = 0; @@ -458,7 +458,7 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2, } } -#ifdef USE_BULLET +#ifdef WITH_BULLET // calc distance + normal distance = plNearestPoints ( verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa, collpair->pb, collpair->vector ); diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 529fe07cab3..d08c16eac9e 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -895,7 +895,7 @@ void curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size #define INV_255 (1.f / 255.f) -DO_INLINE int get_bin_float(float f) +BLI_INLINE int get_bin_float(float f) { int bin = (int)((f * 255.0f) + 0.5f); /* 0.5 to prevent quantisation differences */ diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index fe8bd0cc5a4..a6e68b9b2d5 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1746,7 +1746,7 @@ static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *si else t02 = (saacos(t02)) / 2.0f; - t02 = (float)sin(t02); + t02 = sinf(t02); if (t02 == 0.0f) t02 = 1.0f; @@ -2220,6 +2220,7 @@ void BKE_curve_bevelList_make(Object *ob) struct bevelsort *sortdata, *sd, *sd1; int a, b, nr, poly, resolu = 0, len = 0; int do_tilt, do_radius, do_weight; + int is_editmode = 0; /* this function needs an object, because of tflag and upflag */ cu = ob->data; @@ -2233,12 +2234,17 @@ void BKE_curve_bevelList_make(Object *ob) if (cu->editnurb && ob->type != OB_FONT) { ListBase *nurbs = BKE_curve_editNurbs_get(cu); nu = nurbs->first; + is_editmode = 1; } else { nu = cu->nurb.first; } - while (nu) { + for (; nu; nu = nu->next) { + + if (nu->hide && is_editmode) + continue; + /* check if we will calculate tilt data */ do_tilt = CU_DO_TILT(cu, nu); do_radius = CU_DO_RADIUS(cu, nu); /* normal display uses the radius, better just to calculate them */ @@ -2384,7 +2390,6 @@ void BKE_curve_bevelList_make(Object *ob) } } } - nu = nu->next; } /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */ diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 42389564ec0..78d7bfa5bc5 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2290,7 +2290,7 @@ static short animdata_use_time(AnimData *adt) return 0; } -static void dag_object_time_update_flags(Object *ob) +static void dag_object_time_update_flags(Scene *scene, Object *ob) { if (ob->constraints.first) { bConstraint *con; @@ -2350,6 +2350,9 @@ static void dag_object_time_update_flags(Object *ob) if (object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; if ((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA; + if (ob->rigidbody_object && BKE_scene_check_rigidbody_active(scene)) + ob->recalc |= OB_RECALC_OB; + { AnimData *adt = BKE_animdata_from_id((ID *)ob->data); Mesh *me; @@ -2434,7 +2437,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s if (do_time) { /* now if DagNode were part of base, the node->lay could be checked... */ /* we do all now, since the scene_flush checks layers and clears recalc flags even */ - dag_object_time_update_flags(ob); + dag_object_time_update_flags(scene, ob); } /* handled in next loop */ @@ -2447,7 +2450,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s for (group = bmain->group.first; group; group = group->id.next) { if (group->id.flag & LIB_DOIT) { for (go = group->gobject.first; go; go = go->next) { - dag_object_time_update_flags(go->ob); + dag_object_time_update_flags(scene, go->ob); } } } @@ -2466,7 +2469,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s /* hrmf... an exception to look at once, for invisible camera object we do it over */ if (scene->camera) - dag_object_time_update_flags(scene->camera); + dag_object_time_update_flags(scene, scene->camera); } /* and store the info in groupobject */ diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 643c7b1d972..23b0d3e6e22 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -309,10 +309,11 @@ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, i BPoint *bp; float *data; int a, len, resolu; + const int editmode = (!forRender && (cu->editnurb || cu->editfont)); nu = nubase->first; while (nu) { - if (nu->hide == 0) { + if (nu->hide == 0 || editmode == 0) { if (forRender && cu->resolu_ren != 0) resolu = cu->resolu_ren; else diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index fff51ab2a59..c92c52a7651 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1483,7 +1483,9 @@ static void dynamicPaint_setInitialColor(DynamicPaintSurface *surface) /* for vertex surface loop through tfaces and find uv color * that provides highest alpha */ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { - #pragma omp parallel for schedule(static) + struct ImagePool *pool = BKE_image_pool_new(); + + #pragma omp parallel for schedule(static) shared(pool) for (i = 0; i < numOfFaces; i++) { int numOfVert = (mface[i].v4) ? 4 : 3; float uv[3] = {0.0f}; @@ -1496,7 +1498,7 @@ static void dynamicPaint_setInitialColor(DynamicPaintSurface *surface) uv[0] = tface[i].uv[j][0] * 2.0f - 1.0f; uv[1] = tface[i].uv[j][1] * 2.0f - 1.0f; - multitex_ext_safe(tex, uv, &texres); + multitex_ext_safe(tex, uv, &texres, pool); if (texres.tin > pPoint[*vert].alpha) { copy_v3_v3(pPoint[*vert].color, &texres.tr); @@ -1504,6 +1506,7 @@ static void dynamicPaint_setInitialColor(DynamicPaintSurface *surface) } } } + BKE_image_pool_free(pool); } else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data; @@ -1529,7 +1532,7 @@ static void dynamicPaint_setInitialColor(DynamicPaintSurface *surface) uv_final[0] = uv_final[0] * 2.0f - 1.0f; uv_final[1] = uv_final[1] * 2.0f - 1.0f; - multitex_ext_safe(tex, uv_final, &texres); + multitex_ext_safe(tex, uv_final, &texres, NULL); /* apply color */ copy_v3_v3(pPoint[i].color, &texres.tr); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 91577320a9c..d41893b4335 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -69,7 +69,7 @@ extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */ -BMEditMesh *BMEdit_Create(BMesh *bm, int do_tessellate) +BMEditMesh *BMEdit_Create(BMesh *bm, const bool do_tessellate) { BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__); @@ -1410,7 +1410,7 @@ static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) normal_float_to_short_v3(vert_r->no, eve->no); vert_r->flag = BM_vert_flag_to_mflag(eve); - if (cd_vert_bweight_offset != -1) vert_r->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset); + vert_r->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0; vert_r++; } @@ -1421,7 +1421,7 @@ static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) normal_float_to_short_v3(vert_r->no, eve->no); vert_r->flag = BM_vert_flag_to_mflag(eve); - if (cd_vert_bweight_offset != -1) vert_r->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset); + vert_r->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0; vert_r++; } @@ -1445,8 +1445,8 @@ static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) edge_r->flag = BM_edge_flag_to_mflag(eed); - if (cd_edge_crease_offset != -1) edge_r->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset); - if (cd_edge_bweight_offset != -1) edge_r->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset); + edge_r->crease = (cd_edge_crease_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset) : 0; + edge_r->bweight = (cd_edge_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset) : 0; edge_r++; } @@ -1469,6 +1469,7 @@ static void emDM_copyTessFaceArray(DerivedMesh *dm, MFace *face_r) face_r->mat_nr = (unsigned char) ef->mat_nr; face_r->flag = BM_face_flag_to_mflag(ef); + face_r->edcode = 0; face_r->v1 = BM_elem_index_get(l[0]->v); face_r->v2 = BM_elem_index_get(l[1]->v); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 1f6db19ac27..1880cb42f4d 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -769,7 +769,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP mul_m4_v3(eff->ob->imat, tex_co); } - hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result); + hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL); if (hasrgb && mode==PFIELD_TEX_RGB) { force[0] = (0.5f - result->tr) * strength; @@ -780,15 +780,15 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP strength/=nabla; tex_co[0] += nabla; - multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1); + multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL); tex_co[0] -= nabla; tex_co[1] += nabla; - multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2); + multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL); tex_co[1] -= nabla; tex_co[2] += nabla; - multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3); + multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL); if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */ /* generate intensity if texture only has rgb value */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index d4634748c71..3e1e55132d8 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -962,9 +962,9 @@ makebreak: float si, co; ct = chartransdata + cu->pos; - si = (float)sin(ct->rot); - co = (float)cos(ct->rot); - + si = sinf(ct->rot); + co = cosf(ct->rot); + f = cu->editfont->textcurs[0]; f[0] = cu->fsize * (-0.1f * co + ct->xof); diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index d8c3e260399..9c265814b8f 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -51,6 +51,8 @@ #include "BLO_sys_types.h" // for intptr_t support +#include "GPU_extensions.h" + /* GLOBALS */ static GHash *gIcons = NULL; @@ -138,7 +140,10 @@ void BKE_previewimg_freefunc(void *link) MEM_freeN(prv->rect[i]); prv->rect[i] = NULL; } + if (prv->gputexture[i]) + GPU_texture_free(prv->gputexture[i]); } + MEM_freeN(prv); } } @@ -165,6 +170,7 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv) else { prv_img->rect[i] = NULL; } + prv_img->gputexture[i] = NULL; } } return prv_img; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 3be47668fb5..9086ef49e4d 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -663,7 +663,7 @@ int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_s { IDProperty *link1, *link2; - if (is_strict && BLI_countlist(&prop1->data.group) != BLI_countlist(&prop2->data.group)) + if (is_strict && prop1->len != prop2->len) return 0; for (link1 = prop1->data.group.first; link1; link1 = link1->next) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 21417386d65..82b0d231869 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2205,9 +2205,20 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) } } +#if 0 /* force reload on first use, but not for multilayer, that makes nodes and buttons in ui drawing fail */ if (ima->type != IMA_TYPE_MULTILAYER) image_free_buffers(ima); +#else + /* image buffers for non-sequence multilayer will share buffers with RenderResult, + * however sequence multilayer will own buffers. Such logic makes switching from + * single multilayer file to sequence completely instable + * since changes in nodes seems this workaround isn't needed anymore, all sockets + * are nicely detecting anyway, but freeing buffers always here makes multilayer + * sequences behave stable + */ + image_free_buffers(ima); +#endif ima->ok = 1; if (iuser) @@ -2811,6 +2822,28 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ return ibuf; } +static void image_get_fame_and_index(Image *ima, ImageUser *iuser, int *frame_r, int *index_r) +{ + int frame = 0, index = 0; + + /* see if we already have an appropriate ibuf, with image source and type */ + if (ima->source == IMA_SRC_MOVIE) { + frame = iuser ? iuser->framenr : ima->lastframe; + } + else if (ima->source == IMA_SRC_SEQUENCE) { + if (ima->type == IMA_TYPE_IMAGE) { + frame = iuser ? iuser->framenr : ima->lastframe; + } + else if (ima->type == IMA_TYPE_MULTILAYER) { + frame = iuser ? iuser->framenr : ima->lastframe; + index = iuser ? iuser->multi_index : IMA_NO_INDEX; + } + } + + *frame_r = frame; + *index_r = index; +} + static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame_r, int *index_r) { ImBuf *ibuf = NULL; @@ -2866,6 +2899,21 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame return ibuf; } +BLI_INLINE int image_quick_test(Image *ima, ImageUser *iuser) +{ + if (ima == NULL) + return FALSE; + + if (iuser) { + if (iuser->ok == 0) + return FALSE; + } + else if (ima->ok == 0) + return FALSE; + + return TRUE; +} + /* Checks optional ImageUser and verifies/creates ImBuf. * * not thread-safe, so callee should worry about thread locks @@ -2880,14 +2928,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) *lock_r = NULL; /* quick reject tests */ - if (ima == NULL) - return NULL; - - if (iuser) { - if (iuser->ok == 0) - return NULL; - } - else if (ima->ok == 0) + if (!image_quick_test(ima, iuser)) return NULL; ibuf = image_get_ibuf_threadsafe(ima, iuser, &frame, &index); @@ -3011,14 +3052,7 @@ int BKE_image_has_ibuf(Image *ima, ImageUser *iuser) ImBuf *ibuf; /* quick reject tests */ - if (ima == NULL) - return FALSE; - - if (iuser) { - if (iuser->ok == 0) - return FALSE; - } - else if (ima->ok == 0) + if (!image_quick_test(ima, iuser)) return FALSE; ibuf = image_get_ibuf_threadsafe(ima, iuser, NULL, NULL); @@ -3037,6 +3071,122 @@ int BKE_image_has_ibuf(Image *ima, ImageUser *iuser) return ibuf != NULL; } +/* ******** Pool for image buffers ******** */ + +typedef struct ImagePoolEntry { + struct ImagePoolEntry *next, *prev; + Image *image; + ImBuf *ibuf; + int index; + int frame; +} ImagePoolEntry; + +typedef struct ImagePool { + ListBase image_buffers; +} ImagePool; + +ImagePool *BKE_image_pool_new(void) +{ + ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool"); + + return pool; +} + +void BKE_image_pool_free(ImagePool *pool) +{ + ImagePoolEntry *entry, *next_entry; + + /* use single lock to dereference all the image buffers */ + BLI_spin_lock(&image_spin); + + for (entry = pool->image_buffers.first; entry; entry = next_entry) { + next_entry = entry->next; + + if (entry->ibuf) + IMB_freeImBuf(entry->ibuf); + + MEM_freeN(entry); + } + + BLI_spin_unlock(&image_spin); + + MEM_freeN(pool); +} + +BLI_INLINE ImBuf *image_pool_find_entry(ImagePool *pool, Image *image, int frame, int index, int *found) +{ + ImagePoolEntry *entry; + + *found = FALSE; + + for (entry = pool->image_buffers.first; entry; entry = entry->next) { + if (entry->image == image && entry->frame == frame && entry->index == index) { + *found = TRUE; + return entry->ibuf; + } + } + + return NULL; +} + +ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool) +{ + ImBuf *ibuf; + int index, frame, found; + + if (!image_quick_test(ima, iuser)) + return NULL; + + if (pool == NULL) { + /* pool could be NULL, in this case use general acquire function */ + return BKE_image_acquire_ibuf(ima, iuser, NULL); + } + + image_get_fame_and_index(ima, iuser, &frame, &index); + + ibuf = image_pool_find_entry(pool, ima, frame, index, &found); + if (found) + return ibuf; + + BLI_spin_lock(&image_spin); + + ibuf = image_pool_find_entry(pool, ima, frame, index, &found); + + /* will also create entry even in cases image buffer failed to load, + * prevents trying to load the same buggy file multiple times + */ + if (!found) { + ImagePoolEntry *entry; + + ibuf = image_acquire_ibuf(ima, iuser, NULL); + + if (ibuf) + IMB_refImBuf(ibuf); + + entry = MEM_callocN(sizeof(ImagePoolEntry), "Image Pool Entry"); + entry->image = ima; + entry->frame = frame; + entry->index = index; + entry->ibuf = ibuf; + + BLI_addtail(&pool->image_buffers, entry); + } + + BLI_spin_unlock(&image_spin); + + return ibuf; +} + +void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool) +{ + /* if pool wasn't actually used, use general release stuff, + * for pools image buffers will be dereferenced on pool free + */ + if (pool == NULL) { + BKE_image_release_ibuf(ima, ibuf, NULL); + } +} + int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, short *r_is_in_range) { const int len = (iuser->fie_ima * iuser->frames) / 2; @@ -3199,3 +3349,57 @@ void BKE_image_get_aspect(Image *image, float *aspx, float *aspy) else *aspy = 1.0f; } + +unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame) +{ + ImageUser iuser = {0}; + void *lock; + ImBuf *ibuf; + unsigned char *pixels = NULL; + + iuser.framenr = frame; + iuser.ok = TRUE; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf) { + pixels = (unsigned char *) ibuf->rect; + + if (pixels) + pixels = MEM_dupallocN(pixels); + + BKE_image_release_ibuf(image, ibuf, lock); + } + + if (!pixels) + return NULL; + + return pixels; +} + +float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame) +{ + ImageUser iuser = {0}; + void *lock; + ImBuf *ibuf; + float *pixels = NULL; + + iuser.framenr = frame; + iuser.ok = TRUE; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf) { + pixels = ibuf->rect_float; + + if (pixels) + pixels = MEM_dupallocN(pixels); + + BKE_image_release_ibuf(image, ibuf, lock); + } + + if (!pixels) + return NULL; + + return pixels; +} diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index ccc57a24540..803b1e68915 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -108,19 +108,6 @@ void BKE_key_free_nolib(Key *key) } -/* GS reads the memory pointed at in a specific ordering. There are, - * however two definitions for it. I have jotted them down here, both, - * but I think the first one is actually used. The thing is that - * big-endian systems might read this the wrong way round. OTOH, we - * constructed the IDs that are read out with this macro explicitly as - * well. I expect we'll sort it out soon... */ - -/* from blendef: */ -#define GS(a) (*((short *)(a))) - -/* from misc_util: flip the bytes from x */ -/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ - Key *BKE_key_add(ID *id) /* common function */ { Key *key; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 98625807ddc..610237abcdd 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -47,6 +47,7 @@ #include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_group_types.h" +#include "DNA_gpencil_types.h" #include "DNA_ipo_types.h" #include "DNA_key_types.h" #include "DNA_lamp_types.h" @@ -54,6 +55,8 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" #include "DNA_nla_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" @@ -64,51 +67,49 @@ #include "DNA_vfont_types.h" #include "DNA_windowmanager_types.h" #include "DNA_world_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_mask_types.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" #include "BLI_utildefines.h" #include "BKE_bpath.h" +#include "BKE_action.h" #include "BKE_animsys.h" +#include "BKE_armature.h" +#include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_context.h" -#include "BKE_lamp.h" -#include "BKE_library.h" -#include "BKE_main.h" -#include "BKE_global.h" -#include "BKE_sound.h" -#include "BKE_object.h" -#include "BKE_screen.h" -#include "BKE_mesh.h" -#include "BKE_material.h" #include "BKE_curve.h" -#include "BKE_mball.h" -#include "BKE_text.h" -#include "BKE_texture.h" -#include "BKE_scene.h" +#include "BKE_fcurve.h" +#include "BKE_font.h" +#include "BKE_global.h" +#include "BKE_group.h" +#include "BKE_gpencil.h" +#include "BKE_idprop.h" #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_ipo.h" #include "BKE_key.h" -#include "BKE_world.h" -#include "BKE_font.h" -#include "BKE_group.h" +#include "BKE_lamp.h" #include "BKE_lattice.h" -#include "BKE_armature.h" -#include "BKE_action.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_movieclip.h" +#include "BKE_mask.h" #include "BKE_node.h" -#include "BKE_brush.h" -#include "BKE_idprop.h" +#include "BKE_object.h" #include "BKE_particle.h" -#include "BKE_gpencil.h" -#include "BKE_fcurve.h" +#include "BKE_packedFile.h" #include "BKE_speaker.h" -#include "BKE_movieclip.h" -#include "BKE_mask.h" +#include "BKE_sound.h" +#include "BKE_screen.h" +#include "BKE_scene.h" +#include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_world.h" #ifdef WITH_FREESTYLE # include "BKE_linestyle.h" #endif @@ -125,9 +126,6 @@ * only use this definition, makes little and big endian systems * work fine, in conjunction with MAKE_ID */ -/* from blendef: */ -#define GS(a) (*((short *)(a))) - /* ************* general ************************ */ @@ -795,9 +793,10 @@ void *BKE_libblock_copy(ID *id) return idn; } -static void BKE_library_free(Library *UNUSED(lib)) +static void BKE_library_free(Library *lib) { - /* no freeing needed for libraries yet */ + if (lib->packedfile) + freePackedFile(lib->packedfile); } static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 4655dd04261..ad0a149a42c 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -684,19 +684,6 @@ Material *give_node_material(Material *ma) return NULL; } -/* GS reads the memory pointed at in a specific ordering. There are, - * however two definitions for it. I have jotted them down here, both, - * but I think the first one is actually used. The thing is that - * big-endian systems might read this the wrong way round. OTOH, we - * constructed the IDs that are read out with this macro explicitly as - * well. I expect we'll sort it out soon... */ - -/* from blendef: */ -#define GS(a) (*((short *)(a))) - -/* from misc_util: flip the bytes from x */ -/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ - void resize_object_material(Object *ob, const short totcol) { Material **newmatar; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index dec7556392f..03df0c28944 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -533,7 +533,7 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob) bm = BM_mesh_create(&bm_mesh_allocsize_default); - BM_mesh_bm_from_me(bm, me, TRUE, ob->shapenr); + BM_mesh_bm_from_me(bm, me, true, ob->shapenr); return bm; } @@ -1360,7 +1360,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, int i; for (i = 0; i < 3; i++, mloopuv++) { - mloopuv->uv[0] = (mloop[i].v - startvert)/(float)(dl->nr - 1); + mloopuv->uv[0] = (mloop[i].v - startvert) / (float)(dl->nr - 1); mloopuv->uv[1] = 0.0f; } } @@ -1430,8 +1430,8 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, /* find uv based on vertex index into grid array */ int v = mloop[i].v - startvert; - mloopuv->uv[0] = (v / dl->nr)/(float)orco_sizev; - mloopuv->uv[1] = (v % dl->nr)/(float)orco_sizeu; + mloopuv->uv[0] = (v / dl->nr) / (float)orco_sizev; + mloopuv->uv[1] = (v % dl->nr) / (float)orco_sizeu; /* cyclic correction */ if ((i == 0 || i == 1) && mloopuv->uv[1] == 0.0f) @@ -2993,6 +2993,68 @@ float BKE_mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart, } } +/** + * This function takes the difference between 2 vertex-coord-arrays + * (\a vert_cos_src, \a vert_cos_dst), + * and applies the difference to \a vert_cos_new relative to \a vert_cos_org. + * + * \param vert_cos_src reference deform source. + * \param vert_cos_dst reference deform destination. + * + * \param vert_cos_org reference for the output location. + * \param vert_cos_new resulting coords. + */ +void BKE_mesh_calc_relative_deform( + const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totvert, + + const float (*vert_cos_src)[3], + const float (*vert_cos_dst)[3], + + const float (*vert_cos_org)[3], + float (*vert_cos_new)[3]) +{ + const MPoly *mp; + int i; + + int *vert_accum = MEM_callocN(sizeof(*vert_accum) * totvert, __func__); + + memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * totvert); + + for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { + const MLoop *loopstart = mloop + mp->loopstart; + int j; + + for (j = 0; j < mp->totloop; j++) { + int v_prev = (loopstart + ((mp->totloop + (j - 1)) % mp->totloop))->v; + int v_curr = (loopstart + j)->v; + int v_next = (loopstart + ((j + 1) % mp->totloop))->v; + + float tvec[3]; + + barycentric_transform( + tvec, vert_cos_dst[v_curr], + vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next], + vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next] + ); + + add_v3_v3(vert_cos_new[v_curr], tvec); + vert_accum[v_curr] += 1; + } + } + + for (i = 0; i < totvert; i++) { + if (vert_accum[i]) { + mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]); + } + else { + copy_v3_v3(vert_cos_new[i], vert_cos_org[i]); + } + } + + MEM_freeN(vert_accum); +} + /* Find the index of the loop in 'poly' which references vertex, * returns -1 if not found */ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index b12463daf72..722e1f2b918 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1559,7 +1559,7 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp) if (S == 1) { (*out)[1] = -(*out)[1]; } else if (S == 2) { SWAP(float, (*out)[0], (*out)[1]); } else if (S == 3) { (*out)[0] = -(*out)[0]; } - else if (S == 0) { SWAP(float, (*out)[0], (*out)[1]); (*out)[0] = -(*out)[0]; (*out)[1] = -(*out)[1]; }; + else if (S == 0) { SWAP(float, (*out)[0], (*out)[1]); (*out)[0] = -(*out)[0]; (*out)[1] = -(*out)[1]; } } } } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 84e280034ed..c73bd5ef8fd 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1035,9 +1035,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) */ if (ntree->execdata) { switch (ntree->type) { - case NTREE_COMPOSIT: - ntreeCompositEndExecTree(ntree->execdata, 1); - break; case NTREE_SHADER: ntreeShaderEndExecTree(ntree->execdata, 1); break; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 5a22973164e..8a6309593f1 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -83,6 +83,7 @@ #include "BKE_fcurve.h" #include "BKE_group.h" #include "BKE_icons.h" +#include "BKE_image.h" #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" @@ -97,6 +98,7 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_property.h" +#include "BKE_rigidbody.h" #include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_sequencer.h" @@ -312,6 +314,9 @@ void free_sculptsession(Object *ob) if (ss->texcache) MEM_freeN(ss->texcache); + if (ss->tex_pool) + BKE_image_pool_free(ss->tex_pool); + if (ss->layer_co) MEM_freeN(ss->layer_co); @@ -386,6 +391,8 @@ void BKE_object_free(Object *ob) BKE_free_constraints(&ob->constraints); free_partdeflect(ob->pd); + BKE_rigidbody_free_object(ob); + BKE_rigidbody_free_constraint(ob); if (ob->soft) sbFree(ob->soft); if (ob->bsoft) bsbFree(ob->bsoft); @@ -1296,6 +1303,8 @@ static Object *object_copy_do(Object *ob, int copy_caches) } obn->soft = copy_softbody(ob->soft, copy_caches); obn->bsoft = copy_bulletsoftbody(ob->bsoft); + obn->rigidbody_object = BKE_rigidbody_copy_object(ob); + obn->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob); BKE_object_copy_particlesystems(obn, ob); @@ -2153,6 +2162,8 @@ void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime) BKE_object_to_mat4(ob, ob->obmat); } + BKE_rigidbody_sync_transforms(scene, ob, ctime); + /* solve constraints */ if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { bConstraintOb *cob; @@ -2714,8 +2725,10 @@ void BKE_object_handle_update(Scene *scene, Object *ob) case OB_ARMATURE: if (ob->id.lib && ob->proxy_from) { - // printf("pose proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); - BKE_pose_copy_result(ob->pose, ob->proxy_from->pose); + if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { + printf("Proxy copy error, lib Object: %s proxy Object: %s\n", + ob->id.name + 2, ob->proxy_from->id.name + 2); + } } else { BKE_pose_where_is(scene, ob); diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index c4274aa1f93..695ac7da792 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -35,10 +35,6 @@ #include "DNA_scene_types.h" -#include "BKE_global.h" /* XXX TESTING */ -#include "BKE_image.h" -#include "BKE_ocean.h" - #include "BLI_math.h" #include "BLI_path_util.h" #include "BLI_rand.h" @@ -46,6 +42,9 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BKE_image.h" +#include "BKE_ocean.h" + #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -1425,4 +1424,4 @@ void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), /* unused */ (void)update_cb; } -#endif /* WITH_OCEANSIM */
\ No newline at end of file +#endif /* WITH_OCEANSIM */ diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 9f77094994d..9fab052f80c 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -553,7 +553,7 @@ int unpackLibraries(Main *bmain, ReportList *reports) if (newname != NULL) { ret_value = RET_OK; - printf("Saved .blend library: %s\n", newname); + printf("Unpacked .blend library: %s\n", newname); freePackedFile(lib->packedfile); lib->packedfile = NULL; @@ -570,6 +570,16 @@ void packLibraries(Main *bmain, ReportList *reports) { Library *lib; + /* test for relativenss */ + for (lib = bmain->library.first; lib; lib = lib->id.next) + if (0 == BLI_path_is_rel(lib->name)) + break; + + if (lib) { + BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name); + return; + } + for (lib = bmain->library.first; lib; lib = lib->id.next) if (lib->packedfile == NULL) lib->packedfile = newPackedFile(reports, lib->name, bmain->name); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 5847e7508f0..dc8aed91c00 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -47,6 +47,8 @@ #include "BKE_paint.h" #include "BKE_subsurf.h" +#include "bmesh.h" + #include <stdlib.h> #include <string.h> @@ -224,6 +226,22 @@ int paint_is_grid_face_hidden(const unsigned int *grid_hidden, BLI_BITMAP_GET(grid_hidden, (y + 1) * gridsize + x)); } +/* Return TRUE if all vertices in the face are visible, FALSE otherwise */ +int paint_is_bmesh_face_hidden(BMFace *f) +{ + BMLoop *l_iter; + BMLoop *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN)) { + return true; + } + } while ((l_iter = l_iter->next) != l_first); + + return false; +} + float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, unsigned x, unsigned y) { diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b2851962b49..71854a93f4d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3849,7 +3849,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti break; } - externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0); + externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL); if ((event & mtex->mapto) & PAMAP_ROUGH) ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(def, ptex->rough1, value, mtex->roughfac, blend); @@ -3920,7 +3920,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex break; } - externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0); + externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL); if ((event & mtex->mapto) & PAMAP_TIME) { /* the first time has to set the base value for time regardless of blend mode */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 5eac86a7e77..fda5f6f2ecb 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4500,7 +4500,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) int startframe = 0, endframe = 100, oldtotpart = 0; /* cache shouldn't be used for hair or "continue physics" */ - if (part->type != PART_HAIR && BKE_ptcache_get_continue_physics() == 0) { + if (part->type != PART_HAIR) { psys_clear_temp_pointcache(psys); /* set suitable cache range automatically */ diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 2df2dd631d5..483dd2570e2 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1238,6 +1238,19 @@ PBVHType BKE_pbvh_type(const PBVH *bvh) return bvh->type; } +void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]) +{ + if (bvh->totnode) { + const BB *bb = &bvh->nodes[0].vb; + copy_v3_v3(min, bb->bmin); + copy_v3_v3(max, bb->bmax); + } + else { + zero_v3(min); + zero_v3(max); + } +} + BLI_bitmap *BKE_pbvh_grid_hidden(const PBVH *bvh) { BLI_assert(bvh->type == PBVH_GRIDS); @@ -1386,10 +1399,10 @@ void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data, } 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) + const float ray_normal[3], + const float *t0, const float *t1, + const float *t2, const float *t3, + float *fdist) { float dist; diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 791288a4dda..9a0b1a76988 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -28,6 +28,7 @@ #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_paint.h" #include "BKE_pbvh.h" #include "GPU_buffers.h" @@ -53,7 +54,8 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) GHASH_ITER (gh_iter, n->bm_faces) { BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - BMIter bm_iter; + BMLoop *l_iter; + BMLoop *l_first; BMVert *v; void *node_val = SET_INT_IN_POINTER(node_index); @@ -61,7 +63,9 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) BLI_ghash_insert(bvh->bm_face_to_node, f, node_val); /* Update vertices */ - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + v = l_iter->v; if (!BLI_ghash_haskey(n->bm_unique_verts, v)) { if (BLI_ghash_haskey(bvh->bm_vert_to_node, v)) { if (!BLI_ghash_haskey(n->bm_other_verts, v)) @@ -74,7 +78,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) } /* Update node bounding box */ BB_expand(&n->vb, v->co); - } + } while ((l_iter = l_iter->next) != l_first); } BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && @@ -233,15 +237,16 @@ static int pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) prim_bbc = BLI_ghash_ptr_new("prim_bbc"); GHASH_ITER (gh_iter, bvh->nodes[node_index].bm_faces) { - BMIter bm_iter; - BMVert *v; BMFace *f = BLI_ghashIterator_getKey(&gh_iter); BBC *bbc = MEM_callocN(sizeof(BBC), "BBC"); + BMLoop *l_iter; + BMLoop *l_first; BB_reset((BB *)bbc); - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { - BB_expand((BB *)bbc, v->co); - } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BB_expand((BB *)bbc, l_iter->v->co); + } while ((l_iter = l_iter->next) != l_first); BBC_update_centroid(bbc); BLI_ghash_insert(prim_bbc, f, bbc); @@ -286,16 +291,16 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index, return v; } -static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index, BMVert *v1, - BMVert *v2, BMVert *v3, - const BMFace *UNUSED(example)) +static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index, + BMVert *v1, BMVert *v2, BMVert *v3, + const BMFace *UNUSED(example)) { BMFace *f; void *val = SET_INT_IN_POINTER(node_index); /* Note: passing NULL for the 'example' parameter, profiling shows * a small performance bump */ - f = BM_face_create_quad_tri(bvh->bm, v1, v2, v3, NULL, NULL, TRUE); + f = BM_face_create_quad_tri(bvh->bm, v1, v2, v3, NULL, NULL, true); if (!BLI_ghash_haskey(bvh->bm_face_to_node, f)) { BLI_ghash_insert(bvh->nodes[node_index].bm_faces, f, NULL); @@ -394,14 +399,18 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) { PBVHNode *f_node; - BMIter bm_iter; BMVert *v; + BMLoop *l_iter; + BMLoop *l_first; + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); /* Check if any of this face's vertices need to be removed * from the node */ - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + v = l_iter->v; if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) { if (BLI_ghash_lookup(f_node->bm_unique_verts, v)) { /* Find a different node that uses 'v' */ @@ -419,7 +428,7 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); } } - } + } while ((l_iter = l_iter->next) != l_first); /* Remove face from node and top level */ BLI_ghash_remove(f_node->bm_faces, f, NULL, NULL); @@ -429,57 +438,20 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) BM_log_face_removed(bvh->bm_log, f); } -static BMVert *bm_triangle_other_vert_find(BMFace *triangle, const BMVert *v1, - const BMVert *v2) +static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e) { - BLI_assert(triangle->len == 3); - BLI_assert(v1 != v2); - - if (triangle->len == 3) { - BMIter iter; - BMVert *v, *other = NULL; - int found_v1 = FALSE, found_v2 = FALSE; - - BM_ITER_ELEM (v, &iter, triangle, BM_VERTS_OF_FACE) { - if (v == v1) - found_v1 = TRUE; - else if (v == v2) - found_v2 = TRUE; - else - other = v; - } - - if (found_v1 && found_v2) - return other; + /* fast-path for most common case where an edge has 2 faces, + * no need to iterate twice. + * This assumes that the buffer */ + BMLoop **data = buf->data; + BLI_assert(buf->alloc_count >= 2); + if (LIKELY(BM_edge_loop_pair(e, &data[0], &data[1]))) { + buf->count = 2; } - - BLI_assert(0); - return NULL; -} - -static void pbvh_bmesh_edge_faces(BLI_Buffer *buf, BMEdge *e) -{ - BLI_buffer_resize(buf, BM_edge_face_count(e)); - BM_iter_as_array(NULL, BM_FACES_OF_EDGE, e, buf->data, buf->count); -} - -/* TODO: maybe a better way to do this, if not then this should go to - * bmesh_queries */ -static int bm_face_edge_backwards(BMFace *f, BMEdge *e) -{ - BMIter bm_iter; - BMLoop *l, *l1 = NULL, *l2 = NULL; - - BM_ITER_ELEM (l, &bm_iter, f, BM_LOOPS_OF_FACE) { - if (l->v == e->v1) - l1 = l; - else if (l->v == e->v2) - l2 = l; + else { + BLI_buffer_resize(buf, BM_edge_face_count(e)); + BM_iter_as_array(NULL, BM_LOOPS_OF_EDGE, e, buf->data, buf->count); } - - BLI_assert(l1 && l2); - BLI_assert(l1->next == l2 || l2->next == l1); - return l2->next == l1; } static void pbvh_bmesh_node_drop_orig(PBVHNode *node) @@ -504,12 +476,14 @@ typedef struct { static int edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) { - BMVert *v[3]; + BMVert *v_tri[3]; float c[3]; /* Get closest point in triangle to sphere center */ - BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); - closest_on_tri_to_point_v3(c, q->center, v[0]->co, v[1]->co, v[2]->co); + // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3); + BM_face_as_array_vert_tri(f, v_tri); + + closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); /* Check if triangle intersects the sphere */ return ((len_squared_v3v3(q->center, c) <= q->radius_squared)); @@ -542,36 +516,34 @@ static void short_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, edge_queue_insert(q, pool, e, len_sq); } -static int long_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, - BMFace *f) +static void long_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, + BMFace *f) { - BMIter bm_iter; - BMEdge *e; - if (edge_queue_tri_in_sphere(q, f)) { + BMLoop *l_iter; + BMLoop *l_first; + /* Check each edge of the face */ - BM_ITER_ELEM (e, &bm_iter, f, BM_EDGES_OF_FACE) { - long_edge_queue_edge_add(q, pool, e); - } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + long_edge_queue_edge_add(q, pool, l_iter->e); + } while ((l_iter = l_iter->next) != l_first); } - - return TRUE; } -static int short_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, - BMFace *f) +static void short_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, + BMFace *f) { - BMIter bm_iter; - BMEdge *e; - if (edge_queue_tri_in_sphere(q, f)) { + BMLoop *l_iter; + BMLoop *l_first; + /* Check each edge of the face */ - BM_ITER_ELEM (e, &bm_iter, f, BM_EDGES_OF_FACE) { - short_edge_queue_edge_add(q, pool, e); - } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + short_edge_queue_edge_add(q, pool, l_iter->e); + } while ((l_iter = l_iter->next) != l_first); } - - return TRUE; } /* Create a priority queue containing vertex pairs connected by a long @@ -655,25 +627,26 @@ static void short_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, /*************************** Topology update **************************/ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, - BMEdge *e, BLI_Buffer *edge_faces) + BMEdge *e, BLI_Buffer *edge_loops) { BMVert *v_new; float mid[3]; int i, node_index; /* Get all faces adjacent to the edge */ - pbvh_bmesh_edge_faces(edge_faces, e); + pbvh_bmesh_edge_loops(edge_loops, e); /* Create a new vertex in current node at the edge's midpoint */ mid_v3_v3v3(mid, e->v1->co, e->v2->co); node_index = GET_INT_FROM_POINTER(BLI_ghash_lookup(bvh->bm_vert_to_node, - e->v1)); + e->v1)); v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1); /* For each face, add two new triangles and delete the original */ - for (i = 0; i < edge_faces->count; i++) { - BMFace *f_adj = BLI_buffer_at(edge_faces, BMFace *, i); + for (i = 0; i < edge_loops->count; i++) { + BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i); + BMFace *f_adj = l_adj->f; BMFace *f_new; BMVert *opp, *v1, *v2; void *nip; @@ -687,15 +660,13 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, bvh->nodes[ni].flag |= PBVH_UpdateDrawBuffers; /* Find the vertex not in the edge */ - opp = bm_triangle_other_vert_find(f_adj, e->v1, e->v2); + opp = l_adj->prev->v; /* Get e->v1 and e->v2 in the order they appear in the * existing face so that the new faces' winding orders * match */ - v1 = e->v1; - v2 = e->v2; - if (bm_face_edge_backwards(f_adj, e)) - SWAP(BMVert *, v1, v2); + v1 = l_adj->v; + v2 = l_adj->next->v; if (ni != node_index && i == 0) pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new); @@ -731,8 +702,8 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, } static int pbvh_bmesh_subdivide_long_edges(PBVH *bvh, EdgeQueue *q, - BLI_mempool *pool, - BLI_Buffer *edge_faces) + BLI_mempool *pool, + BLI_Buffer *edge_loops) { int any_subdivided = FALSE; @@ -764,30 +735,31 @@ static int pbvh_bmesh_subdivide_long_edges(PBVH *bvh, EdgeQueue *q, any_subdivided = TRUE; - pbvh_bmesh_split_edge(bvh, q, pool, e, edge_faces); + pbvh_bmesh_split_edge(bvh, q, pool, e, edge_loops); } return any_subdivided; } static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, - BMVert *v2, GHash *deleted_verts, - BLI_Buffer *edge_faces, - BLI_Buffer *deleted_faces) + BMVert *v2, GHash *deleted_verts, + BLI_Buffer *edge_loops, + BLI_Buffer *deleted_faces) { BMIter bm_iter; BMFace *f; int i; /* Get all faces adjacent to the edge */ - pbvh_bmesh_edge_faces(edge_faces, e); + pbvh_bmesh_edge_loops(edge_loops, e); /* Remove the merge vertex from the PBVH */ pbvh_bmesh_vert_remove(bvh, v2); /* Remove all faces adjacent to the edge */ - for (i = 0; i < edge_faces->count; i++) { - BMFace *f_adj = BLI_buffer_at(edge_faces, BMFace *, i); + for (i = 0; i < edge_loops->count; i++) { + BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i); + BMFace *f_adj = l_adj->f; pbvh_bmesh_face_remove(bvh, f_adj); BM_face_kill(bvh->bm, f_adj); @@ -804,30 +776,32 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, * really buy anything. */ deleted_faces->count = 0; BM_ITER_ELEM (f, &bm_iter, v2, BM_FACES_OF_VERT) { - BMVert *v[3]; + BMVert *v_tri[3]; BMFace *existing_face; PBVHNode *n; int ni; /* Get vertices, replace use of v2 with v1 */ - BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3); + BM_face_as_array_vert_tri(f, v_tri); for (i = 0; i < 3; i++) { - if (v[i] == v2) - v[i] = v1; + if (v_tri[i] == v2) { + v_tri[i] = v1; + } } /* Check if a face using these vertices already exists. If so, * skip adding this face and mark the existing one for * deletion as well. Prevents extraneous "flaps" from being * created. */ - if (BM_face_exists(v, 3, &existing_face)) { + if (BM_face_exists(v_tri, 3, &existing_face)) { BLI_assert(existing_face); BLI_buffer_append(deleted_faces, BMFace *, existing_face); } else { n = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); ni = n - bvh->nodes; - pbvh_bmesh_face_create(bvh, ni, v[0], v[1], v[2], f); + pbvh_bmesh_face_create(bvh, ni, v_tri[0], v_tri[1], v_tri[2], f); /* Ensure that v1 is in the new face's node */ if (!BLI_ghash_haskey(n->bm_unique_verts, v1) && @@ -842,20 +816,24 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, /* Delete the tagged faces */ for (i = 0; i < deleted_faces->count; i++) { BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i); - BMVert *v[3]; + BMVert *v_tri[3]; + BMEdge *e_tri[3]; int j; - BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f_del, (void **)v, 3); + /* Get vertices and edges of face */ + BM_face_as_array_vert_tri(f_del, v_tri); + for (j = 0; j < 3; j++) + e_tri[j] = BM_edge_exists(v_tri[j], v_tri[j == 2 ? 0 : j + 1]); /* Check if any of the face's vertices are now unused, if so - remove them from the PBVH */ + * remove them from the PBVH */ for (j = 0; j < 3; j++) { - if (v[j] != v2 && BM_vert_face_count(v[j]) == 0) { - BLI_ghash_insert(deleted_verts, v[j], NULL); - pbvh_bmesh_vert_remove(bvh, v[j]); + if (v_tri[j] != v2 && BM_vert_face_count(v_tri[j]) == 1) { + BLI_ghash_insert(deleted_verts, v_tri[j], NULL); + pbvh_bmesh_vert_remove(bvh, v_tri[j]); } else { - v[j] = NULL; + v_tri[j] = NULL; } } @@ -863,18 +841,28 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, pbvh_bmesh_face_remove(bvh, f_del); BM_face_kill(bvh->bm, f_del); + /* Check if any of the face's edges are now unused by any + * face, if so delete them */ + for (j = 0; j < 3; j++) { + if (BM_edge_face_count(e_tri[j]) == 0) + BM_edge_kill(bvh->bm, e_tri[j]); + } + /* Delete unused vertices */ for (j = 0; j < 3; j++) { - if (v[j]) { - BM_log_vert_removed(bvh->bm, bvh->bm_log, v[j]); - BM_vert_kill(bvh->bm, v[j]); + if (v_tri[j]) { + BM_log_vert_removed(bvh->bm, bvh->bm_log, v_tri[j]); + BM_vert_kill(bvh->bm, v_tri[j]); } } } - /* Move v1 to the midpoint of v1 and v2 */ - BM_log_vert_before_modified(bvh->bm, bvh->bm_log, v1); - mid_v3_v3v3(v1->co, v1->co, v2->co); + /* Move v1 to the midpoint of v1 and v2 (if v1 still exists, it + * may have been deleted above) */ + if (!BLI_ghash_haskey(deleted_verts, v1)) { + BM_log_vert_before_modified(bvh->bm, bvh->bm_log, v1); + mid_v3_v3v3(v1->co, v1->co, v2->co); + } /* Delete v2 */ BLI_assert(BM_vert_face_count(v2) == 0); @@ -884,9 +872,9 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, } static int pbvh_bmesh_collapse_short_edges(PBVH *bvh, EdgeQueue *q, - BLI_mempool *pool, - BLI_Buffer *edge_faces, - BLI_Buffer *deleted_faces) + BLI_mempool *pool, + BLI_Buffer *edge_loops, + BLI_Buffer *deleted_faces) { float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; GHash *deleted_verts; @@ -928,8 +916,8 @@ static int pbvh_bmesh_collapse_short_edges(PBVH *bvh, EdgeQueue *q, any_collapsed = TRUE; pbvh_bmesh_collapse_edge(bvh, e, v1, v2, - deleted_verts, edge_faces, - deleted_faces); + deleted_verts, edge_loops, + deleted_faces); } BLI_ghash_free(deleted_verts, NULL, NULL); @@ -962,15 +950,15 @@ int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], BMFace *f = BLI_ghashIterator_getKey(&gh_iter); BLI_assert(f->len == 3); - if (f->len == 3) { - BMVert *v[3]; + if (f->len == 3 && !paint_is_bmesh_face_hidden(f)) { + BMVert *v_tri[3]; - BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + BM_face_as_array_vert_tri(f, v_tri); hit |= ray_face_intersection(ray_start, ray_normal, - v[0]->co, - v[1]->co, - v[2]->co, - NULL, dist); + v_tri[0]->co, + v_tri[1]->co, + v_tri[2]->co, + NULL, dist); } } } @@ -1038,9 +1026,10 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, int smooth_shading, /* Collapse short edges, subdivide long edges */ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, - const float center[3], float radius) + const float center[3], float radius) { - BLI_buffer_declare_static(BMFace *, edge_faces, BLI_BUFFER_NOP, 8); + /* 2 is enough for edge faces - manifold edge */ + BLI_buffer_declare_static(BMFace *, edge_loops, BLI_BUFFER_NOP, 2); BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); int modified = FALSE; @@ -1049,10 +1038,10 @@ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, if (mode & PBVH_Collapse) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, - 128, 128, 0); + 128, 128, 0); short_edge_queue_create(&q, queue_pool, bvh, center, radius); - pbvh_bmesh_collapse_short_edges(bvh, &q, queue_pool, &edge_faces, - &deleted_faces); + pbvh_bmesh_collapse_short_edges(bvh, &q, queue_pool, &edge_loops, + &deleted_faces); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } @@ -1060,9 +1049,9 @@ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, if (mode & PBVH_Subdivide) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, - 128, 128, 0); + 128, 128, 0); long_edge_queue_create(&q, queue_pool, bvh, center, radius); - pbvh_bmesh_subdivide_long_edges(bvh, &q, queue_pool, &edge_faces); + pbvh_bmesh_subdivide_long_edges(bvh, &q, queue_pool, &edge_loops); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } @@ -1077,14 +1066,27 @@ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, node->flag &= ~PBVH_UpdateTopology; } } - BLI_buffer_free(&edge_faces); + BLI_buffer_free(&edge_loops); BLI_buffer_free(&deleted_faces); return modified; } +BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) +{ + BMLoop *l = BM_FACE_FIRST_LOOP(f); + + BLI_assert(f->len == 3); + + r_index[0] = BM_elem_index_get(l->v); l = l->next; + r_index[1] = BM_elem_index_get(l->v); l = l->next; + r_index[2] = BM_elem_index_get(l->v); +} + /* In order to perform operations on the original node coordinates - * (such as raycast), store the node's triangles and vertices.*/ + * (currently just raycast), store the node's triangles and vertices. + * + * Skips triangles that are hidden. */ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) { GHashIterator gh_iter; @@ -1120,15 +1122,22 @@ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) /* Copy the triangles */ i = 0; GHASH_ITER (gh_iter, node->bm_faces) { - BMIter bm_iter; BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + if (paint_is_bmesh_face_hidden(f)) + continue; + +#if 0 + BMIter bm_iter; BMVert *v; int j = 0; - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { node->bm_ortri[i][j] = BM_elem_index_get(v); j++; } +#else + bm_face_as_array_index_tri(f, node->bm_ortri[i]); +#endif i++; } node->bm_tot_ortri = i; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 97948683e22..ef096adc7a7 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -43,6 +43,7 @@ #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_particle_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_smoke_types.h" @@ -72,6 +73,10 @@ #include "BIK_api.h" +#ifdef WITH_BULLET +# include "RBI_api.h" +#endif + /* both in intern */ #ifdef WITH_SMOKE #include "smoke_API.h" @@ -308,8 +313,9 @@ static void ptcache_particle_read(int index, void *psys_v, void **data, float cf pa->lifetime = times[2]; } - if (boid) + if (boid) { PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data); + } /* determine velocity from previous location */ if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) { @@ -866,6 +872,97 @@ static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v) return 1; } +/* Rigid Body functions */ +static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSED(cfra)) +{ + RigidBodyWorld *rbw = rb_v; + Object *ob = NULL; + + if (rbw->objects) + ob = rbw->objects[index]; + + if (ob && ob->rigidbody_object) { + RigidBodyOb *rbo = ob->rigidbody_object; + + if (rbo->type == RBO_TYPE_ACTIVE) { +#ifdef WITH_BULLET + RB_body_get_position(rbo->physics_object, rbo->pos); + RB_body_get_orientation(rbo->physics_object, rbo->orn); +#endif + PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos); + PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn); + } + } + + return 1; +} +static void ptcache_rigidbody_read(int index, void *rb_v, void **data, float UNUSED(cfra), float *old_data) +{ + RigidBodyWorld *rbw = rb_v; + Object *ob = NULL; + + if (rbw->objects) + ob = rbw->objects[index]; + + if (ob && ob->rigidbody_object) { + RigidBodyOb *rbo = ob->rigidbody_object; + + if (rbo->type == RBO_TYPE_ACTIVE) { + + if (old_data) { + memcpy(rbo->pos, data, 3 * sizeof(float)); + memcpy(rbo->orn, data + 3, 4 * sizeof(float)); + } + else { + PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, rbo->pos); + PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, 0, rbo->orn); + } + } + } +} +static void ptcache_rigidbody_interpolate(int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, float *old_data) +{ + RigidBodyWorld *rbw = rb_v; + Object *ob = NULL; + ParticleKey keys[4]; + float dfra; + + if (rbw->objects) + ob = rbw->objects[index]; + + if (ob && ob->rigidbody_object) { + RigidBodyOb *rbo = ob->rigidbody_object; + + if (rbo->type == RBO_TYPE_ACTIVE) { + + copy_v3_v3(keys[1].co, rbo->pos); + copy_v3_v3(keys[1].rot, rbo->orn); + + if (old_data) { + memcpy(keys[2].co, data, 3 * sizeof(float)); + memcpy(keys[2].rot, data + 3, 4 * sizeof(float)); + } + else { + BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2); + } + + dfra = cfra2 - cfra1; + + psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1); + interp_qt_qtqt(keys->rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra); + + copy_v3_v3(rbo->pos, keys->co); + copy_v3_v3(rbo->orn, keys->rot); + } + } +} +static int ptcache_rigidbody_totpoint(void *rb_v, int UNUSED(cfra)) +{ + RigidBodyWorld *rbw = rb_v; + + return rbw->numbodies; +} + /* Creating ID's */ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) { @@ -1071,6 +1168,42 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu pid->max_step = 1; } +void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw) +{ + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->calldata= rbw; + pid->type= PTCACHE_TYPE_RIGIDBODY; + pid->cache= rbw->pointcache; + pid->cache_ptr= &rbw->pointcache; + pid->ptcaches= &rbw->ptcaches; + pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint; + + pid->write_point = ptcache_rigidbody_write; + pid->read_point = ptcache_rigidbody_read; + pid->interpolate_point = ptcache_rigidbody_interpolate; + + pid->write_stream = NULL; + pid->read_stream = NULL; + + pid->write_extra_data = NULL; + pid->read_extra_data = NULL; + pid->interpolate_extra_data = NULL; + + pid->write_header = ptcache_basic_header_write; + pid->read_header = ptcache_basic_header_read; + + pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_ROTATION); + pid->info_types= 0; + + pid->stack_index = pid->cache->index; + + pid->default_step = 1; + pid->max_step = 1; +} + void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis) { PTCacheID *pid; @@ -1132,6 +1265,12 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup } } } + + if (scene && ob->rigidbody_object && scene->rigidbody_world) { + pid = MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_rigidbody(pid, ob, scene->rigidbody_world); + BLI_addtail(lb, pid); + } if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) { ListBase *lb_dupli_ob; @@ -2535,7 +2674,7 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode) after= 0; if (mode == PTCACHE_RESET_DEPSGRAPH) { - if (!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) { + if (!(cache->flag & PTCACHE_BAKED)) { after= 1; } @@ -2543,12 +2682,7 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode) cache->flag |= PTCACHE_OUTDATED; } else if (mode == PTCACHE_RESET_BAKED) { - if (!BKE_ptcache_get_continue_physics()) { - reset= 1; - clear= 1; - } - else - cache->flag |= PTCACHE_OUTDATED; + cache->flag |= PTCACHE_OUTDATED; } else if (mode == PTCACHE_RESET_OUTDATED) { reset = 1; @@ -2645,6 +2779,14 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) } } + if (scene->rigidbody_world && (ob->rigidbody_object || ob->rigidbody_constraint)) { + if (ob->rigidbody_object) + ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_RESHAPE; + BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world); + /* only flag as outdated, resetting should happen on start frame */ + pid.cache->flag |= PTCACHE_OUTDATED; + } + if (ob->type == OB_ARMATURE) BIK_clear_cache(ob->pose); @@ -2694,30 +2836,6 @@ void BKE_ptcache_remove(void) } } -/* Continuous Interaction */ - -static int CONTINUE_PHYSICS = 0; - -void BKE_ptcache_set_continue_physics(Main *bmain, Scene *scene, int enable) -{ - Object *ob; - - if (CONTINUE_PHYSICS != enable) { - CONTINUE_PHYSICS = enable; - - if (CONTINUE_PHYSICS == 0) { - for (ob=bmain->object.first; ob; ob=ob->id.next) - if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED)) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - } -} - -int BKE_ptcache_get_continue_physics(void) -{ - return CONTINUE_PHYSICS; -} - /* Point Cache handling */ PointCache *BKE_ptcache_add(ListBase *ptcaches) diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c new file mode 100644 index 00000000000..7cab0d7471f --- /dev/null +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -0,0 +1,1302 @@ +/* + * ***** 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) 2013 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file rigidbody.c + * \ingroup blenkernel + * \brief Blender-side interface and methods for dealing with Rigid Body simulations + */ + +#include <stdio.h> +#include <string.h> +#include <stddef.h> +#include <float.h> +#include <math.h> +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#ifdef WITH_BULLET +# include "RBI_api.h" +#endif + +#include "DNA_anim_types.h" +#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_rigidbody_types.h" +#include "DNA_scene_types.h" + +#include "BKE_animsys.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_effect.h" +#include "BKE_group.h" +#include "BKE_object.h" +#include "BKE_mesh.h" +#include "BKE_pointcache.h" +#include "BKE_rigidbody.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" + +#ifdef WITH_BULLET + +/* ************************************** */ +/* Memory Management */ + +/* Freeing Methods --------------------- */ + +/* Free rigidbody world */ +void BKE_rigidbody_free_world(RigidBodyWorld *rbw) +{ + /* sanity check */ + if (!rbw) + return; + + if (rbw->physics_world) { + /* free physics references, we assume that all physics objects in will have been added to the world */ + GroupObject *go; + if (rbw->constraints) { + for (go = rbw->constraints->gobject.first; go; go = go->next) { + if (go->ob && go->ob->rigidbody_constraint) { + RigidBodyCon *rbc = go->ob->rigidbody_constraint; + + if (rbc->physics_constraint) + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } + } + } + if (rbw->group) { + for (go = rbw->group->gobject.first; go; go = go->next) { + if (go->ob && go->ob->rigidbody_object) { + RigidBodyOb *rbo = go->ob->rigidbody_object; + + if (rbo->physics_object) + RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + } + } + } + /* free dynamics world */ + RB_dworld_delete(rbw->physics_world); + } + if (rbw->objects) + free(rbw->objects); + + /* free cache */ + BKE_ptcache_free_list(&(rbw->ptcaches)); + rbw->pointcache = NULL; + + /* free effector weights */ + if (rbw->effector_weights) + MEM_freeN(rbw->effector_weights); + + /* free rigidbody world itself */ + MEM_freeN(rbw); +} + +/* Free RigidBody settings and sim instances */ +void BKE_rigidbody_free_object(Object *ob) +{ + RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL; + + /* sanity check */ + if (rbo == NULL) + return; + + /* free physics references */ + if (rbo->physics_object) { + RB_body_delete(rbo->physics_object); + rbo->physics_object = NULL; + } + + if (rbo->physics_shape) { + RB_shape_delete(rbo->physics_shape); + rbo->physics_shape = NULL; + } + + /* free data itself */ + MEM_freeN(rbo); + ob->rigidbody_object = NULL; +} + +/* Free RigidBody constraint and sim instance */ +void BKE_rigidbody_free_constraint(Object *ob) +{ + RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL; + + /* sanity check */ + if (rbc == NULL) + return; + + /* free physics reference */ + if (rbc->physics_constraint) { + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + + /* free data itself */ + MEM_freeN(rbc); + ob->rigidbody_constraint = NULL; +} + +/* Copying Methods --------------------- */ + +/* These just copy the data, clearing out references to physics objects. + * Anything that uses them MUST verify that the copied object will + * be added to relevant groups later... + */ + +RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) +{ + RigidBodyOb *rboN = NULL; + + if (ob->rigidbody_object) { + /* just duplicate the whole struct first (to catch all the settings) */ + rboN = MEM_dupallocN(ob->rigidbody_object); + + /* tag object as needing to be verified */ + rboN->flag |= RBO_FLAG_NEEDS_VALIDATE; + + /* clear out all the fields which need to be revalidated later */ + rboN->physics_object = NULL; + rboN->physics_shape = NULL; + } + + /* return new copy of settings */ + return rboN; +} + +RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) +{ + RigidBodyCon *rbcN = NULL; + + if (ob->rigidbody_constraint) { + /* just duplicate the whole struct first (to catch all the settings) */ + rbcN = MEM_dupallocN(ob->rigidbody_constraint); + + // RB_TODO be more clever about copying constrained objects + + /* tag object as needing to be verified */ + rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE; + + /* clear out all the fields which need to be revalidated later */ + rbcN->physics_constraint = NULL; + } + + /* return new copy of settings */ + return rbcN; +} + +/* ************************************** */ +/* Setup Utilities - Validate Sim Instances */ + +/* create collision shape of mesh - convex hull */ +static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed) +{ + rbCollisionShape *shape = NULL; + Mesh *me = NULL; + + if (ob->type == OB_MESH && ob->data) { + me = ob->data; + } + else { + printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n"); + } + + if (me && me->totvert) { + shape = RB_shape_new_convex_hull((float *)me->mvert, sizeof(MVert), me->totvert, margin, can_embed); + } + else { + printf("ERROR: no vertices to define Convex Hull collision shape with\n"); + } + + return shape; +} + +/* create collision shape of mesh - triangulated mesh + * returns NULL if creation fails. + */ +static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) +{ + rbCollisionShape *shape = NULL; + + if (ob->type == OB_MESH) { + DerivedMesh *dm = CDDM_from_mesh(ob->data, ob); + + MVert *mvert; + MFace *mface; + int totvert; + int totface; + + /* ensure mesh validity, then grab data */ + DM_ensure_tessface(dm); + + mvert = (dm) ? dm->getVertArray(dm) : NULL; + totvert = (dm) ? dm->getNumVerts(dm) : 0; + mface = (dm) ? dm->getTessFaceArray(dm) : NULL; + totface = (dm) ? dm->getNumTessFaces(dm) : 0; + + /* sanity checking - potential case when no data will be present */ + if ((totvert == 0) || (totface == 0)) { + printf("WARNING: no geometry data converted for Mesh Collision Shape (ob = %s)\n", ob->id.name + 2); + } + else { + rbMeshData *mdata; + int i; + + /* init mesh data for collision shape */ + mdata = RB_trimesh_data_new(); + + /* loop over all faces, adding them as triangles to the collision shape + * (so for some faces, more than triangle will get added) + */ + for (i = 0; (i < totface) && (mface) && (mvert); i++, mface++) { + /* add first triangle - verts 1,2,3 */ + { + MVert *va = (IN_RANGE(mface->v1, 0, totvert)) ? (mvert + mface->v1) : (mvert); + MVert *vb = (IN_RANGE(mface->v2, 0, totvert)) ? (mvert + mface->v2) : (mvert); + MVert *vc = (IN_RANGE(mface->v3, 0, totvert)) ? (mvert + mface->v3) : (mvert); + + RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co); + } + + /* add second triangle if needed - verts 1,3,4 */ + if (mface->v4) { + MVert *va = (IN_RANGE(mface->v1, 0, totvert)) ? (mvert + mface->v1) : (mvert); + MVert *vb = (IN_RANGE(mface->v3, 0, totvert)) ? (mvert + mface->v3) : (mvert); + MVert *vc = (IN_RANGE(mface->v4, 0, totvert)) ? (mvert + mface->v4) : (mvert); + + RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co); + } + } + + /* construct collision shape + * + * These have been chosen to get better speed/accuracy tradeoffs with regards + * to limitations of each: + * - BVH-Triangle Mesh: for passive objects only. Despite having greater + * speed/accuracy, they cannot be used for moving objects. + * - GImpact Mesh: for active objects. These are slower and less stable, + * but are more flexible for general usage. + */ + if (ob->rigidbody_object->type == RBO_TYPE_PASSIVE) { + shape = RB_shape_new_trimesh(mdata); + } + else { + shape = RB_shape_new_gimpact_mesh(mdata); + } + } + + /* cleanup temp data */ + if (dm) { + dm->release(dm); + } + } + else { + printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n"); + } + + return shape; +} + +/* Create new physics sim collision shape for object and store it, + * or remove the existing one first and replace... + */ +void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild) +{ + RigidBodyOb *rbo = ob->rigidbody_object; + rbCollisionShape *new_shape = NULL; + BoundBox *bb = NULL; + float size[3] = {1.0f, 1.0f, 1.0f}; + float radius = 1.0f; + float height = 1.0f; + float capsule_height; + float hull_margin = 0.0f; + bool can_embed = true; + + /* sanity check */ + if (rbo == NULL) + return; + + /* don't create a new shape if we already have one and don't want to rebuild it */ + if (rbo->physics_shape && !rebuild) + return; + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralised in boundbox) + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + /* get object dimensions without scaling */ + bb = BKE_object_boundbox_get(ob); + if (bb) { + size[0] = (bb->vec[4][0] - bb->vec[0][0]); + size[1] = (bb->vec[2][1] - bb->vec[0][1]); + size[2] = (bb->vec[1][2] - bb->vec[0][2]); + } + mul_v3_fl(size, 0.5f); + + if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + /* take radius as largest x/y dimension, and height as z-dimension */ + radius = MAX2(size[0], size[1]); + height = size[2]; + } + else if (rbo->shape == RB_SHAPE_SPHERE) { + /* take radius to the the largest dimension to try and encompass everything */ + radius = MAX3(size[0], size[1], size[2]); + } + + /* create new shape */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + new_shape = RB_shape_new_box(size[0], size[1], size[2]); + break; + + case RB_SHAPE_SPHERE: + new_shape = RB_shape_new_sphere(radius); + break; + + case RB_SHAPE_CAPSULE: + capsule_height = (height - radius) * 2.0f; + new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f); + break; + case RB_SHAPE_CYLINDER: + new_shape = RB_shape_new_cylinder(radius, height); + break; + case RB_SHAPE_CONE: + new_shape = RB_shape_new_cone(radius, height * 2.0f); + break; + + case RB_SHAPE_CONVEXH: + /* try to emged collision margin */ + if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) + hull_margin = 0.04f; + new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed); + if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) + rbo->margin = (can_embed) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */ + break; + case RB_SHAPE_TRIMESH: + new_shape = rigidbody_get_shape_trimesh_from_mesh(ob); + break; + } + /* assign new collision shape if creation was successful */ + if (new_shape) { + if (rbo->physics_shape) + RB_shape_delete(rbo->physics_shape); + rbo->physics_shape = new_shape; + RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo)); + } +} + +/* --------------------- */ + +/* Create physics sim representation of object given RigidBody settings + * < rebuild: even if an instance already exists, replace it + */ +void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short rebuild) +{ + RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL; + float loc[3]; + float rot[4]; + + /* sanity checks: + * - object doesn't have RigidBody info already: then why is it here? + */ + if (rbo == NULL) + return; + + /* make sure collision shape exists */ + /* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */ + if (rbo->physics_shape == NULL || rebuild) + BKE_rigidbody_validate_sim_shape(ob, true); + + if (rbo->physics_object) { + if (rebuild == false) + RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + } + if (!rbo->physics_object || rebuild) { + /* remove rigid body if it already exists before creating a new one */ + if (rbo->physics_object) { + RB_body_delete(rbo->physics_object); + } + + mat4_to_loc_quat(loc, rot, ob->obmat); + + rbo->physics_object = RB_body_new(rbo->physics_shape, loc, rot); + + RB_body_set_friction(rbo->physics_object, rbo->friction); + RB_body_set_restitution(rbo->physics_object, rbo->restitution); + + RB_body_set_damping(rbo->physics_object, rbo->lin_damping, rbo->ang_damping); + RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh); + RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION); + + if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED) + RB_body_deactivate(rbo->physics_object); + + + RB_body_set_linear_factor(rbo->physics_object, + (ob->protectflag & OB_LOCK_LOCX) == 0, + (ob->protectflag & OB_LOCK_LOCY) == 0, + (ob->protectflag & OB_LOCK_LOCZ) == 0); + RB_body_set_angular_factor(rbo->physics_object, + (ob->protectflag & OB_LOCK_ROTX) == 0, + (ob->protectflag & OB_LOCK_ROTY) == 0, + (ob->protectflag & OB_LOCK_ROTZ) == 0); + + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); + RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + } + + if (rbw && rbw->physics_world) + RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups); +} + +/* --------------------- */ + +/* Create physics sim representation of constraint given rigid body constraint settings + * < rebuild: even if an instance already exists, replace it + */ +void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, short rebuild) +{ + RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL; + float loc[3]; + float rot[4]; + float lin_lower; + float lin_upper; + float ang_lower; + float ang_upper; + + /* sanity checks: + * - object should have a rigid body constraint + * - rigid body constraint should have at least one constrained object + */ + if (rbc == NULL) { + return; + } + + if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { + if (rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + return; + } + + if (rbc->physics_constraint) { + if (rebuild == false) + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } + if (rbc->physics_constraint == NULL || rebuild) { + rbRigidBody *rb1 = rbc->ob1->rigidbody_object->physics_object; + rbRigidBody *rb2 = rbc->ob2->rigidbody_object->physics_object; + + /* remove constraint if it already exists before creating a new one */ + if (rbc->physics_constraint) { + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + + mat4_to_loc_quat(loc, rot, ob->obmat); + + if (rb1 && rb2) { + switch (rbc->type) { + case RBC_TYPE_POINT: + rbc->physics_constraint = RB_constraint_new_point(loc, rb1, rb2); + break; + case RBC_TYPE_FIXED: + rbc->physics_constraint = RB_constraint_new_fixed(loc, rot, rb1, rb2); + break; + case RBC_TYPE_HINGE: + rbc->physics_constraint = RB_constraint_new_hinge(loc, rot, rb1, rb2); + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) { + RB_constraint_set_limits_hinge(rbc->physics_constraint, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + } + else + RB_constraint_set_limits_hinge(rbc->physics_constraint, 0.0f, -1.0f); + break; + case RBC_TYPE_SLIDER: + rbc->physics_constraint = RB_constraint_new_slider(loc, rot, rb1, rb2); + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + RB_constraint_set_limits_slider(rbc->physics_constraint, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + RB_constraint_set_limits_slider(rbc->physics_constraint, 0.0f, -1.0f); + break; + case RBC_TYPE_PISTON: + rbc->physics_constraint = RB_constraint_new_piston(loc, rot, rb1, rb2); + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) { + lin_lower = rbc->limit_lin_x_lower; + lin_upper = rbc->limit_lin_x_upper; + } + else { + lin_lower = 0.0f; + lin_upper = -1.0f; + } + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) { + ang_lower = rbc->limit_ang_x_lower; + ang_upper = rbc->limit_ang_x_upper; + } + else { + ang_lower = 0.0f; + ang_upper = -1.0f; + } + RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper); + break; + case RBC_TYPE_6DOF_SPRING: + rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); + + RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); + /* fall through */ + case RBC_TYPE_6DOF: + if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */ + rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); + break; + } + } + + RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED); + + if (rbc->flag & RBC_FLAG_USE_BREAKING) + RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold); + else + RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX); + + if (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS) + RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations); + else + RB_constraint_set_solver_iterations(rbc->physics_constraint, -1); + } + + if (rbw && rbw->physics_world && rbc->physics_constraint) { + RB_dworld_add_constraint(rbw->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS); + } +} + +/* --------------------- */ + +/* Create physics sim world given RigidBody world settings */ +// NOTE: this does NOT update object references that the scene uses, in case those aren't ready yet! +void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, short rebuild) +{ + /* sanity checks */ + if (rbw == NULL) + return; + + /* create new sim world */ + if (rebuild || rbw->physics_world == NULL) { + if (rbw->physics_world) + RB_dworld_delete(rbw->physics_world); + rbw->physics_world = RB_dworld_new(scene->physics_settings.gravity); + } + + RB_dworld_set_solver_iterations(rbw->physics_world, rbw->num_solver_iterations); + RB_dworld_set_split_impulse(rbw->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE); +} + +/* ************************************** */ +/* Setup Utilities - Create Settings Blocks */ + +/* Set up RigidBody world */ +RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) +{ + /* try to get whatever RigidBody world that might be representing this already */ + RigidBodyWorld *rbw; + + /* sanity checks + * - there must be a valid scene to add world to + * - there mustn't be a sim world using this group already + */ + if (scene == NULL) + return NULL; + + /* create a new sim world */ + rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld"); + + /* set default settings */ + rbw->effector_weights = BKE_add_effector_weights(NULL); + + rbw->ltime = PSFRA; + + rbw->time_scale = 1.0f; + + rbw->steps_per_second = 60; /* Bullet default (60 Hz) */ + rbw->num_solver_iterations = 10; /* 10 is bullet default */ + + rbw->pointcache = BKE_ptcache_add(&(rbw->ptcaches)); + rbw->pointcache->step = 1; + + /* return this sim world */ + return rbw; +} + +/* Add rigid body settings to the specified object */ +RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) +{ + RigidBodyOb *rbo; + RigidBodyWorld *rbw = scene->rigidbody_world; + + /* sanity checks + * - rigidbody world must exist + * - object must exist + * - cannot add rigid body if it already exists + */ + if (ob == NULL || (ob->rigidbody_object != NULL)) + return NULL; + + /* create new settings data, and link it up */ + rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb"); + + /* set default settings */ + rbo->type = type; + + rbo->mass = 1.0f; + + rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */ + rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */ + + rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */ + + rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */ + rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */ + + rbo->lin_damping = 0.04f; /* 0.04 is game engine default */ + rbo->ang_damping = 0.1f; /* 0.1 is game engine default */ + + rbo->col_groups = 1; + + /* use triangle meshes for passive objects + * use convex hulls for active objects since dynamic triangle meshes are very unstable + */ + if (type == RBO_TYPE_ACTIVE) + rbo->shape = RB_SHAPE_CONVEXH; + else + rbo->shape = RB_SHAPE_TRIMESH; + + /* set initial transform */ + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); + + /* return this object */ + return rbo; +} + +/* Add rigid body constraint to the specified object */ +RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) +{ + RigidBodyCon *rbc; + RigidBodyWorld *rbw = scene->rigidbody_world; + + /* sanity checks + * - rigidbody world must exist + * - object must exist + * - cannot add constraint if it already exists + */ + if (ob == NULL || (ob->rigidbody_constraint != NULL)) + return NULL; + + /* create new settings data, and link it up */ + rbc = MEM_callocN(sizeof(RigidBodyCon), "RigidBodyCon"); + + /* set default settings */ + rbc->type = type; + + rbc->ob1 = NULL; + rbc->ob2 = NULL; + + rbc->flag |= RBC_FLAG_ENABLED; + rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS; + + rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */ + rbc->num_solver_iterations = 10; /* 10 is Bullet default */ + + rbc->limit_lin_x_lower = -1.0f; + rbc->limit_lin_x_upper = 1.0f; + rbc->limit_lin_y_lower = -1.0f; + rbc->limit_lin_y_upper = 1.0f; + rbc->limit_lin_z_lower = -1.0f; + rbc->limit_lin_z_upper = 1.0f; + rbc->limit_ang_x_lower = -M_PI_4; + rbc->limit_ang_x_upper = M_PI_4; + rbc->limit_ang_y_lower = -M_PI_4; + rbc->limit_ang_y_upper = M_PI_4; + rbc->limit_ang_z_lower = -M_PI_4; + rbc->limit_ang_z_upper = M_PI_4; + + rbc->spring_damping_x = 0.5f; + rbc->spring_damping_y = 0.5f; + rbc->spring_damping_z = 0.5f; + rbc->spring_stiffness_x = 10.0f; + rbc->spring_stiffness_y = 10.0f; + rbc->spring_stiffness_z = 10.0f; + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); + + /* return this object */ + return rbc; +} + +/* ************************************** */ +/* Utilities API */ + +/* Get RigidBody world for the given scene, creating one if needed + * < scene: Scene to find active Rigid Body world for + */ +RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) +{ + /* sanity check */ + if (scene == NULL) + return NULL; + + return scene->rigidbody_world; +} + +void BKE_rigidbody_remove_object(Scene *scene, Object *ob) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyOb *rbo = ob->rigidbody_object; + RigidBodyCon *rbc; + GroupObject *go; + int i; + + if (rbw) { + /* remove from rigidbody world, free object won't do this */ + if (rbw->physics_world && rbo->physics_object) + RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + + /* remove object from array */ + if (rbw && rbw->objects) { + for (i = 0; i < rbw->numbodies; i++) { + if (rbw->objects[i] == ob) { + rbw->objects[i] = NULL; + break; + } + } + } + + /* remove object from rigid body constraints */ + if (rbw->constraints) { + for (go = rbw->constraints->gobject.first; go; go = go->next) { + Object *obt = go->ob; + if (obt) { + rbc = obt->rigidbody_constraint; + if (rbc->ob1 == ob) { + rbc->ob1 = NULL; + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; + } + if (rbc->ob2 == ob) { + rbc->ob2 = NULL; + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; + } + } + } + } + } + + /* remove object's settings */ + BKE_rigidbody_free_object(ob); + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); +} + +void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyCon *rbc = ob->rigidbody_constraint; + + if (rbw) { + /* remove from rigidbody world, free object won't do this */ + if (rbw && rbw->physics_world && rbc->physics_constraint) + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } + /* remove object's settings */ + BKE_rigidbody_free_constraint(ob); + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); +} + + +/* ************************************** */ +/* Simulation Interface - Bullet */ + +/* Update object array and rigid body count so they're in sync with the rigid body group */ +static void rigidbody_update_ob_array(RigidBodyWorld *rbw) +{ + GroupObject *go; + int i, n; + + n = BLI_countlist(&rbw->group->gobject); + + if (rbw->numbodies != n) { + rbw->numbodies = n; + rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies); + } + + for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) { + Object *ob = go->ob; + rbw->objects[i] = ob; + } +} + +static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) +{ + float adj_gravity[3]; + + /* adjust gravity to take effector weights into account */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(adj_gravity, scene->physics_settings.gravity); + mul_v3_fl(adj_gravity, rbw->effector_weights->global_gravity * rbw->effector_weights->weight[0]); + } + else { + zero_v3(adj_gravity); + } + + /* update gravity, since this RNA setting is not part of RigidBody settings */ + RB_dworld_set_gravity(rbw->physics_world, adj_gravity); + + /* update object array in case there are changes */ + rigidbody_update_ob_array(rbw); +} + +static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) +{ + float loc[3]; + float rot[4]; + float scale[3]; + + /* only update if rigid body exists */ + if (rbo->physics_object == NULL) + return; + + mat4_decompose(loc, rot, scale, ob->obmat); + + /* update scale for all objects */ + RB_body_set_scale(rbo->physics_object, scale); + /* compensate for embedded convex hull collision margin */ + if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) + RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); + + /* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */ + if ((ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) || rbo->type == RBO_TYPE_PASSIVE) { + RB_body_set_kinematic_state(rbo->physics_object, TRUE); + RB_body_set_mass(rbo->physics_object, 0.0f); + } + + /* update rigid body location and rotation for kinematic bodies */ + if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { + RB_body_activate(rbo->physics_object); + RB_body_set_loc_rot(rbo->physics_object, loc, rot); + } + /* update influence of effectors - but don't do it on an effector */ + /* only dynamic bodies need effector update */ + else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { + EffectorWeights *effector_weights = rbw->effector_weights; + EffectedPoint epoint; + ListBase *effectors; + + /* get effectors present in the group specified by effector_weights */ + effectors = pdInitEffectors(scene, ob, NULL, effector_weights); + if (effectors) { + float force[3] = {0.0f, 0.0f, 0.0f}; + float loc[3], vel[3]; + + /* create dummy 'point' which represents last known position of object as result of sim */ + // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals? + RB_body_get_position(rbo->physics_object, loc); + RB_body_get_linear_velocity(rbo->physics_object, vel); + + pd_point_from_loc(scene, loc, vel, 0, &epoint); + + /* calculate net force of effectors, and apply to sim object + * - we use 'central force' since apply force requires a "relative position" which we don't have... + */ + pdDoEffectors(effectors, NULL, effector_weights, &epoint, force, NULL); + if (G.f & G_DEBUG) + printf("\tapplying force (%f,%f,%f) to '%s'\n", force[0], force[1], force[2], ob->id.name + 2); + /* activate object in case it is deactivated */ + if (!is_zero_v3(force)) + RB_body_activate(rbo->physics_object); + RB_body_apply_central_force(rbo->physics_object, force); + } + else if (G.f & G_DEBUG) + printf("\tno forces to apply to '%s'\n", ob->id.name + 2); + + /* cleanup */ + pdEndEffectors(&effectors); + } + /* NOTE: passive objects don't need to be updated since they don't move */ + + /* NOTE: no other settings need to be explicitly updated here, + * since RNA setters take care of the rest :) + */ +} + +/* Updates and validates world, bodies and shapes. + * < rebuild: rebuild entire simulation + */ +static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int rebuild) +{ + GroupObject *go; + + /* update world */ + if (rebuild) + BKE_rigidbody_validate_sim_world(scene, rbw, true); + rigidbody_update_sim_world(scene, rbw); + + /* update objects */ + for (go = rbw->group->gobject.first; go; go = go->next) { + Object *ob = go->ob; + + if (ob && ob->type == OB_MESH) { + /* validate that we've got valid object set up here... */ + RigidBodyOb *rbo = ob->rigidbody_object; + /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ + BKE_object_where_is_calc(scene, ob); + + if (rbo == NULL) { + /* Since this object is included in the sim group but doesn't have + * rigid body settings (perhaps it was added manually), add! + * - assume object to be active? That is the default for newly added settings... + */ + ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE); + BKE_rigidbody_validate_sim_object(rbw, ob, true); + + rbo = ob->rigidbody_object; + } + else { + /* perform simulation data updates as tagged */ + /* refresh object... */ + if (rebuild) { + /* World has been rebuilt so rebuild object */ + BKE_rigidbody_validate_sim_object(rbw, ob, true); + } + else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) { + BKE_rigidbody_validate_sim_object(rbw, ob, false); + } + /* refresh shape... */ + if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) { + /* mesh/shape data changed, so force shape refresh */ + BKE_rigidbody_validate_sim_shape(ob, true); + /* now tell RB sim about it */ + // XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies + RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape); + } + rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); + } + + /* update simulation object... */ + rigidbody_update_sim_ob(scene, rbw, ob, rbo); + } + } + /* update constraints */ + if (rbw->constraints == NULL) /* no constraints, move on */ + return; + for (go = rbw->constraints->gobject.first; go; go = go->next) { + Object *ob = go->ob; + + if (ob) { + /* validate that we've got valid object set up here... */ + RigidBodyCon *rbc = ob->rigidbody_constraint; + /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ + BKE_object_where_is_calc(scene, ob); + + if (rbc == NULL) { + /* Since this object is included in the group but doesn't have + * constraint settings (perhaps it was added manually), add! + */ + ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED); + BKE_rigidbody_validate_sim_constraint(rbw, ob, true); + + rbc = ob->rigidbody_constraint; + } + else { + /* perform simulation data updates as tagged */ + if (rebuild) { + /* World has been rebuilt so rebuild constraint */ + BKE_rigidbody_validate_sim_constraint(rbw, ob, true); + } + else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { + BKE_rigidbody_validate_sim_constraint(rbw, ob, false); + } + rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; + } + } + } +} + +static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) +{ + GroupObject *go; + + for (go = rbw->group->gobject.first; go; go = go->next) { + Object *ob = go->ob; + + if (ob) { + RigidBodyOb *rbo = ob->rigidbody_object; + /* reset kinematic state for transformed objects */ + if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) { + RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); + } + } + } +} + +/* Sync rigid body and object transformations */ +void BKE_rigidbody_sync_transforms(Scene *scene, Object *ob, float ctime) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyOb *rbo = ob->rigidbody_object; + + /* keep original transform for kinematic and passive objects */ + if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE) + return; + + /* use rigid body transform after cache start frame if objects is not being transformed */ + if (ctime > rbw->pointcache->startframe && !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { + float mat[4][4], size_mat[4][4], size[3]; + + /* keep original transform when the simulation is muted */ + if (rbw->flag & RBW_FLAG_MUTED) + return; + + normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point + quat_to_mat4(mat, rbo->orn); + copy_v3_v3(mat[3], rbo->pos); + + mat4_to_size(size, ob->obmat); + size_to_mat4(size_mat, size); + mult_m4_m4m4(mat, mat, size_mat); + + copy_m4_m4(ob->obmat, mat); + } + /* otherwise set rigid body transform to current obmat */ + else { + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + } +} + +void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) +{ + RigidBodyOb *rbo = ob->rigidbody_object; + + /* return rigid body and object to their initial states */ + copy_v3_v3(rbo->pos, ob->loc); + copy_v3_v3(ob->loc, loc); + + if (ob->rotmode > 0) { + eulO_to_quat(rbo->orn, ob->rot, ob->rotmode); + copy_v3_v3(ob->rot, rot); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_quat(rbo->orn, ob->rotAxis, ob->rotAngle); + copy_v3_v3(ob->rotAxis, rotAxis); + ob->rotAngle = rotAngle; + } + else { + copy_qt_qt(rbo->orn, ob->quat); + copy_qt_qt(ob->quat, quat); + } + if (rbo->physics_object) + RB_body_set_loc_rot(rbo->physics_object, rbo->pos, rbo->orn); + // RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop) +} + +void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) +{ + if (rbw) + rbw->pointcache->flag |= PTCACHE_OUTDATED; +} + +/* ------------------ */ + +/* Run RigidBody simulation for the specified physics world */ +void BKE_rigidbody_do_simulation(Scene *scene, float ctime) +{ + float timestep; + RigidBodyWorld *rbw = scene->rigidbody_world; + PointCache *cache; + PTCacheID pid; + int startframe, endframe; + + BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); + BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); + cache = rbw->pointcache; + + /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */ + if (rbw->physics_world == NULL || rbw->numbodies != BLI_countlist(&rbw->group->gobject)) { + cache->flag |= PTCACHE_OUTDATED; + } + + if (ctime <= startframe) { + rbw->ltime = startframe; + /* reset and rebuild simulation if necessary */ + if (cache->flag & PTCACHE_OUTDATED) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + rigidbody_update_simulation(scene, rbw, true); + BKE_ptcache_validate(cache, (int)ctime); + cache->last_exact = 0; + cache->flag &= ~PTCACHE_REDO_NEEDED; + } + return; + } + /* rebuild world if it's outdated on second frame */ + else if (ctime == startframe + 1 && rbw->ltime == startframe && cache->flag & PTCACHE_OUTDATED) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + rigidbody_update_simulation(scene, rbw, true); + } + /* make sure we don't go out of cache frame range */ + else if (ctime > endframe) { + ctime = endframe; + } + + /* don't try to run the simulation if we don't have a world yet but allow reading baked cache */ + if (rbw->physics_world == NULL && !(cache->flag & PTCACHE_BAKED)) + return; + else if (rbw->objects == NULL) + rigidbody_update_ob_array(rbw); + + /* try to read from cache */ + // RB_TODO deal with interpolated, old and baked results + if (BKE_ptcache_read(&pid, ctime)) { + BKE_ptcache_validate(cache, (int)ctime); + rbw->ltime = ctime; + return; + } + + /* advance simulation, we can only step one frame forward */ + if (ctime == rbw->ltime + 1) { + /* write cache for first frame when on second frame */ + if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { + BKE_ptcache_write(&pid, startframe); + } + + /* update and validate simulation */ + rigidbody_update_simulation(scene, rbw, false); + + /* calculate how much time elapsed since last step in seconds */ + timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale; + /* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */ + RB_dworld_step_simulation(rbw->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f)); + + rigidbody_update_simulation_post_step(rbw); + + /* write cache for current frame */ + BKE_ptcache_validate(cache, (int)ctime); + BKE_ptcache_write(&pid, (unsigned int)ctime); + + rbw->ltime = ctime; + } +} +/* ************************************** */ + +#else /* WITH_BULLET */ + +/* stubs */ +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +void BKE_rigidbody_free_world(RigidBodyWorld *rbw) {} +void BKE_rigidbody_free_object(Object *ob) {} +void BKE_rigidbody_free_constraint(Object *ob) {} +struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; } +struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; } +void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild) {} +void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short rebuild) {} +void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, short rebuild) {} +void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, short rebuild) {} +struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; } +struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; } +struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; } +struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; } +void BKE_rigidbody_remove_object(Scene *scene, Object *ob) {} +void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {} +void BKE_rigidbody_sync_transforms(Scene *scene, Object *ob, float ctime) {} +void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) {} +void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {} +void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {} + +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + +#endif /* WITH_BULLET */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index eb56f34b99b..285646191f7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -46,6 +46,7 @@ #include "DNA_group_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" @@ -72,6 +73,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pointcache.h" +#include "BKE_rigidbody.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_world.h" @@ -314,6 +316,9 @@ void BKE_scene_free(Scene *sce) BKE_free_animdata((ID *)sce); BKE_keyingsets_free(&sce->keyingsets); + if (sce->rigidbody_world) + BKE_rigidbody_free_world(sce->rigidbody_world); + if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); MEM_freeN(sce->r.avicodecdata); @@ -950,6 +955,18 @@ Base *BKE_scene_base_add(Scene *sce, Object *ob) return b; } +void BKE_scene_base_unlink(Scene *sce, Base *base) +{ + /* remove rigid body constraint from world before removing object */ + if (base->object->rigidbody_constraint) + BKE_rigidbody_remove_constraint(sce, base->object); + /* remove rigid body object from world before removing object */ + if (base->object->rigidbody_object) + BKE_rigidbody_remove_object(sce, base->object); + + BLI_remlink(&sce->base, base); +} + void BKE_scene_base_deselect_all(Scene *sce) { Base *b; @@ -1205,6 +1222,12 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) BKE_animsys_evaluate_all_animation(bmain, sce, ctime); /*...done with recusrive funcs */ + /* run rigidbody sim */ + // XXX: this position may still change, objects not being updated correctly before simulation is run + // NOTE: current position is so that rigidbody sim affects other objects + if (BKE_scene_check_rigidbody_active(sce)) + BKE_rigidbody_do_simulation(sce, ctime); + /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later * when trying to find materials with drivers that need evaluating [#32017] */ @@ -1393,3 +1416,8 @@ int BKE_scene_check_color_management_enabled(const Scene *scene) { return strcmp(scene->display_settings.display_device, "None") != 0; } + +int BKE_scene_check_rigidbody_active(const Scene *scene) +{ + return scene && scene->rigidbody_world && scene->rigidbody_world->group && !(scene->rigidbody_world->flag & RBW_FLAG_MUTED); +} diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c64609c8e70..c0e85352217 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1317,7 +1317,8 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f switch (wipe->wipetype) { case DO_SINGLE_WIPE: - width = wipezone->width; + width = min_ii(wipezone->width, facf0 * yo); + width = min_ii(width, yo - facf0 * yo); if (angle == 0.0f) { b1 = posy; diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 2563fc268b1..be36e30808d 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1060,7 +1060,7 @@ static void get_texture_value(Tex *texture, float tex_co[3], TexResult *texres) int result_type; /* no node textures for now */ - result_type = multitex_ext_safe(texture, tex_co, texres); + result_type = multitex_ext_safe(texture, tex_co, texres, NULL); /* if the texture gave an RGB value, we assume it didn't give a valid * intensity, since this is in the context of modifiers don't use perceptual color conversion. diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 79356d39235..e2c6df5e528 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -4108,18 +4108,6 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i softbody_reset(ob, sb, vertexCos, numVerts); } - /* continue physics special case */ - if (BKE_ptcache_get_continue_physics()) { - BKE_ptcache_invalidate(cache); - /* do simulation */ - dtime = timescale; - softbody_update_positions(ob, sb, vertexCos, numVerts); - softbody_step(scene, ob, sb, dtime); - softbody_to_object(ob, vertexCos, numVerts, 0); - sb->last_frame = framenr; - return; - } - /* still no points? go away */ if (sb->totpoint==0) { return; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 01409a0f7e4..ce6e158b6d9 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1017,7 +1017,11 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf) mf->flag = faceFlags[i].flag; mf->mat_nr = faceFlags[i].mat_nr; } - else mf->flag = ME_SMOOTH; + else { + mf->flag = ME_SMOOTH; +} + + mf->edcode = 0; } /* Translate GridHidden into the ME_HIDE flag for MVerts. Assumes @@ -1097,6 +1101,14 @@ void subsurf_copy_grid_paint_mask(DerivedMesh *dm, const MPoly *mpoly, } } +/* utility functon */ +BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem) +{ + copy_v3_v3(mv->co, CCG_elem_co(key, elem)); + normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem)); + mv->flag = mv->bweight = 0; +} + static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; @@ -1107,7 +1119,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) int totvert, totedge, totface; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); - int i = 0; + unsigned int i = 0; CCG_key_top_level(&key, ss); @@ -1117,24 +1129,20 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); vd = ccgSubSurf_getFaceCenterData(f); - copy_v3_v3(mvert[i].co, CCG_elem_co(&key, vd)); - normal_float_to_short_v3(mvert[i].no, CCG_elem_no(&key, vd)); - i++; + ccgDM_to_MVert(&mvert[i++], &key, vd); for (S = 0; S < numVerts; S++) { - for (x = 1; x < gridSize - 1; x++, i++) { + for (x = 1; x < gridSize - 1; x++) { vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x); - copy_v3_v3(mvert[i].co, CCG_elem_co(&key, vd)); - normal_float_to_short_v3(mvert[i].no, CCG_elem_no(&key, vd)); + ccgDM_to_MVert(&mvert[i++], &key, vd); } } for (S = 0; S < numVerts; S++) { for (y = 1; y < gridSize - 1; y++) { - for (x = 1; x < gridSize - 1; x++, i++) { + for (x = 1; x < gridSize - 1; x++) { vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y); - copy_v3_v3(mvert[i].co, CCG_elem_co(&key, vd)); - normal_float_to_short_v3(mvert[i].no, CCG_elem_no(&key, vd)); + ccgDM_to_MVert(&mvert[i++], &key, vd); } } } @@ -1145,15 +1153,14 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) CCGEdge *e = ccgdm->edgeMap[index].edge; int x; - for (x = 1; x < edgeSize - 1; x++, i++) { - vd = ccgSubSurf_getEdgeData(ss, e, x); - copy_v3_v3(mvert[i].co, CCG_elem_co(&key, vd)); + for (x = 1; x < edgeSize - 1; x++) { /* This gives errors with -debug-fpe * the normals don't seem to be unit length. * this is most likely caused by edges with no * faces which are now zerod out, see comment in: * ccgSubSurf__calcVertNormals(), - campbell */ - normal_float_to_short_v3(mvert[i].no, CCG_elem_no(&key, vd)); + vd = ccgSubSurf_getEdgeData(ss, e, x); + ccgDM_to_MVert(&mvert[i++], &key, vd); } } @@ -1162,12 +1169,20 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) CCGVert *v = ccgdm->vertMap[index].vert; vd = ccgSubSurf_getVertData(ss, v); - copy_v3_v3(mvert[i].co, CCG_elem_co(&key, vd)); - normal_float_to_short_v3(mvert[i].no, CCG_elem_no(&key, vd)); - i++; + ccgDM_to_MVert(&mvert[i++], &key, vd); } } + +/* utility functon */ +BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const short flag) +{ + med->v1 = v1; + med->v2 = v2; + med->crease = med->bweight = 0; + med->flag = flag; +} + static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; @@ -1176,8 +1191,9 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) int totedge, totface; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); - int i = 0; + unsigned int i = 0; short *edgeFlags = ccgdm->edgeFlags; + const short ed_interior_flag = ccgdm->drawInteriorEdges ? (ME_EDGEDRAW | ME_EDGERENDER) : 0; totface = ccgSubSurf_getNumFaces(ss); for (index = 0; index < totface; index++) { @@ -1186,36 +1202,22 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) for (S = 0; S < numVerts; S++) { for (x = 0; x < gridSize - 1; x++) { - MEdge *med = &medge[i]; - - if (ccgdm->drawInteriorEdges) - med->flag = ME_EDGEDRAW | ME_EDGERENDER; - med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize); - med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize); - i++; + ccgDM_to_MEdge(&medge[i++], + getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize), + getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize), + ed_interior_flag); } for (x = 1; x < gridSize - 1; x++) { for (y = 0; y < gridSize - 1; y++) { - MEdge *med; - - med = &medge[i]; - if (ccgdm->drawInteriorEdges) - med->flag = ME_EDGEDRAW | ME_EDGERENDER; - med->v1 = getFaceIndex(ss, f, S, x, y, - edgeSize, gridSize); - med->v2 = getFaceIndex(ss, f, S, x, y + 1, - edgeSize, gridSize); - i++; - - med = &medge[i]; - if (ccgdm->drawInteriorEdges) - med->flag = ME_EDGEDRAW | ME_EDGERENDER; - med->v1 = getFaceIndex(ss, f, S, y, x, - edgeSize, gridSize); - med->v2 = getFaceIndex(ss, f, S, y + 1, x, - edgeSize, gridSize); - i++; + ccgDM_to_MEdge(&medge[i++], + getFaceIndex(ss, f, S, x, y, edgeSize, gridSize), + getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize), + ed_interior_flag); + ccgDM_to_MEdge(&medge[i++], + getFaceIndex(ss, f, S, y, x, edgeSize, gridSize), + getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize), + ed_interior_flag); } } } @@ -1224,31 +1226,32 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) totedge = ccgSubSurf_getNumEdges(ss); for (index = 0; index < totedge; index++) { CCGEdge *e = ccgdm->edgeMap[index].edge; - unsigned int flags = 0; + short ed_flag = 0; int x; int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e)); - if (!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE; + if (!ccgSubSurf_getEdgeNumFaces(e)) { + ed_flag |= ME_LOOSEEDGE; + } if (edgeFlags) { if (edgeIdx != -1) { #ifdef WITH_FREESTYLE - flags |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP | ME_FREESTYLE_EDGE)) | ME_EDGEDRAW | ME_EDGERENDER); + ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP | ME_FREESTYLE_EDGE)) | ME_EDGEDRAW | ME_EDGERENDER); #else - flags |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER); + ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER); #endif } } else { - flags |= ME_EDGEDRAW | ME_EDGERENDER; + ed_flag |= ME_EDGEDRAW | ME_EDGERENDER; } for (x = 0; x < edgeSize - 1; x++) { - MEdge *med = &medge[i]; - med->v1 = getEdgeIndex(ss, e, x, edgeSize); - med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize); - med->flag = flags; - i++; + ccgDM_to_MEdge(&medge[i++], + getEdgeIndex(ss, e, x, edgeSize), + getEdgeIndex(ss, e, x + 1, edgeSize), + ed_flag); } } } @@ -1286,6 +1289,7 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) edgeSize, gridSize); mf->mat_nr = mat_nr; mf->flag = flag; + mf->edcode = 0; i++; } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index c337e339ebf..a0f611a5a7b 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2930,6 +2930,16 @@ int text_check_identifier(const char ch) return 0; } +int text_check_identifier_nodigit(const char ch) +{ + if (ch <= '9') return 0; + if (ch < 'A') return 0; + if (ch <= 'Z' || ch == '_') return 1; + if (ch < 'a') return 0; + if (ch <= 'z') return 1; + return 0; +} + int text_check_whitespace(const char ch) { if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index fbaf6f70fbc..2e909f11eaa 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -615,6 +615,7 @@ void default_mtex(MTex *mtex) mtex->gravityfac = 1.0f; mtex->fieldfac = 1.0f; mtex->normapspace = MTEX_NSPACE_TANGENT; + mtex->brush_map_mode = MTEX_MAP_MODE_TILED; } diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 801fecc9f7c..3c5d94a21e4 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -1660,7 +1660,7 @@ ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, ImBuf *sea /* real sampling requires libmv, but areas are supposing pattern would be * sampled if search area does exists, so we'll need to create empty * pattern area here to prevent adding NULL-checks all over just to deal - * with situation when lubmv is disabled + * with situation when libmv is disabled */ (void) frame_width; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index cf2a165c2b2..7e51025883d 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -373,7 +373,7 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop) { char name[128]; char *param; - const AVOption *rv = NULL; + int fail = TRUE; PRINT("FFMPEG expert option: %s: ", prop->name); @@ -388,30 +388,30 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop) switch (prop->type) { case IDP_STRING: PRINT("%s.\n", IDP_String(prop)); - av_set_string3(c, prop->name, IDP_String(prop), 1, &rv); + fail = av_opt_set(c, prop->name, IDP_String(prop), 0); break; case IDP_FLOAT: PRINT("%g.\n", IDP_Float(prop)); - rv = av_set_double(c, prop->name, IDP_Float(prop)); + fail = av_opt_set_double(c, prop->name, IDP_Float(prop), 0); break; case IDP_INT: PRINT("%d.\n", IDP_Int(prop)); if (param) { if (IDP_Int(prop)) { - av_set_string3(c, name, param, 1, &rv); + fail = av_opt_set(c, name, param, 0); } else { return; } } else { - rv = av_set_int(c, prop->name, IDP_Int(prop)); + fail = av_opt_set_int(c, prop->name, IDP_Int(prop), 0); } break; } - if (!rv) { + if (fail) { PRINT("ffmpeg-option not supported: %s! Skipping.\n", prop->name); } } @@ -464,8 +464,9 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex error[0] = '\0'; - st = av_new_stream(of, 0); + st = avformat_new_stream(of, NULL); if (!st) return NULL; + st->id = 0; /* Set up the codec context */ @@ -541,16 +542,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex } if (codec_id == CODEC_ID_FFV1) { -#ifdef FFMPEG_FFV1_ALPHA_SUPPORTED - if (rd->im_format.planes == R_IMF_PLANES_RGBA) { - c->pix_fmt = PIX_FMT_RGB32; - } - else { - c->pix_fmt = PIX_FMT_BGR0; - } -#else c->pix_fmt = PIX_FMT_RGB32; -#endif } if (codec_id == CODEC_ID_QTRLE) { @@ -582,7 +574,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex set_ffmpeg_properties(rd, c, "video"); - if (avcodec_open(c, codec) < 0) { + if (avcodec_open2(c, codec, NULL) < 0) { BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size); return NULL; } @@ -619,8 +611,9 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex error[0] = '\0'; - st = av_new_stream(of, 1); + st = avformat_new_stream(of, NULL); if (!st) return NULL; + st->id = 1; c = st->codec; c->codec_id = codec_id; @@ -642,7 +635,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex set_ffmpeg_properties(rd, c, "audio"); - if (avcodec_open(c, codec) < 0) { + if (avcodec_open2(c, codec, NULL) < 0) { //XXX error("Couldn't initialize audio codec"); BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size); return NULL; @@ -1151,7 +1144,7 @@ IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, int opt_in val.i = 0; - avcodec_get_context_defaults(&c); + avcodec_get_context_defaults3(&c, NULL); o = c.av_class->option + opt_index; parent = c.av_class->option + parent_index; @@ -1182,23 +1175,23 @@ IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, int opt_in } switch (o->type) { - case FF_OPT_TYPE_INT: - case FF_OPT_TYPE_INT64: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: val.i = FFMPEG_DEF_OPT_VAL_INT(o); idp_type = IDP_INT; break; - case FF_OPT_TYPE_DOUBLE: - case FF_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: val.f = FFMPEG_DEF_OPT_VAL_DOUBLE(o); idp_type = IDP_FLOAT; break; - case FF_OPT_TYPE_STRING: + case AV_OPT_TYPE_STRING: val.string.str = (char *)" "; val.string.len = 80; /* val.str = (char *)" ";*/ idp_type = IDP_STRING; break; - case FF_OPT_TYPE_CONST: + case AV_OPT_TYPE_CONST: val.i = 1; idp_type = IDP_INT; break; @@ -1238,7 +1231,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char char *param; IDProperty *prop = NULL; - avcodec_get_context_defaults(&c); + avcodec_get_context_defaults3(&c, NULL); strncpy(name_, str, sizeof(name_)); @@ -1259,10 +1252,10 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char if (!o) { return 0; } - if (param && o->type == FF_OPT_TYPE_CONST) { + if (param && o->type == AV_OPT_TYPE_CONST) { return 0; } - if (param && o->type != FF_OPT_TYPE_CONST && o->unit) { + if (param && o->type != AV_OPT_TYPE_CONST && o->unit) { p = my_av_find_opt(&c, param, o->unit, 0, 0); if (p) { prop = BKE_ffmpeg_property_add(rd, (char *) type, p - c.av_class->option, o - c.av_class->option); |